@@ -11,8 +11,11 @@ import type { AuthDescriptor, AuthProviderDescriptor } from "../../auth/types.js
1111import type { DatabaseDescriptor } from "../../db/adapters.js" ;
1212import type { MediaProviderDescriptor } from "../../media/types.js" ;
1313import type { ResolvedPlugin } from "../../plugins/types.js" ;
14+ import type { ExperimentalConfig } from "../../registry/types.js" ;
1415import type { StorageDescriptor } from "../storage/types.js" ;
1516
17+ export type { ExperimentalConfig , RegistryConfig } from "../../registry/types.js" ;
18+
1619export type { ResolvedPlugin } ;
1720export type { MediaProviderDescriptor } ;
1821
@@ -125,133 +128,6 @@ export interface PluginDescriptor<TOptions = Record<string, unknown>> {
125128export type SandboxedPluginDescriptor < TOptions = Record < string , unknown > > =
126129 PluginDescriptor < TOptions > ;
127130
128- /**
129- * Experimental plugin registry configuration.
130- *
131- * See {@link ExperimentalConfig.registry}.
132- */
133- export interface RegistryConfig {
134- /**
135- * Base URL of the registry aggregator (an atproto AppView that indexes
136- * the firehose for `pm.fair.package.*` and `com.emdashcms.*` records).
137- *
138- * Must be the origin where the aggregator's XRPC endpoints are mounted,
139- * such that `${aggregatorUrl}/xrpc/<nsid>` resolves to a valid endpoint.
140- *
141- * Must be HTTPS in production; `http://localhost` or `http://127.0.0.1`
142- * are accepted in dev.
143- */
144- aggregatorUrl : string ;
145-
146- /**
147- * Optional comma-separated list of labeller DIDs forwarded as the
148- * `atproto-accept-labelers` header on every aggregator request.
149- *
150- * Format follows the atproto convention:
151- * `did:plc:abc;redact, did:plc:def`
152- *
153- * When unset, the aggregator applies its operator-default labeller set
154- * (typically the EmDash publisher-verification labeller and any
155- * additional trusted labellers the aggregator operator configured).
156- */
157- acceptLabelers ?: string ;
158-
159- /**
160- * Site-level policy applied to the latest-release selection filter.
161- *
162- * These filters operate over the signed records the aggregator returns;
163- * they are not protocol-level constraints. See the RFC's
164- * "Update Discovery and Takedowns" section for the integration point.
165- */
166- policy ?: {
167- /**
168- * Hold back releases newer than this when computing the recommended
169- * install or update version. Mitigates "compromised publisher
170- * account pushes a malicious release of an established plugin" by
171- * giving the takedown labeller a detection window.
172- *
173- * Accepts a duration string (`"24h"`, `"48h"`, `"72h"`, `"7d"`) or a
174- * number of seconds.
175- *
176- * Currently applies uniformly to all releases. A future addition
177- * may exempt brand-new packages (those with no prior release
178- * history) so the holdback doesn't block first-time publishing,
179- * but that exemption is not implemented yet; use
180- * {@link minimumReleaseAgeExclude} to allowlist trusted publishers
181- * whose packages should install immediately.
182- *
183- * Defaults to `undefined` (no holdback). A future trust/moderation
184- * RFC will specify the recommended default.
185- */
186- minimumReleaseAge ?: string | number ;
187-
188- /**
189- * Packages exempt from the {@link minimumReleaseAge} holdback. Use
190- * for publishers whose release tempo you've explicitly accepted --
191- * your own first-party plugins, a trusted partner, etc.
192- *
193- * Each entry is either:
194- * - A bare publisher DID (e.g. `"did:plc:abc123"`) -- every
195- * package from that publisher is exempt.
196- * - A `<did>/<slug>` pair (e.g.
197- * `"did:plc:abc123/hotfix-plugin"`) -- only that specific
198- * package is exempt.
199- *
200- * Whole-publisher exemptions are the common case: trust is
201- * naturally a property of the publisher, not of each individual
202- * package. Per-package exemptions exist for cases where a publisher
203- * has one plugin you want fast-track installs for and others you'd
204- * rather hold back.
205- *
206- * Only DIDs are accepted -- not handles. Handles are mutable
207- * aggregator-supplied envelope data, and accepting them as a
208- * trust input would let a compromised aggregator bypass the
209- * holdback by claiming any handle for any package. DIDs are
210- * tied to the AT URI of the package record itself, so even a
211- * compromised aggregator cannot lie about which DID published
212- * a release.
213- *
214- * Mirrors pnpm's `minimumReleaseAgeExclude`.
215- *
216- * @example
217- * ```ts
218- * minimumReleaseAgeExclude: [
219- * "did:plc:emdashfirstparty", // every package from this publisher
220- * "did:plc:abc123/hotfix-plugin", // just this one package
221- * ]
222- * ```
223- */
224- minimumReleaseAgeExclude ?: readonly string [ ] ;
225- } ;
226- }
227-
228- /**
229- * Experimental EmDash features. See {@link EmDashConfig.experimental}.
230- *
231- * Each field is independently opt-in. Fields may be promoted out of
232- * `experimental` (becoming top-level `EmDashConfig` options) or removed
233- * in minor releases; check the changelog when upgrading.
234- */
235- export interface ExperimentalConfig {
236- /**
237- * Decentralized plugin registry.
238- *
239- * When set, replaces the centralized `marketplace` for the admin UI's
240- * browse and install flows. The registry is an atproto-backed
241- * federation: package metadata lives in each publisher's PDS, an
242- * aggregator (the `aggregatorUrl`) indexes the firehose and exposes
243- * read-only XRPC endpoints for discovery, and EmDash verifies each
244- * release against the publisher's signed records before installing.
245- *
246- * See [RFC 0001](https://github.com/emdash-cms/emdash/pull/694) for
247- * the protocol design and threat model.
248- *
249- * Requires `sandboxRunner` to be configured -- registry plugins always
250- * run sandboxed.
251- */
252- registry ?: RegistryConfig ;
253- }
254-
255131export interface EmDashConfig {
256132 /**
257133 * Database configuration
0 commit comments