@sonicjs-cms/core 3.0.0-beta.10 → 3.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-IDCZBF35.js → chunk-3PU4WVU6.js} +4 -4
- package/dist/{chunk-IDCZBF35.js.map → chunk-3PU4WVU6.js.map} +1 -1
- package/dist/{chunk-ALDRXTUO.js → chunk-6H66MSSL.js} +2 -2
- package/dist/{chunk-ALDRXTUO.js.map → chunk-6H66MSSL.js.map} +1 -1
- package/dist/{chunk-IGADDMXH.js → chunk-HPAJKZAQ.js} +3 -3
- package/dist/{chunk-IGADDMXH.js.map → chunk-HPAJKZAQ.js.map} +1 -1
- package/dist/{chunk-TO6EY4P7.cjs → chunk-K342JMA3.cjs} +200 -200
- package/dist/{chunk-TO6EY4P7.cjs.map → chunk-K342JMA3.cjs.map} +1 -1
- package/dist/{chunk-F67UK75A.cjs → chunk-KV3CM5RK.cjs} +3 -3
- package/dist/{chunk-F67UK75A.cjs.map → chunk-KV3CM5RK.cjs.map} +1 -1
- package/dist/{chunk-3KYKEXV7.cjs → chunk-MKKGA3C4.cjs} +10 -10
- package/dist/{chunk-3KYKEXV7.cjs.map → chunk-MKKGA3C4.cjs.map} +1 -1
- package/dist/{chunk-IHTXB7AT.cjs → chunk-ORF4CT74.cjs} +2 -2
- package/dist/{chunk-IHTXB7AT.cjs.map → chunk-ORF4CT74.cjs.map} +1 -1
- package/dist/{chunk-ATUPB6MN.js → chunk-PDYRDYXI.js} +4 -4
- package/dist/{chunk-ATUPB6MN.js.map → chunk-PDYRDYXI.js.map} +1 -1
- package/dist/{chunk-R4ILO3W6.cjs → chunk-QJNKSFDJ.cjs} +2 -2
- package/dist/{chunk-R4ILO3W6.cjs.map → chunk-QJNKSFDJ.cjs.map} +1 -1
- package/dist/{chunk-PYVFXCSD.js → chunk-QLFTG3QJ.js} +2 -2
- package/dist/{chunk-PYVFXCSD.js.map → chunk-QLFTG3QJ.js.map} +1 -1
- package/dist/{chunk-6OC6MF3C.js → chunk-SXLVXD2X.js} +9 -9
- package/dist/{chunk-6OC6MF3C.js.map → chunk-SXLVXD2X.js.map} +1 -1
- package/dist/{chunk-PMGOBS6X.cjs → chunk-UHRHZXVR.cjs} +4 -4
- package/dist/{chunk-PMGOBS6X.cjs.map → chunk-UHRHZXVR.cjs.map} +1 -1
- package/dist/{chunk-MUNO67TT.cjs → chunk-YJEBDJDV.cjs} +13 -13
- package/dist/{chunk-MUNO67TT.cjs.map → chunk-YJEBDJDV.cjs.map} +1 -1
- package/dist/{chunk-V464XBYS.js → chunk-ZUEIQFE5.js} +3 -3
- package/dist/{chunk-V464XBYS.js.map → chunk-ZUEIQFE5.js.map} +1 -1
- package/dist/index.cjs +255 -254
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +16 -15
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +32 -32
- package/dist/middleware.js +3 -3
- package/dist/migrations-XQLBY7E5.js +4 -0
- package/dist/{migrations-PE3CDVSM.js.map → migrations-XQLBY7E5.js.map} +1 -1
- package/dist/migrations-ZXJEUTFA.cjs +13 -0
- package/dist/{migrations-2XHQEGOQ.cjs.map → migrations-ZXJEUTFA.cjs.map} +1 -1
- package/dist/plugins.cjs +40 -40
- package/dist/plugins.js +3 -3
- package/dist/routes.cjs +26 -26
- package/dist/routes.js +6 -6
- package/dist/services.cjs +18 -18
- package/dist/services.js +2 -2
- package/dist/utils.cjs +3 -3
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/dist/migrations-2XHQEGOQ.cjs +0 -13
- package/dist/migrations-PE3CDVSM.js +0 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkJ6JTWD2A_cjs = require('./chunk-J6JTWD2A.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkKV3CM5RK_cjs = require('./chunk-KV3CM5RK.cjs');
|
|
5
5
|
var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
|
|
6
6
|
|
|
7
7
|
// src/plugins/singletons/service-singleton.ts
|
|
@@ -205,7 +205,7 @@ function definePlugin(input) {
|
|
|
205
205
|
);
|
|
206
206
|
}
|
|
207
207
|
if (input.sonicjsVersionRange) {
|
|
208
|
-
const coreVersion =
|
|
208
|
+
const coreVersion = chunkKV3CM5RK_cjs.getCoreVersion();
|
|
209
209
|
if (!semverSatisfies(coreVersion, input.sonicjsVersionRange)) {
|
|
210
210
|
console.warn(
|
|
211
211
|
`[plugins] Plugin "${input.id}" declares sonicjsVersionRange "${input.sonicjsVersionRange}" but running core version is "${coreVersion}". The plugin may not work correctly. Consider updating the plugin or the version range.`
|
|
@@ -404,5 +404,5 @@ exports.parseFormDataToSettings = parseFormDataToSettings;
|
|
|
404
404
|
exports.renderSchemaFields = renderSchemaFields;
|
|
405
405
|
exports.setPluginDefinitions = setPluginDefinitions;
|
|
406
406
|
exports.validateCapabilities = validateCapabilities;
|
|
407
|
-
//# sourceMappingURL=chunk-
|
|
408
|
-
//# sourceMappingURL=chunk-
|
|
407
|
+
//# sourceMappingURL=chunk-UHRHZXVR.cjs.map
|
|
408
|
+
//# sourceMappingURL=chunk-UHRHZXVR.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugins/singletons/service-singleton.ts","../src/plugins/capabilities.ts","../src/plugins/sdk/define-plugin.ts","../src/plugins/sdk/config-schema.ts","../src/services/plugin-definition-registry.ts"],"names":["createTypedHooks","getCoreVersion","escapeHtml"],"mappings":"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","file":"chunk-PMGOBS6X.cjs","sourcesContent":["/**\n * Generic service-singleton factory\n *\n * Generalizes the hook-system-singleton pattern: a process-wide slot for a\n * service that code outside the HTTP request context — most importantly cron /\n * `scheduled()` handlers, which have no per-request `c.env` — can reach without\n * threading it through every call.\n *\n * Contract (same as the hook-system singleton):\n * - `get()` throws if read before `set()` (throw-before-get) so wiring-order\n * bugs surface loudly rather than silently no-oping.\n * - `set()` is idempotent (last write wins) so constructing multiple apps in one\n * process (e.g. across tests) never throws.\n * - `reset()` clears the slot for test isolation.\n */\n\nexport interface ServiceSingleton<T> {\n /** Set the process-wide instance. Last write wins. */\n set(instance: T): void\n /** Get the instance; throws if not yet set. */\n get(): T\n /** True if an instance has been set. */\n has(): boolean\n /** Clear the slot (test isolation). */\n reset(): void\n}\n\n/**\n * Create a service singleton.\n *\n * @param label Human-readable name used in the throw-before-get error message\n * (e.g. `'EmailService'`).\n */\nexport function createServiceSingleton<T>(label: string): ServiceSingleton<T> {\n let current: T | undefined\n return {\n set(instance: T) {\n current = instance\n },\n get(): T {\n if (current === undefined) {\n throw new Error(\n `${label} has not been initialized. Its setter must be called (the app factory does this at construction) before reading it.`\n )\n }\n return current\n },\n has(): boolean {\n return current !== undefined\n },\n reset() {\n current = undefined\n },\n }\n}\n","/**\n * Plugin capabilities\n *\n * A plugin declares the capabilities it needs (`capabilities: ['email:send']`).\n * The host then hands it a context whose powerful accessors are *gated* by those\n * declarations: reaching `ctx.email` without having declared `email:send` throws\n * `SonicCapabilityError` immediately, instead of failing deep inside a send.\n *\n * This is the isolation boundary that Strapi (namespacing only) and Payload (full\n * config access) don't have: capabilities make a plugin's blast radius explicit\n * and enforceable, and double as documentation of what a plugin can touch.\n *\n * Phase 1 vocabulary. Payment/queue/scheduled-fetch capabilities are intentionally\n * deferred to Phase 2 (see the overhaul plan §8.4 / open question 2).\n */\n\n// Type-only import (no runtime coupling) so a const-narrowed `ctx.cap.email`\n// resolves to the real EmailService type instead of `unknown`.\nimport type { EmailService } from '../services/email/email-service'\nimport type { HookEventName } from './hooks/catalog'\n\n/**\n * Fixed capability names. `db:<table>` is parameterized (a plugin owns specific\n * tables), so it is matched by pattern rather than listed here.\n */\nexport const FIXED_CAPABILITIES = [\n 'email:send',\n 'cache:read',\n 'cache:write',\n 'media:read',\n 'media:write',\n 'http:fetch',\n 'cron:register',\n 'admin:menu',\n 'hooks.auth:subscribe',\n 'hooks.content:subscribe',\n // Reserved: gates subscription to the email event family once those events are\n // dispatched. Declared now so the canonical vocabulary is stable and the\n // Infowall rename target resolves.\n 'hooks.email:subscribe',\n] as const\n\nexport type FixedCapability = (typeof FIXED_CAPABILITIES)[number]\n\n/** A scoped database capability, e.g. `db:email_log`. */\nexport type DbCapability = `db:${string}`\n\n/** Any declarable capability. */\nexport type Capability = FixedCapability | DbCapability\n\nconst DB_CAPABILITY_RE = /^db:[a-zA-Z_][a-zA-Z0-9_]*$/\n\n/** True if `name` is a recognized capability (fixed name or a valid `db:<table>`). */\nexport function isKnownCapability(name: string): name is Capability {\n return (FIXED_CAPABILITIES as readonly string[]).includes(name) || DB_CAPABILITY_RE.test(name)\n}\n\n/**\n * Thrown when a plugin uses a capability it did not declare.\n */\nexport class SonicCapabilityError extends Error {\n readonly capability: string\n readonly plugin?: string\n /** The API surface the plugin tried to access (e.g. 'ctx.cap.email'). Optional. */\n readonly accessedApi?: string\n constructor(capability: string, plugin?: string, accessedApi?: string) {\n super(\n `${plugin ? `Plugin \"${plugin}\"` : 'Plugin'} used capability \"${capability}\" without declaring it. ` +\n `Add \"${capability}\" to the plugin's capabilities.`\n )\n this.name = 'SonicCapabilityError'\n this.capability = capability\n this.plugin = plugin\n this.accessedApi = accessedApi\n }\n}\n\n/** True if `capability` is in the granted set. */\nexport function hasCapability(granted: readonly string[], capability: string): boolean {\n return granted.includes(capability)\n}\n\n/**\n * Assert a capability is granted, throwing {@link SonicCapabilityError} otherwise.\n */\nexport function assertCapability(granted: readonly string[], capability: string, plugin?: string): void {\n if (!hasCapability(granted, capability)) {\n throw new SonicCapabilityError(capability, plugin)\n }\n}\n\n/**\n * Validate a plugin's declared capability list. Returns the unknown entries (empty\n * array = all valid). Callers decide whether to warn or hard-fail.\n *\n * Apply {@link normalizeCapabilities} first if the input may contain deprecated\n * spellings (e.g. from an older SDK or a sibling fork's manifest).\n */\nexport function validateCapabilities(declared: readonly string[]): string[] {\n return declared.filter((c) => !isKnownCapability(c))\n}\n\n// ── Capability rename / normalization (cross-version & cross-fork portability) ─\n//\n// Lets a plugin authored against a different/older SDK spelling load against the\n// canonical vocabulary without code changes. The map is deprecated→canonical; it\n// is applied before the known-capability check. Seeded with the sibling fork's\n// (Infowall) spellings so plugins built there are portable here.\n\nexport const CAPABILITY_RENAMES = {\n // storage:* → media:* (this fork scopes the media library as `media`)\n 'storage:read': 'media:read',\n 'storage:write': 'media:write',\n // cron is a direct registration, not a hook subscription, here\n 'hooks.cron:register': 'cron:register',\n // `:register` → `:subscribe` verb; content read/write granularity lives in the\n // event name (before/after), so both collapse to one subscription capability\n 'hooks.auth:register': 'hooks.auth:subscribe',\n 'hooks.content-read:register': 'hooks.content:subscribe',\n 'hooks.content-write:register': 'hooks.content:subscribe',\n 'hooks.email-events:register': 'hooks.email:subscribe',\n // NOTE: Infowall's `request:intercept` has no canonical target — there is no\n // middleware-insertion surface to gate yet, so it is intentionally absent\n // (a plugin declaring it will surface as unknown rather than silently no-op).\n} as const satisfies Record<string, Capability>\n\n/**\n * Resolve a (possibly deprecated) capability string to its canonical form, or\n * `null` if it is unknown after rename resolution. Renames apply first, then the\n * result is checked against the known vocabulary.\n */\nexport function normalizeCapability(input: string): Capability | null {\n const renamed: string = (CAPABILITY_RENAMES as Record<string, Capability>)[input] ?? input\n return isKnownCapability(renamed) ? (renamed as Capability) : null\n}\n\n/**\n * Normalize a list of capability strings. Returns the canonical capabilities plus\n * the inputs that remained unknown after rename resolution, so the caller can warn\n * (production) or reject (strict).\n */\nexport function normalizeCapabilities(declared: readonly string[]): {\n capabilities: Capability[]\n unknown: string[]\n} {\n const capabilities: Capability[] = []\n const unknown: string[] = []\n for (const raw of declared) {\n const canonical = normalizeCapability(raw)\n if (canonical) {\n if (!capabilities.includes(canonical)) capabilities.push(canonical)\n } else {\n unknown.push(raw)\n }\n }\n return { capabilities, unknown }\n}\n\n// ── Capability-gated context ─────────────────────────────────────────────────\n\n/** Provider factories for capability-backed accessors. Each is called lazily. */\nexport interface CapabilityProviders {\n email?: () => EmailService\n cache?: () => unknown\n http?: () => typeof fetch\n}\n\n// ── Type-level capability narrowing ──────────────────────────────────────────\ndeclare const CAP_NOT_DECLARED: unique symbol\n/**\n * The type of a capability accessor the plugin did NOT declare. Deliberately a\n * branded type (not `never`, which is assignable to everything): using it where a\n * service is expected is a compile error, so `ctx.cap.email` without `email:send`\n * fails to type-check instead of silently passing.\n */\nexport type CapabilityNotDeclared<C extends string = string> = {\n readonly [CAP_NOT_DECLARED]: C\n}\n\n// `T` if the declared tuple `Caps` contains `C`, else the branded not-declared type.\ntype WhenGranted<Caps extends readonly Capability[], C extends string, T> =\n C extends Caps[number] ? T : CapabilityNotDeclared<C>\n// `T` if `Caps` contains ANY of the union `C`, else the branded not-declared type.\ntype WhenGrantedAny<Caps extends readonly Capability[], C extends string, T> =\n Extract<Caps[number], C> extends never ? CapabilityNotDeclared<C> : T\n\n/**\n * The gated context handed to a plugin. Accessors throw at runtime unless the\n * backing capability was declared; with a const-narrowed `Caps` tuple they are\n * also *typed* to the service (or `never`) at compile time, so `ctx.cap.email`\n * is `EmailService` only when `'email:send'` was declared.\n */\nexport interface CapabilityContext<Caps extends readonly Capability[] = readonly Capability[]> {\n /** The capabilities granted to this plugin. */\n readonly capabilities: readonly string[]\n /** True if the plugin declared `capability`. */\n has(capability: string): boolean\n /** Throw {@link SonicCapabilityError} unless `capability` was declared. */\n require(capability: string): void\n /** Email service. `EmailService` when `email:send` is declared, else `never`. */\n readonly email: WhenGranted<Caps, 'email:send', EmailService>\n /** Cache service. Present when `cache:read` or `cache:write` is declared. */\n readonly cache: WhenGrantedAny<Caps, 'cache:read' | 'cache:write', unknown>\n /** Outbound fetch. Present when `http:fetch` is declared. */\n readonly http: WhenGranted<Caps, 'http:fetch', typeof fetch>\n}\n\n/** The un-narrowed gated context (every accessor typed as its service). */\nexport type PluginCapabilityContext = CapabilityContext</** all */ readonly Capability[]>\n\n\n/**\n * Build a capability-gated context.\n *\n * Accessors are lazy getters: they check the grant (and that a provider was\n * supplied) at access time, so merely constructing the context is cheap and\n * holding a reference to a capability you never use costs nothing.\n *\n * @param granted Capabilities the plugin declared.\n * @param providers Backing service factories (only the granted ones get called).\n * @param plugin Plugin name, for clearer errors.\n */\nexport function createCapabilityContext<const Caps extends readonly Capability[]>(\n granted: Caps,\n providers: CapabilityProviders = {},\n plugin?: string\n): CapabilityContext<Caps> {\n // `any` so the lazy getters satisfy the narrowed accessor types (the provider\n // returns the real service at runtime; gating is enforced dynamically below).\n const gate = (capability: string, anyOf: string[], provider: (() => unknown) | undefined): any => {\n const ok = anyOf.some((c) => hasCapability(granted, c))\n if (!ok) throw new SonicCapabilityError(capability, plugin)\n if (!provider) {\n throw new Error(\n `Capability \"${capability}\" is declared by ${plugin ?? 'the plugin'} but no provider was supplied by the host.`\n )\n }\n return provider()\n }\n\n const ctx: CapabilityContext<Caps> = {\n capabilities: [...granted],\n has: (capability) => hasCapability(granted, capability),\n require: (capability) => assertCapability(granted, capability, plugin),\n get email() {\n return gate('email:send', ['email:send'], providers.email)\n },\n get cache() {\n return gate('cache:read', ['cache:read', 'cache:write'], providers.cache)\n },\n get http() {\n return gate('http:fetch', ['http:fetch'], providers.http)\n },\n }\n return ctx\n}\n\n// ── Hook-subscription capability map ────────────────────────────────────────\n//\n// Maps each catalog event to the capability a plugin must declare in order to\n// subscribe to it. Used by the wire phase (Phase A) to gate declarative hook\n// registrations. Plugins that don't declare the required capability have the\n// offending hook skipped (warn in prod, error in strict).\n\nexport const HOOK_CAPABILITY_MAP: Record<HookEventName, Capability> = {\n 'content:read': 'hooks.content:subscribe',\n 'content:before:create': 'hooks.content:subscribe',\n 'content:before:update': 'hooks.content:subscribe',\n 'content:before:delete': 'hooks.content:subscribe',\n 'content:after:create': 'hooks.content:subscribe',\n 'content:after:update': 'hooks.content:subscribe',\n 'content:after:delete': 'hooks.content:subscribe',\n 'content:after:publish': 'hooks.content:subscribe',\n 'auth:registration:completed': 'hooks.auth:subscribe',\n 'auth:password-reset:requested': 'hooks.auth:subscribe',\n 'auth:password-reset:completed': 'hooks.auth:subscribe',\n 'auth:magic-link:consumed': 'hooks.auth:subscribe',\n 'auth:otp:verified': 'hooks.auth:subscribe',\n}\n","/**\n * definePlugin() — the v3 plugin authoring entry point\n *\n * A plugin is authored as a single typed declaration and consumed, unchanged, by\n * every part of the runtime:\n *\n * export const emailPlugin = definePlugin({\n * id: 'email',\n * version: '3.0.0',\n * capabilities: ['email:send', 'hooks.auth:subscribe', 'cron:register'],\n * register(app) { app.route('/admin/plugins/email', emailRoutes) }, // SYNC\n * async onBoot(ctx) { // ASYNC\n * ctx.hooks.on('auth:registration:completed', (p) => { ... }) // typed\n * ctx.cap.email // gated\n * },\n * crons: [{ schedule: '*\\/15 * * * *', hookFamily: 'email-reconciliation' }],\n * async onCronTick(event, ctx) { ... },\n * })\n *\n * The object it returns satisfies the structural contracts the runtime already\n * uses — `MountablePlugin` (mount.ts), `WirablePlugin` (wire.ts), `CronablePlugin`\n * (cron.ts) — plus the legacy `Plugin` metadata fields the admin/registry read.\n * No adapters: a defined plugin drops straight into `plugins.register` or the core\n * plugin list.\n *\n * The value definePlugin adds over a hand-written object is the enriched context:\n * inside `onBoot`/`onCronTick` the author gets a *typed* hook facade (`ctx.hooks`)\n * and the *capability-gated* service context (`ctx.cap`), instead of the raw\n * string-keyed hook system. See the two-phase boot contract: `register` is\n * synchronous (routes only); everything env-dependent lives in `onBoot`.\n */\n\nimport type { Hono } from 'hono'\nimport type { Capability } from '../capabilities'\nimport {\n createCapabilityContext,\n normalizeCapabilities,\n type CapabilityProviders,\n type CapabilityContext,\n} from '../capabilities'\nimport { createTypedHooks, type TypedHooks, type TypedHookHandler } from '../hooks/typed-hooks'\nimport type { HookEventName } from '../hooks/catalog'\nimport type { PluginBootContext, WirableHook } from '../wire'\nimport type { CronContext, CronDeclaration, CronTickEvent } from '../cron'\nimport type { MountableRoute } from '../mount'\nimport { getCoreVersion } from '../../utils/version'\nimport type { ConfigSchema } from './config-schema'\nimport type { PluginMenuEntry } from '../../services/plugin-menu-singleton'\n\n// ── Minimal semver helpers (no external dep — Workers are bundle-size constrained) ─\n\n/** True if `v` is a valid semver string (X.Y.Z with optional pre-release). */\nfunction isSemver(v: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?(\\+[\\w.]+)?$/.test(v.trim())\n}\n\n/**\n * Very lightweight semver range satisfier. Handles the most common range forms:\n * exact (`1.2.3`), caret (`^1.2.3` = compatible major), tilde (`~1.2.3` = compatible\n * minor), comparators (`>=1.0.0`, `>1`, `<2.0.0`), and space-separated AND chains.\n * Not a full semver implementation — use the `semver` npm package if you need\n * full range syntax in a non-Workers environment.\n */\nfunction semverSatisfies(version: string, range: string): boolean {\n try {\n const [major, minor, patch] = version.trim().split('-')[0]!.split('.').map(Number)\n const v = major! * 1_000_000 + (minor ?? 0) * 1_000 + (patch ?? 0)\n\n const toInt = (s: string) => {\n const [a, b, c] = s.split('.').map(Number)\n return a! * 1_000_000 + (b ?? 0) * 1_000 + (c ?? 0)\n }\n\n // AND chain: all clauses must pass.\n return range\n .trim()\n .split(/\\s+(?=[><=^~])|\\s+(?=\\d)/)\n .filter(Boolean)\n .every((clause) => {\n const c = clause.trim()\n if (c.startsWith('^')) {\n const base = toInt(c.slice(1))\n const nextMajor = Math.floor(base / 1_000_000 + 1) * 1_000_000\n return v >= base && v < nextMajor\n }\n if (c.startsWith('~')) {\n const base = toInt(c.slice(1))\n const nextMinor = Math.floor(base / 1_000 + 1) * 1_000\n return v >= base && v < nextMinor\n }\n if (c.startsWith('>=')) return v >= toInt(c.slice(2))\n if (c.startsWith('<=')) return v <= toInt(c.slice(2))\n if (c.startsWith('>')) return v > toInt(c.slice(1))\n if (c.startsWith('<')) return v < toInt(c.slice(1))\n return v === toInt(c) // exact\n })\n } catch {\n return true // fail open — don't block a plugin on a parse error\n }\n}\n\n/**\n * Declarative typed hook subscriptions: a map of canonical event name → handler,\n * each narrowed to that event's payload. Flattened into the plugin's `hooks[]`\n * and subscribed during the wire phase. Use `onBoot`'s `ctx.hooks.on()` instead\n * for dynamic/conditional subscriptions.\n */\nexport type DeclarativeHooks = {\n [E in HookEventName]?: TypedHookHandler<E>\n}\n\n/**\n * Context handed to a defined plugin's `onBoot` / `onCronTick`.\n *\n * Enriches the raw boot/cron context with a typed hook facade and the gated\n * capability context, while keeping `raw` and `env` available as an escape hatch.\n */\nexport interface DefinedPluginContext<Caps extends readonly Capability[] = readonly Capability[]> {\n /** Typed hook facade — `ctx.hooks.on('auth:registration:completed', …)`. */\n hooks: TypedHooks\n /**\n * Capability-gated services. With a const-narrowed `Caps`, `ctx.cap.email` is\n * typed `EmailService` only when `'email:send'` was declared (else `never`),\n * and throws `SonicCapabilityError` at runtime if accessed undeclared.\n */\n cap: CapabilityContext<Caps>\n /** Runtime bindings, when available (absent during construction). */\n env?: Record<string, unknown>\n /** The unwrapped context the runtime passed. */\n raw: PluginBootContext | CronContext\n}\n\n/** Input to {@link definePlugin}. */\nexport interface DefinePluginInput<Caps extends readonly Capability[] = readonly []> {\n /** Unique, stable plugin id (kebab-case). Becomes the plugin `name`. */\n id: string\n /** Human-readable display name. Defaults to `id`. */\n name?: string\n /**\n * Semantic version of this plugin (e.g. `'1.2.3'`). Must be a valid semver\n * string — invalid values emit a console.warn at definition time.\n */\n version: string\n /**\n * A semver range expressing which SonicJS core versions this plugin supports\n * (e.g. `'^3.0.0'` or `'>=3.1.0 <4.0.0'`). Checked against the running\n * core version at registration; a mismatch logs a compatibility warning but\n * does not block activation (plugins remain resilient by default).\n */\n sonicjsVersionRange?: string\n description?: string\n author?: { name: string; email?: string; url?: string }\n /** Other plugin ids this one needs (load-order / activation). */\n dependencies?: string[]\n /**\n * Capabilities this plugin declares. The gated `ctx.cap` accessors throw for\n * anything not listed here. Pass as a literal (`['email:send'] as const` is not\n * needed — the `const` type param infers the tuple) to get `ctx.cap` narrowed.\n * Unknown/deprecated names are normalized then warned about at definition.\n */\n capabilities?: Caps\n\n // ── Synchronous registration (routes only) ──\n /** Declarative routes (mounted before the /admin catch-all). */\n routes?: MountableRoute[]\n /**\n * Imperative route registration. MUST be synchronous (Hono's router locks after\n * the first request). Async work belongs in `onBoot`.\n */\n register?: (app: Hono) => void\n\n // ── Asynchronous wiring ──\n /**\n * Declarative typed hook subscriptions (`{ 'content:after:create': (p) => … }`).\n * Subscribed during the wire phase; each handler is narrowed to its event payload.\n */\n hooks?: DeclarativeHooks\n /**\n * Run once on first request, after every plugin has registered. The place for\n * dynamic hook subscriptions (`ctx.hooks.on(...)`) and env-dependent setup.\n */\n onBoot?: (context: DefinedPluginContext<Caps>) => void | Promise<void>\n\n // ── Cron ──\n /** Scheduled-work declarations (also list the expressions in wrangler.toml). */\n crons?: CronDeclaration[]\n /** Handler for a fired cron; branch on `event.hookFamily`. */\n onCronTick?: (event: CronTickEvent, context: DefinedPluginContext<Caps>) => void | Promise<void>\n\n // ── Lifecycle (DB/schema only — never touches routes) ──\n install?: (context: unknown) => void | Promise<void>\n uninstall?: (context: unknown) => void | Promise<void>\n activate?: (context: unknown) => void | Promise<void>\n deactivate?: (context: unknown) => void | Promise<void>\n\n // ── Declarative admin surface ──\n /**\n * Declarative admin-sidebar entries collected by registerPlugins. The catalyst\n * sidebar renders them automatically; no per-plugin `addMenuItem(...)` call\n * required.\n */\n menu?: PluginMenuEntry[]\n /**\n * Schema-driven settings. Declaring this auto-renders the admin form at\n * `/admin/settings/plugins/:id`, parses FormData back into typed values, and\n * persists them via the plugin-service. Authors no longer hand-roll settings\n * routes/templates.\n */\n configSchema?: ConfigSchema\n}\n\n/**\n * The runtime shape produced by {@link definePlugin}. Carries the legacy metadata\n * fields plus the v3 surfaces; structurally satisfies `MountablePlugin`,\n * `WirablePlugin`, and `CronablePlugin`.\n */\nexport interface DefinedPlugin {\n id: string\n name: string\n version: string\n /** The semver range for SonicJS core compatibility declared by the author. */\n sonicjsVersionRange?: string\n description?: string\n author?: { name: string; email?: string; url?: string }\n dependencies?: string[]\n capabilities: Capability[]\n routes?: MountableRoute[]\n register?: (app: Hono) => void\n /** Declarative hook subscriptions, flattened for the wire phase. */\n hooks?: WirableHook[]\n /** Wrapped onBoot accepting the runtime's raw boot context. */\n onBoot?: (context: PluginBootContext) => void | Promise<void>\n crons?: CronDeclaration[]\n /** Wrapped onCronTick accepting the runtime's raw cron context. */\n onCronTick?: (event: CronTickEvent, context: CronContext) => void | Promise<void>\n install?: (context: unknown) => void | Promise<void>\n uninstall?: (context: unknown) => void | Promise<void>\n activate?: (context: unknown) => void | Promise<void>\n deactivate?: (context: unknown) => void | Promise<void>\n /** Declarative admin sidebar entries. registerPlugins collects + sets the menu singleton. */\n menu?: PluginMenuEntry[]\n /** Schema-driven settings. Renders the admin settings form for this plugin. */\n configSchema?: ConfigSchema\n /** Marker so tooling/tests can detect a v3-defined plugin. */\n // eslint-disable-next-line @typescript-eslint/naming-convention -- intentional internal marker\n readonly __sonicV3: true\n}\n\n/**\n * Build the enriched context from whatever raw context the runtime passed.\n *\n * Capability providers ride on the raw context (`raw.providers`) — the host\n * supplies real `email`/`cache`/`http` factories there. When none are supplied, a\n * declared-but-used capability throws \"no provider supplied by host\", which is the\n * correct signal during early bring-up.\n */\nfunction enrich<Caps extends readonly Capability[]>(\n raw: PluginBootContext | CronContext,\n runtimeCaps: readonly Capability[],\n pluginName: string\n): DefinedPluginContext<Caps> {\n const providers = (raw as { providers?: CapabilityProviders }).providers ?? {}\n return {\n hooks: createTypedHooks(raw.hooks),\n // Runtime gating uses the normalized capability set; the context TYPE reflects\n // the declared `Caps` tuple (the narrowing the author sees).\n cap: createCapabilityContext(runtimeCaps as unknown as Caps, providers, pluginName),\n env: raw.env,\n raw,\n }\n}\n\n/**\n * Define a v3 plugin. Validates declared capabilities (warns on unknown), then\n * returns a runtime-ready plugin whose `onBoot`/`onCronTick` receive the enriched,\n * typed, capability-gated context. The `const Caps` type parameter captures the\n * declared capability tuple so `ctx.cap` is narrowed at the author's call site.\n */\nexport function definePlugin<const Caps extends readonly Capability[] = readonly []>(\n input: DefinePluginInput<Caps>\n): DefinedPlugin {\n if (!input.id) throw new Error('definePlugin: `id` is required')\n if (!input.version) throw new Error(`definePlugin: \\`version\\` is required (plugin \"${input.id}\")`)\n\n // Semver validation: warn if the plugin's own version is not a valid semver string.\n if (!isSemver(input.version)) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugins] Plugin \"${input.id}\" has an invalid version: \"${input.version}\". ` +\n `Use a valid semver string (e.g. \"1.0.0\") to participate in version-range checks.`\n )\n }\n\n // SonicJS core compatibility range check.\n if (input.sonicjsVersionRange) {\n const coreVersion = getCoreVersion()\n if (!semverSatisfies(coreVersion, input.sonicjsVersionRange)) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugins] Plugin \"${input.id}\" declares sonicjsVersionRange \"${input.sonicjsVersionRange}\" ` +\n `but running core version is \"${coreVersion}\". ` +\n `The plugin may not work correctly. Consider updating the plugin or the version range.`\n )\n }\n }\n\n // Normalize declared capabilities to canonical names first (resolves deprecated\n // / cross-fork spellings like `storage:write` → `media:write`), then warn on any\n // that remain unknown. Strict-reject at registration is layered in Phase 5d.\n const { capabilities, unknown } = normalizeCapabilities(input.capabilities ?? [])\n if (unknown.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugins] Plugin \"${input.id}\" declares unknown capabilities: ${unknown.join(', ')}. ` +\n `These will gate nothing. Check for typos or update the capability vocabulary.`\n )\n }\n\n const name = input.id\n\n const onBoot = input.onBoot\n ? (raw: PluginBootContext) => input.onBoot!(enrich(raw, capabilities, name))\n : undefined\n\n const onCronTick = input.onCronTick\n ? (event: CronTickEvent, raw: CronContext) => input.onCronTick!(event, enrich(raw, capabilities, name))\n : undefined\n\n // Flatten the declarative typed `hooks` map into the wirable `hooks[]` array.\n // Each handler is wrapped to the raw (data, context) shape, coalescing a void\n // return back to the incoming payload (matching createTypedHooks().on()).\n const hooks: WirableHook[] | undefined = input.hooks\n ? Object.entries(input.hooks)\n .filter(([, h]) => typeof h === 'function')\n .map(([eventName, h]) => ({\n name: eventName,\n handler: async (data: any, context: any) => {\n const result = await (h as TypedHookHandler<HookEventName>)(data, context ?? {})\n return result === undefined ? data : result\n },\n }))\n : undefined\n\n return {\n id: input.id,\n name,\n version: input.version,\n sonicjsVersionRange: input.sonicjsVersionRange,\n description: input.description,\n author: input.author,\n dependencies: input.dependencies,\n capabilities,\n routes: input.routes,\n register: input.register,\n hooks,\n onBoot,\n crons: input.crons,\n onCronTick,\n install: input.install,\n uninstall: input.uninstall,\n activate: input.activate,\n deactivate: input.deactivate,\n menu: input.menu,\n configSchema: input.configSchema,\n // eslint-disable-next-line @typescript-eslint/naming-convention -- intentional internal marker\n __sonicV3: true,\n }\n}\n\n/** True if `plugin` was produced by {@link definePlugin}. */\nexport function isDefinedPlugin(plugin: unknown): plugin is DefinedPlugin {\n // eslint-disable-next-line @typescript-eslint/naming-convention -- intentional internal marker\n return !!plugin && typeof plugin === 'object' && (plugin as { __sonicV3?: unknown }).__sonicV3 === true\n}\n","/**\n * Schema-driven plugin settings.\n *\n * Plugins declare `configSchema: { key: ConfigSchemaField }` on definePlugin.\n * The host renders the admin settings UI from the schema, parses FormData back\n * into typed values, and exposes the resulting record via `ctx.settings.load()`.\n *\n * Field kinds: 'string' | 'number' | 'boolean' | 'select'. New kinds get added\n * here once and every consumer picks them up.\n *\n * Phase 1 — settings UI only. The renderer emits plain HTML strings designed to\n * compose into the existing admin layout (no client-side JS). FormData parsing\n * coalesces unchecked-checkbox omission into `false` (the only browser quirk\n * the renderer must account for).\n */\n\nimport { escapeHtml } from '../../utils/sanitize'\n\n// ── Field model ──────────────────────────────────────────────────────────────\n\ninterface BaseField {\n label: string\n description?: string\n required?: boolean\n}\n\nexport interface StringField extends BaseField {\n type: 'string'\n default?: string\n format?: 'email' | 'url' | 'password'\n /** Render as `<input type=\"password\">`. Implied when `format === 'password'`. */\n sensitive?: boolean\n placeholder?: string\n minLength?: number\n maxLength?: number\n}\n\nexport interface NumberField extends BaseField {\n type: 'number'\n default?: number\n min?: number\n max?: number\n step?: number\n}\n\nexport interface BooleanField extends BaseField {\n type: 'boolean'\n default?: boolean\n}\n\nexport interface SelectField extends BaseField {\n type: 'select'\n default?: string\n /** Either `['us','eu']` shorthand or `[{ value, label }]` for distinct display strings. */\n options: readonly string[] | readonly { value: string; label: string }[]\n}\n\nexport type ConfigSchemaField = StringField | NumberField | BooleanField | SelectField\n\nexport type ConfigSchema = Record<string, ConfigSchemaField>\n\n/** Parsed shape — typed record inferred from the schema. */\nexport type SettingsFor<S extends ConfigSchema> = {\n [K in keyof S]: S[K] extends StringField\n ? string\n : S[K] extends NumberField\n ? number\n : S[K] extends BooleanField\n ? boolean\n : S[K] extends SelectField\n ? string\n : never\n}\n\n// ── Parse ────────────────────────────────────────────────────────────────────\n\nexport interface ParsedField {\n key: string\n field: ConfigSchemaField\n}\n\n/** Stable, ordered field list (preserves declaration order). */\nexport function parseConfigSchema(schema: ConfigSchema): ParsedField[] {\n return Object.entries(schema).map(([key, field]) => ({ key, field }))\n}\n\n// ── Render ───────────────────────────────────────────────────────────────────\n\n/**\n * Render all fields as HTML controls. Output is a sequence of `<div class=\"field\">…</div>`\n * blocks designed to drop into the admin form template (no surrounding `<form>` or\n * submit button — those belong to the page that calls this).\n */\nexport function renderSchemaFields(\n schema: ConfigSchema,\n currentValues: Record<string, unknown> = {}\n): string {\n return parseConfigSchema(schema)\n .map(({ key, field }) => {\n const value = key in currentValues ? currentValues[key] : (field as { default?: unknown }).default\n return renderField(key, field, value)\n })\n .join('\\n')\n}\n\nfunction renderField(key: string, field: ConfigSchemaField, value: unknown): string {\n const id = `field-${key}`\n const requiredAttr = field.required ? ' required' : ''\n const labelHtml = `${escapeHtml(field.label)}${field.required ? ' *' : ''}`\n const helpHtml = field.description ? `<p class=\"help text-sm text-gray-400 mt-1\">${escapeHtml(field.description)}</p>` : ''\n\n switch (field.type) {\n case 'string': {\n const isPassword = field.sensitive === true || field.format === 'password'\n const inputType = isPassword ? 'password' : field.format === 'email' ? 'email' : field.format === 'url' ? 'url' : 'text'\n const placeholder = field.placeholder ? ` placeholder=\"${escapeHtml(field.placeholder)}\"` : ''\n const min = field.minLength != null ? ` minlength=\"${field.minLength}\"` : ''\n const max = field.maxLength != null ? ` maxlength=\"${field.maxLength}\"` : ''\n return `\n<div class=\"field mb-4\">\n <label for=\"${id}\" class=\"block text-sm font-medium mb-1\">${labelHtml}</label>\n <input id=\"${id}\" name=\"${escapeHtml(key)}\" type=\"${inputType}\"\n class=\"w-full rounded border border-gray-700 bg-gray-800 px-3 py-2 text-sm\"\n value=\"${escapeHtml(String(value ?? ''))}\"${placeholder}${min}${max}${requiredAttr} />\n ${helpHtml}\n</div>`.trim()\n }\n case 'number': {\n const min = field.min != null ? ` min=\"${field.min}\"` : ''\n const max = field.max != null ? ` max=\"${field.max}\"` : ''\n const step = field.step != null ? ` step=\"${field.step}\"` : ''\n return `\n<div class=\"field mb-4\">\n <label for=\"${id}\" class=\"block text-sm font-medium mb-1\">${labelHtml}</label>\n <input id=\"${id}\" name=\"${escapeHtml(key)}\" type=\"number\"\n class=\"w-full rounded border border-gray-700 bg-gray-800 px-3 py-2 text-sm\"\n value=\"${value == null ? '' : escapeHtml(String(value))}\"${min}${max}${step}${requiredAttr} />\n ${helpHtml}\n</div>`.trim()\n }\n case 'boolean': {\n const checked = value === true ? ' checked' : ''\n return `\n<div class=\"field mb-4\">\n <label class=\"flex items-center gap-2 text-sm font-medium\">\n <input name=\"${escapeHtml(key)}\" type=\"checkbox\" class=\"rounded\"${checked} />\n ${labelHtml}\n </label>\n ${helpHtml}\n</div>`.trim()\n }\n case 'select': {\n const optionsHtml = field.options\n .map((o) => {\n const opt = typeof o === 'string' ? { value: o, label: o } : o\n const selected = opt.value === value ? ' selected' : ''\n return `<option value=\"${escapeHtml(opt.value)}\"${selected}>${escapeHtml(opt.label)}</option>`\n })\n .join('')\n return `\n<div class=\"field mb-4\">\n <label for=\"${id}\" class=\"block text-sm font-medium mb-1\">${labelHtml}</label>\n <select id=\"${id}\" name=\"${escapeHtml(key)}\"\n class=\"w-full rounded border border-gray-700 bg-gray-800 px-3 py-2 text-sm\"${requiredAttr}>\n ${optionsHtml}\n </select>\n ${helpHtml}\n</div>`.trim()\n }\n }\n}\n\n// ── FormData → settings ──────────────────────────────────────────────────────\n\n/**\n * Coerce FormData entries into typed settings per the schema. Notably:\n * - Unchecked checkboxes are omitted by the browser; we coalesce to `false`.\n * - Numbers parse via `Number()` and fall back to the field's default if invalid.\n * - Strings preserve empty string (NOT default) so an admin can intentionally clear.\n */\nexport function parseFormDataToSettings(schema: ConfigSchema, form: FormData): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const { key, field } of parseConfigSchema(schema)) {\n switch (field.type) {\n case 'string': {\n const raw = form.get(key)\n result[key] = raw == null ? field.default ?? '' : String(raw)\n break\n }\n case 'number': {\n const raw = form.get(key)\n if (raw == null || raw === '') {\n result[key] = field.default\n } else {\n const n = Number(raw)\n result[key] = Number.isFinite(n) ? n : field.default\n }\n break\n }\n case 'boolean': {\n // Unchecked checkbox → not present in FormData → false.\n result[key] = form.get(key) != null\n break\n }\n case 'select': {\n const raw = form.get(key)\n result[key] = raw == null ? field.default ?? '' : String(raw)\n break\n }\n }\n }\n return result\n}\n\n// ── Defaults ─────────────────────────────────────────────────────────────────\n\n/** Fill missing keys with field defaults. Existing keys (incl. `false`/`0`/'') win. */\nexport function applySchemaDefaults<S extends ConfigSchema>(\n schema: S,\n stored: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...stored }\n for (const { key, field } of parseConfigSchema(schema)) {\n if (result[key] === undefined) {\n const def = (field as { default?: unknown }).default\n if (def !== undefined) result[key] = def\n }\n }\n return result\n}\n","/**\n * In-memory registry of registered plugin definitions, indexed by id.\n *\n * Populated by `registerPlugins()` at app construction. The admin settings\n * route uses it to look up a plugin's `configSchema` so the schema-driven\n * settings form can be auto-rendered without per-plugin glue code.\n *\n * Read by the admin layer; written ONLY by registerPlugins.\n */\n\nimport type { RegisterablePlugin } from '../plugins/sdk/register-plugins'\n\nlet registry: ReadonlyMap<string, RegisterablePlugin> = new Map()\n\nexport function setPluginDefinitions(plugins: ReadonlyArray<RegisterablePlugin>): void {\n const next = new Map<string, RegisterablePlugin>()\n for (const p of plugins) next.set(p.id, p)\n registry = next\n}\n\nexport function getPluginDefinition(id: string): RegisterablePlugin | undefined {\n return registry.get(id)\n}\n\nexport function getAllPluginDefinitions(): ReadonlyArray<RegisterablePlugin> {\n return Array.from(registry.values())\n}\n\nexport function resetPluginDefinitions(): void {\n registry = new Map()\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugins/singletons/service-singleton.ts","../src/plugins/capabilities.ts","../src/plugins/sdk/define-plugin.ts","../src/plugins/sdk/config-schema.ts","../src/services/plugin-definition-registry.ts"],"names":["createTypedHooks","getCoreVersion","escapeHtml"],"mappings":"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","file":"chunk-UHRHZXVR.cjs","sourcesContent":["/**\n * Generic service-singleton factory\n *\n * Generalizes the hook-system-singleton pattern: a process-wide slot for a\n * service that code outside the HTTP request context — most importantly cron /\n * `scheduled()` handlers, which have no per-request `c.env` — can reach without\n * threading it through every call.\n *\n * Contract (same as the hook-system singleton):\n * - `get()` throws if read before `set()` (throw-before-get) so wiring-order\n * bugs surface loudly rather than silently no-oping.\n * - `set()` is idempotent (last write wins) so constructing multiple apps in one\n * process (e.g. across tests) never throws.\n * - `reset()` clears the slot for test isolation.\n */\n\nexport interface ServiceSingleton<T> {\n /** Set the process-wide instance. Last write wins. */\n set(instance: T): void\n /** Get the instance; throws if not yet set. */\n get(): T\n /** True if an instance has been set. */\n has(): boolean\n /** Clear the slot (test isolation). */\n reset(): void\n}\n\n/**\n * Create a service singleton.\n *\n * @param label Human-readable name used in the throw-before-get error message\n * (e.g. `'EmailService'`).\n */\nexport function createServiceSingleton<T>(label: string): ServiceSingleton<T> {\n let current: T | undefined\n return {\n set(instance: T) {\n current = instance\n },\n get(): T {\n if (current === undefined) {\n throw new Error(\n `${label} has not been initialized. Its setter must be called (the app factory does this at construction) before reading it.`\n )\n }\n return current\n },\n has(): boolean {\n return current !== undefined\n },\n reset() {\n current = undefined\n },\n }\n}\n","/**\n * Plugin capabilities\n *\n * A plugin declares the capabilities it needs (`capabilities: ['email:send']`).\n * The host then hands it a context whose powerful accessors are *gated* by those\n * declarations: reaching `ctx.email` without having declared `email:send` throws\n * `SonicCapabilityError` immediately, instead of failing deep inside a send.\n *\n * This is the isolation boundary that Strapi (namespacing only) and Payload (full\n * config access) don't have: capabilities make a plugin's blast radius explicit\n * and enforceable, and double as documentation of what a plugin can touch.\n *\n * Phase 1 vocabulary. Payment/queue/scheduled-fetch capabilities are intentionally\n * deferred to Phase 2 (see the overhaul plan §8.4 / open question 2).\n */\n\n// Type-only import (no runtime coupling) so a const-narrowed `ctx.cap.email`\n// resolves to the real EmailService type instead of `unknown`.\nimport type { EmailService } from '../services/email/email-service'\nimport type { HookEventName } from './hooks/catalog'\n\n/**\n * Fixed capability names. `db:<table>` is parameterized (a plugin owns specific\n * tables), so it is matched by pattern rather than listed here.\n */\nexport const FIXED_CAPABILITIES = [\n 'email:send',\n 'cache:read',\n 'cache:write',\n 'media:read',\n 'media:write',\n 'http:fetch',\n 'cron:register',\n 'admin:menu',\n 'hooks.auth:subscribe',\n 'hooks.content:subscribe',\n // Reserved: gates subscription to the email event family once those events are\n // dispatched. Declared now so the canonical vocabulary is stable and the\n // Infowall rename target resolves.\n 'hooks.email:subscribe',\n] as const\n\nexport type FixedCapability = (typeof FIXED_CAPABILITIES)[number]\n\n/** A scoped database capability, e.g. `db:email_log`. */\nexport type DbCapability = `db:${string}`\n\n/** Any declarable capability. */\nexport type Capability = FixedCapability | DbCapability\n\nconst DB_CAPABILITY_RE = /^db:[a-zA-Z_][a-zA-Z0-9_]*$/\n\n/** True if `name` is a recognized capability (fixed name or a valid `db:<table>`). */\nexport function isKnownCapability(name: string): name is Capability {\n return (FIXED_CAPABILITIES as readonly string[]).includes(name) || DB_CAPABILITY_RE.test(name)\n}\n\n/**\n * Thrown when a plugin uses a capability it did not declare.\n */\nexport class SonicCapabilityError extends Error {\n readonly capability: string\n readonly plugin?: string\n /** The API surface the plugin tried to access (e.g. 'ctx.cap.email'). Optional. */\n readonly accessedApi?: string\n constructor(capability: string, plugin?: string, accessedApi?: string) {\n super(\n `${plugin ? `Plugin \"${plugin}\"` : 'Plugin'} used capability \"${capability}\" without declaring it. ` +\n `Add \"${capability}\" to the plugin's capabilities.`\n )\n this.name = 'SonicCapabilityError'\n this.capability = capability\n this.plugin = plugin\n this.accessedApi = accessedApi\n }\n}\n\n/** True if `capability` is in the granted set. */\nexport function hasCapability(granted: readonly string[], capability: string): boolean {\n return granted.includes(capability)\n}\n\n/**\n * Assert a capability is granted, throwing {@link SonicCapabilityError} otherwise.\n */\nexport function assertCapability(granted: readonly string[], capability: string, plugin?: string): void {\n if (!hasCapability(granted, capability)) {\n throw new SonicCapabilityError(capability, plugin)\n }\n}\n\n/**\n * Validate a plugin's declared capability list. Returns the unknown entries (empty\n * array = all valid). Callers decide whether to warn or hard-fail.\n *\n * Apply {@link normalizeCapabilities} first if the input may contain deprecated\n * spellings (e.g. from an older SDK or a sibling fork's manifest).\n */\nexport function validateCapabilities(declared: readonly string[]): string[] {\n return declared.filter((c) => !isKnownCapability(c))\n}\n\n// ── Capability rename / normalization (cross-version & cross-fork portability) ─\n//\n// Lets a plugin authored against a different/older SDK spelling load against the\n// canonical vocabulary without code changes. The map is deprecated→canonical; it\n// is applied before the known-capability check. Seeded with the sibling fork's\n// (Infowall) spellings so plugins built there are portable here.\n\nexport const CAPABILITY_RENAMES = {\n // storage:* → media:* (this fork scopes the media library as `media`)\n 'storage:read': 'media:read',\n 'storage:write': 'media:write',\n // cron is a direct registration, not a hook subscription, here\n 'hooks.cron:register': 'cron:register',\n // `:register` → `:subscribe` verb; content read/write granularity lives in the\n // event name (before/after), so both collapse to one subscription capability\n 'hooks.auth:register': 'hooks.auth:subscribe',\n 'hooks.content-read:register': 'hooks.content:subscribe',\n 'hooks.content-write:register': 'hooks.content:subscribe',\n 'hooks.email-events:register': 'hooks.email:subscribe',\n // NOTE: Infowall's `request:intercept` has no canonical target — there is no\n // middleware-insertion surface to gate yet, so it is intentionally absent\n // (a plugin declaring it will surface as unknown rather than silently no-op).\n} as const satisfies Record<string, Capability>\n\n/**\n * Resolve a (possibly deprecated) capability string to its canonical form, or\n * `null` if it is unknown after rename resolution. Renames apply first, then the\n * result is checked against the known vocabulary.\n */\nexport function normalizeCapability(input: string): Capability | null {\n const renamed: string = (CAPABILITY_RENAMES as Record<string, Capability>)[input] ?? input\n return isKnownCapability(renamed) ? (renamed as Capability) : null\n}\n\n/**\n * Normalize a list of capability strings. Returns the canonical capabilities plus\n * the inputs that remained unknown after rename resolution, so the caller can warn\n * (production) or reject (strict).\n */\nexport function normalizeCapabilities(declared: readonly string[]): {\n capabilities: Capability[]\n unknown: string[]\n} {\n const capabilities: Capability[] = []\n const unknown: string[] = []\n for (const raw of declared) {\n const canonical = normalizeCapability(raw)\n if (canonical) {\n if (!capabilities.includes(canonical)) capabilities.push(canonical)\n } else {\n unknown.push(raw)\n }\n }\n return { capabilities, unknown }\n}\n\n// ── Capability-gated context ─────────────────────────────────────────────────\n\n/** Provider factories for capability-backed accessors. Each is called lazily. */\nexport interface CapabilityProviders {\n email?: () => EmailService\n cache?: () => unknown\n http?: () => typeof fetch\n}\n\n// ── Type-level capability narrowing ──────────────────────────────────────────\ndeclare const CAP_NOT_DECLARED: unique symbol\n/**\n * The type of a capability accessor the plugin did NOT declare. Deliberately a\n * branded type (not `never`, which is assignable to everything): using it where a\n * service is expected is a compile error, so `ctx.cap.email` without `email:send`\n * fails to type-check instead of silently passing.\n */\nexport type CapabilityNotDeclared<C extends string = string> = {\n readonly [CAP_NOT_DECLARED]: C\n}\n\n// `T` if the declared tuple `Caps` contains `C`, else the branded not-declared type.\ntype WhenGranted<Caps extends readonly Capability[], C extends string, T> =\n C extends Caps[number] ? T : CapabilityNotDeclared<C>\n// `T` if `Caps` contains ANY of the union `C`, else the branded not-declared type.\ntype WhenGrantedAny<Caps extends readonly Capability[], C extends string, T> =\n Extract<Caps[number], C> extends never ? CapabilityNotDeclared<C> : T\n\n/**\n * The gated context handed to a plugin. Accessors throw at runtime unless the\n * backing capability was declared; with a const-narrowed `Caps` tuple they are\n * also *typed* to the service (or `never`) at compile time, so `ctx.cap.email`\n * is `EmailService` only when `'email:send'` was declared.\n */\nexport interface CapabilityContext<Caps extends readonly Capability[] = readonly Capability[]> {\n /** The capabilities granted to this plugin. */\n readonly capabilities: readonly string[]\n /** True if the plugin declared `capability`. */\n has(capability: string): boolean\n /** Throw {@link SonicCapabilityError} unless `capability` was declared. */\n require(capability: string): void\n /** Email service. `EmailService` when `email:send` is declared, else `never`. */\n readonly email: WhenGranted<Caps, 'email:send', EmailService>\n /** Cache service. Present when `cache:read` or `cache:write` is declared. */\n readonly cache: WhenGrantedAny<Caps, 'cache:read' | 'cache:write', unknown>\n /** Outbound fetch. Present when `http:fetch` is declared. */\n readonly http: WhenGranted<Caps, 'http:fetch', typeof fetch>\n}\n\n/** The un-narrowed gated context (every accessor typed as its service). */\nexport type PluginCapabilityContext = CapabilityContext</** all */ readonly Capability[]>\n\n\n/**\n * Build a capability-gated context.\n *\n * Accessors are lazy getters: they check the grant (and that a provider was\n * supplied) at access time, so merely constructing the context is cheap and\n * holding a reference to a capability you never use costs nothing.\n *\n * @param granted Capabilities the plugin declared.\n * @param providers Backing service factories (only the granted ones get called).\n * @param plugin Plugin name, for clearer errors.\n */\nexport function createCapabilityContext<const Caps extends readonly Capability[]>(\n granted: Caps,\n providers: CapabilityProviders = {},\n plugin?: string\n): CapabilityContext<Caps> {\n // `any` so the lazy getters satisfy the narrowed accessor types (the provider\n // returns the real service at runtime; gating is enforced dynamically below).\n const gate = (capability: string, anyOf: string[], provider: (() => unknown) | undefined): any => {\n const ok = anyOf.some((c) => hasCapability(granted, c))\n if (!ok) throw new SonicCapabilityError(capability, plugin)\n if (!provider) {\n throw new Error(\n `Capability \"${capability}\" is declared by ${plugin ?? 'the plugin'} but no provider was supplied by the host.`\n )\n }\n return provider()\n }\n\n const ctx: CapabilityContext<Caps> = {\n capabilities: [...granted],\n has: (capability) => hasCapability(granted, capability),\n require: (capability) => assertCapability(granted, capability, plugin),\n get email() {\n return gate('email:send', ['email:send'], providers.email)\n },\n get cache() {\n return gate('cache:read', ['cache:read', 'cache:write'], providers.cache)\n },\n get http() {\n return gate('http:fetch', ['http:fetch'], providers.http)\n },\n }\n return ctx\n}\n\n// ── Hook-subscription capability map ────────────────────────────────────────\n//\n// Maps each catalog event to the capability a plugin must declare in order to\n// subscribe to it. Used by the wire phase (Phase A) to gate declarative hook\n// registrations. Plugins that don't declare the required capability have the\n// offending hook skipped (warn in prod, error in strict).\n\nexport const HOOK_CAPABILITY_MAP: Record<HookEventName, Capability> = {\n 'content:read': 'hooks.content:subscribe',\n 'content:before:create': 'hooks.content:subscribe',\n 'content:before:update': 'hooks.content:subscribe',\n 'content:before:delete': 'hooks.content:subscribe',\n 'content:after:create': 'hooks.content:subscribe',\n 'content:after:update': 'hooks.content:subscribe',\n 'content:after:delete': 'hooks.content:subscribe',\n 'content:after:publish': 'hooks.content:subscribe',\n 'auth:registration:completed': 'hooks.auth:subscribe',\n 'auth:password-reset:requested': 'hooks.auth:subscribe',\n 'auth:password-reset:completed': 'hooks.auth:subscribe',\n 'auth:magic-link:consumed': 'hooks.auth:subscribe',\n 'auth:otp:verified': 'hooks.auth:subscribe',\n}\n","/**\n * definePlugin() — the v3 plugin authoring entry point\n *\n * A plugin is authored as a single typed declaration and consumed, unchanged, by\n * every part of the runtime:\n *\n * export const emailPlugin = definePlugin({\n * id: 'email',\n * version: '3.0.0',\n * capabilities: ['email:send', 'hooks.auth:subscribe', 'cron:register'],\n * register(app) { app.route('/admin/plugins/email', emailRoutes) }, // SYNC\n * async onBoot(ctx) { // ASYNC\n * ctx.hooks.on('auth:registration:completed', (p) => { ... }) // typed\n * ctx.cap.email // gated\n * },\n * crons: [{ schedule: '*\\/15 * * * *', hookFamily: 'email-reconciliation' }],\n * async onCronTick(event, ctx) { ... },\n * })\n *\n * The object it returns satisfies the structural contracts the runtime already\n * uses — `MountablePlugin` (mount.ts), `WirablePlugin` (wire.ts), `CronablePlugin`\n * (cron.ts) — plus the legacy `Plugin` metadata fields the admin/registry read.\n * No adapters: a defined plugin drops straight into `plugins.register` or the core\n * plugin list.\n *\n * The value definePlugin adds over a hand-written object is the enriched context:\n * inside `onBoot`/`onCronTick` the author gets a *typed* hook facade (`ctx.hooks`)\n * and the *capability-gated* service context (`ctx.cap`), instead of the raw\n * string-keyed hook system. See the two-phase boot contract: `register` is\n * synchronous (routes only); everything env-dependent lives in `onBoot`.\n */\n\nimport type { Hono } from 'hono'\nimport type { Capability } from '../capabilities'\nimport {\n createCapabilityContext,\n normalizeCapabilities,\n type CapabilityProviders,\n type CapabilityContext,\n} from '../capabilities'\nimport { createTypedHooks, type TypedHooks, type TypedHookHandler } from '../hooks/typed-hooks'\nimport type { HookEventName } from '../hooks/catalog'\nimport type { PluginBootContext, WirableHook } from '../wire'\nimport type { CronContext, CronDeclaration, CronTickEvent } from '../cron'\nimport type { MountableRoute } from '../mount'\nimport { getCoreVersion } from '../../utils/version'\nimport type { ConfigSchema } from './config-schema'\nimport type { PluginMenuEntry } from '../../services/plugin-menu-singleton'\n\n// ── Minimal semver helpers (no external dep — Workers are bundle-size constrained) ─\n\n/** True if `v` is a valid semver string (X.Y.Z with optional pre-release). */\nfunction isSemver(v: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?(\\+[\\w.]+)?$/.test(v.trim())\n}\n\n/**\n * Very lightweight semver range satisfier. Handles the most common range forms:\n * exact (`1.2.3`), caret (`^1.2.3` = compatible major), tilde (`~1.2.3` = compatible\n * minor), comparators (`>=1.0.0`, `>1`, `<2.0.0`), and space-separated AND chains.\n * Not a full semver implementation — use the `semver` npm package if you need\n * full range syntax in a non-Workers environment.\n */\nfunction semverSatisfies(version: string, range: string): boolean {\n try {\n const [major, minor, patch] = version.trim().split('-')[0]!.split('.').map(Number)\n const v = major! * 1_000_000 + (minor ?? 0) * 1_000 + (patch ?? 0)\n\n const toInt = (s: string) => {\n const [a, b, c] = s.split('.').map(Number)\n return a! * 1_000_000 + (b ?? 0) * 1_000 + (c ?? 0)\n }\n\n // AND chain: all clauses must pass.\n return range\n .trim()\n .split(/\\s+(?=[><=^~])|\\s+(?=\\d)/)\n .filter(Boolean)\n .every((clause) => {\n const c = clause.trim()\n if (c.startsWith('^')) {\n const base = toInt(c.slice(1))\n const nextMajor = Math.floor(base / 1_000_000 + 1) * 1_000_000\n return v >= base && v < nextMajor\n }\n if (c.startsWith('~')) {\n const base = toInt(c.slice(1))\n const nextMinor = Math.floor(base / 1_000 + 1) * 1_000\n return v >= base && v < nextMinor\n }\n if (c.startsWith('>=')) return v >= toInt(c.slice(2))\n if (c.startsWith('<=')) return v <= toInt(c.slice(2))\n if (c.startsWith('>')) return v > toInt(c.slice(1))\n if (c.startsWith('<')) return v < toInt(c.slice(1))\n return v === toInt(c) // exact\n })\n } catch {\n return true // fail open — don't block a plugin on a parse error\n }\n}\n\n/**\n * Declarative typed hook subscriptions: a map of canonical event name → handler,\n * each narrowed to that event's payload. Flattened into the plugin's `hooks[]`\n * and subscribed during the wire phase. Use `onBoot`'s `ctx.hooks.on()` instead\n * for dynamic/conditional subscriptions.\n */\nexport type DeclarativeHooks = {\n [E in HookEventName]?: TypedHookHandler<E>\n}\n\n/**\n * Context handed to a defined plugin's `onBoot` / `onCronTick`.\n *\n * Enriches the raw boot/cron context with a typed hook facade and the gated\n * capability context, while keeping `raw` and `env` available as an escape hatch.\n */\nexport interface DefinedPluginContext<Caps extends readonly Capability[] = readonly Capability[]> {\n /** Typed hook facade — `ctx.hooks.on('auth:registration:completed', …)`. */\n hooks: TypedHooks\n /**\n * Capability-gated services. With a const-narrowed `Caps`, `ctx.cap.email` is\n * typed `EmailService` only when `'email:send'` was declared (else `never`),\n * and throws `SonicCapabilityError` at runtime if accessed undeclared.\n */\n cap: CapabilityContext<Caps>\n /** Runtime bindings, when available (absent during construction). */\n env?: Record<string, unknown>\n /** The unwrapped context the runtime passed. */\n raw: PluginBootContext | CronContext\n}\n\n/** Input to {@link definePlugin}. */\nexport interface DefinePluginInput<Caps extends readonly Capability[] = readonly []> {\n /** Unique, stable plugin id (kebab-case). Becomes the plugin `name`. */\n id: string\n /** Human-readable display name. Defaults to `id`. */\n name?: string\n /**\n * Semantic version of this plugin (e.g. `'1.2.3'`). Must be a valid semver\n * string — invalid values emit a console.warn at definition time.\n */\n version: string\n /**\n * A semver range expressing which SonicJS core versions this plugin supports\n * (e.g. `'^3.0.0'` or `'>=3.1.0 <4.0.0'`). Checked against the running\n * core version at registration; a mismatch logs a compatibility warning but\n * does not block activation (plugins remain resilient by default).\n */\n sonicjsVersionRange?: string\n description?: string\n author?: { name: string; email?: string; url?: string }\n /** Other plugin ids this one needs (load-order / activation). */\n dependencies?: string[]\n /**\n * Capabilities this plugin declares. The gated `ctx.cap` accessors throw for\n * anything not listed here. Pass as a literal (`['email:send'] as const` is not\n * needed — the `const` type param infers the tuple) to get `ctx.cap` narrowed.\n * Unknown/deprecated names are normalized then warned about at definition.\n */\n capabilities?: Caps\n\n // ── Synchronous registration (routes only) ──\n /** Declarative routes (mounted before the /admin catch-all). */\n routes?: MountableRoute[]\n /**\n * Imperative route registration. MUST be synchronous (Hono's router locks after\n * the first request). Async work belongs in `onBoot`.\n */\n register?: (app: Hono) => void\n\n // ── Asynchronous wiring ──\n /**\n * Declarative typed hook subscriptions (`{ 'content:after:create': (p) => … }`).\n * Subscribed during the wire phase; each handler is narrowed to its event payload.\n */\n hooks?: DeclarativeHooks\n /**\n * Run once on first request, after every plugin has registered. The place for\n * dynamic hook subscriptions (`ctx.hooks.on(...)`) and env-dependent setup.\n */\n onBoot?: (context: DefinedPluginContext<Caps>) => void | Promise<void>\n\n // ── Cron ──\n /** Scheduled-work declarations (also list the expressions in wrangler.toml). */\n crons?: CronDeclaration[]\n /** Handler for a fired cron; branch on `event.hookFamily`. */\n onCronTick?: (event: CronTickEvent, context: DefinedPluginContext<Caps>) => void | Promise<void>\n\n // ── Lifecycle (DB/schema only — never touches routes) ──\n install?: (context: unknown) => void | Promise<void>\n uninstall?: (context: unknown) => void | Promise<void>\n activate?: (context: unknown) => void | Promise<void>\n deactivate?: (context: unknown) => void | Promise<void>\n\n // ── Declarative admin surface ──\n /**\n * Declarative admin-sidebar entries collected by registerPlugins. The catalyst\n * sidebar renders them automatically; no per-plugin `addMenuItem(...)` call\n * required.\n */\n menu?: PluginMenuEntry[]\n /**\n * Schema-driven settings. Declaring this auto-renders the admin form at\n * `/admin/settings/plugins/:id`, parses FormData back into typed values, and\n * persists them via the plugin-service. Authors no longer hand-roll settings\n * routes/templates.\n */\n configSchema?: ConfigSchema\n}\n\n/**\n * The runtime shape produced by {@link definePlugin}. Carries the legacy metadata\n * fields plus the v3 surfaces; structurally satisfies `MountablePlugin`,\n * `WirablePlugin`, and `CronablePlugin`.\n */\nexport interface DefinedPlugin {\n id: string\n name: string\n version: string\n /** The semver range for SonicJS core compatibility declared by the author. */\n sonicjsVersionRange?: string\n description?: string\n author?: { name: string; email?: string; url?: string }\n dependencies?: string[]\n capabilities: Capability[]\n routes?: MountableRoute[]\n register?: (app: Hono) => void\n /** Declarative hook subscriptions, flattened for the wire phase. */\n hooks?: WirableHook[]\n /** Wrapped onBoot accepting the runtime's raw boot context. */\n onBoot?: (context: PluginBootContext) => void | Promise<void>\n crons?: CronDeclaration[]\n /** Wrapped onCronTick accepting the runtime's raw cron context. */\n onCronTick?: (event: CronTickEvent, context: CronContext) => void | Promise<void>\n install?: (context: unknown) => void | Promise<void>\n uninstall?: (context: unknown) => void | Promise<void>\n activate?: (context: unknown) => void | Promise<void>\n deactivate?: (context: unknown) => void | Promise<void>\n /** Declarative admin sidebar entries. registerPlugins collects + sets the menu singleton. */\n menu?: PluginMenuEntry[]\n /** Schema-driven settings. Renders the admin settings form for this plugin. */\n configSchema?: ConfigSchema\n /** Marker so tooling/tests can detect a v3-defined plugin. */\n // eslint-disable-next-line @typescript-eslint/naming-convention -- intentional internal marker\n readonly __sonicV3: true\n}\n\n/**\n * Build the enriched context from whatever raw context the runtime passed.\n *\n * Capability providers ride on the raw context (`raw.providers`) — the host\n * supplies real `email`/`cache`/`http` factories there. When none are supplied, a\n * declared-but-used capability throws \"no provider supplied by host\", which is the\n * correct signal during early bring-up.\n */\nfunction enrich<Caps extends readonly Capability[]>(\n raw: PluginBootContext | CronContext,\n runtimeCaps: readonly Capability[],\n pluginName: string\n): DefinedPluginContext<Caps> {\n const providers = (raw as { providers?: CapabilityProviders }).providers ?? {}\n return {\n hooks: createTypedHooks(raw.hooks),\n // Runtime gating uses the normalized capability set; the context TYPE reflects\n // the declared `Caps` tuple (the narrowing the author sees).\n cap: createCapabilityContext(runtimeCaps as unknown as Caps, providers, pluginName),\n env: raw.env,\n raw,\n }\n}\n\n/**\n * Define a v3 plugin. Validates declared capabilities (warns on unknown), then\n * returns a runtime-ready plugin whose `onBoot`/`onCronTick` receive the enriched,\n * typed, capability-gated context. The `const Caps` type parameter captures the\n * declared capability tuple so `ctx.cap` is narrowed at the author's call site.\n */\nexport function definePlugin<const Caps extends readonly Capability[] = readonly []>(\n input: DefinePluginInput<Caps>\n): DefinedPlugin {\n if (!input.id) throw new Error('definePlugin: `id` is required')\n if (!input.version) throw new Error(`definePlugin: \\`version\\` is required (plugin \"${input.id}\")`)\n\n // Semver validation: warn if the plugin's own version is not a valid semver string.\n if (!isSemver(input.version)) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugins] Plugin \"${input.id}\" has an invalid version: \"${input.version}\". ` +\n `Use a valid semver string (e.g. \"1.0.0\") to participate in version-range checks.`\n )\n }\n\n // SonicJS core compatibility range check.\n if (input.sonicjsVersionRange) {\n const coreVersion = getCoreVersion()\n if (!semverSatisfies(coreVersion, input.sonicjsVersionRange)) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugins] Plugin \"${input.id}\" declares sonicjsVersionRange \"${input.sonicjsVersionRange}\" ` +\n `but running core version is \"${coreVersion}\". ` +\n `The plugin may not work correctly. Consider updating the plugin or the version range.`\n )\n }\n }\n\n // Normalize declared capabilities to canonical names first (resolves deprecated\n // / cross-fork spellings like `storage:write` → `media:write`), then warn on any\n // that remain unknown. Strict-reject at registration is layered in Phase 5d.\n const { capabilities, unknown } = normalizeCapabilities(input.capabilities ?? [])\n if (unknown.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugins] Plugin \"${input.id}\" declares unknown capabilities: ${unknown.join(', ')}. ` +\n `These will gate nothing. Check for typos or update the capability vocabulary.`\n )\n }\n\n const name = input.id\n\n const onBoot = input.onBoot\n ? (raw: PluginBootContext) => input.onBoot!(enrich(raw, capabilities, name))\n : undefined\n\n const onCronTick = input.onCronTick\n ? (event: CronTickEvent, raw: CronContext) => input.onCronTick!(event, enrich(raw, capabilities, name))\n : undefined\n\n // Flatten the declarative typed `hooks` map into the wirable `hooks[]` array.\n // Each handler is wrapped to the raw (data, context) shape, coalescing a void\n // return back to the incoming payload (matching createTypedHooks().on()).\n const hooks: WirableHook[] | undefined = input.hooks\n ? Object.entries(input.hooks)\n .filter(([, h]) => typeof h === 'function')\n .map(([eventName, h]) => ({\n name: eventName,\n handler: async (data: any, context: any) => {\n const result = await (h as TypedHookHandler<HookEventName>)(data, context ?? {})\n return result === undefined ? data : result\n },\n }))\n : undefined\n\n return {\n id: input.id,\n name,\n version: input.version,\n sonicjsVersionRange: input.sonicjsVersionRange,\n description: input.description,\n author: input.author,\n dependencies: input.dependencies,\n capabilities,\n routes: input.routes,\n register: input.register,\n hooks,\n onBoot,\n crons: input.crons,\n onCronTick,\n install: input.install,\n uninstall: input.uninstall,\n activate: input.activate,\n deactivate: input.deactivate,\n menu: input.menu,\n configSchema: input.configSchema,\n // eslint-disable-next-line @typescript-eslint/naming-convention -- intentional internal marker\n __sonicV3: true,\n }\n}\n\n/** True if `plugin` was produced by {@link definePlugin}. */\nexport function isDefinedPlugin(plugin: unknown): plugin is DefinedPlugin {\n // eslint-disable-next-line @typescript-eslint/naming-convention -- intentional internal marker\n return !!plugin && typeof plugin === 'object' && (plugin as { __sonicV3?: unknown }).__sonicV3 === true\n}\n","/**\n * Schema-driven plugin settings.\n *\n * Plugins declare `configSchema: { key: ConfigSchemaField }` on definePlugin.\n * The host renders the admin settings UI from the schema, parses FormData back\n * into typed values, and exposes the resulting record via `ctx.settings.load()`.\n *\n * Field kinds: 'string' | 'number' | 'boolean' | 'select'. New kinds get added\n * here once and every consumer picks them up.\n *\n * Phase 1 — settings UI only. The renderer emits plain HTML strings designed to\n * compose into the existing admin layout (no client-side JS). FormData parsing\n * coalesces unchecked-checkbox omission into `false` (the only browser quirk\n * the renderer must account for).\n */\n\nimport { escapeHtml } from '../../utils/sanitize'\n\n// ── Field model ──────────────────────────────────────────────────────────────\n\ninterface BaseField {\n label: string\n description?: string\n required?: boolean\n}\n\nexport interface StringField extends BaseField {\n type: 'string'\n default?: string\n format?: 'email' | 'url' | 'password'\n /** Render as `<input type=\"password\">`. Implied when `format === 'password'`. */\n sensitive?: boolean\n placeholder?: string\n minLength?: number\n maxLength?: number\n}\n\nexport interface NumberField extends BaseField {\n type: 'number'\n default?: number\n min?: number\n max?: number\n step?: number\n}\n\nexport interface BooleanField extends BaseField {\n type: 'boolean'\n default?: boolean\n}\n\nexport interface SelectField extends BaseField {\n type: 'select'\n default?: string\n /** Either `['us','eu']` shorthand or `[{ value, label }]` for distinct display strings. */\n options: readonly string[] | readonly { value: string; label: string }[]\n}\n\nexport type ConfigSchemaField = StringField | NumberField | BooleanField | SelectField\n\nexport type ConfigSchema = Record<string, ConfigSchemaField>\n\n/** Parsed shape — typed record inferred from the schema. */\nexport type SettingsFor<S extends ConfigSchema> = {\n [K in keyof S]: S[K] extends StringField\n ? string\n : S[K] extends NumberField\n ? number\n : S[K] extends BooleanField\n ? boolean\n : S[K] extends SelectField\n ? string\n : never\n}\n\n// ── Parse ────────────────────────────────────────────────────────────────────\n\nexport interface ParsedField {\n key: string\n field: ConfigSchemaField\n}\n\n/** Stable, ordered field list (preserves declaration order). */\nexport function parseConfigSchema(schema: ConfigSchema): ParsedField[] {\n return Object.entries(schema).map(([key, field]) => ({ key, field }))\n}\n\n// ── Render ───────────────────────────────────────────────────────────────────\n\n/**\n * Render all fields as HTML controls. Output is a sequence of `<div class=\"field\">…</div>`\n * blocks designed to drop into the admin form template (no surrounding `<form>` or\n * submit button — those belong to the page that calls this).\n */\nexport function renderSchemaFields(\n schema: ConfigSchema,\n currentValues: Record<string, unknown> = {}\n): string {\n return parseConfigSchema(schema)\n .map(({ key, field }) => {\n const value = key in currentValues ? currentValues[key] : (field as { default?: unknown }).default\n return renderField(key, field, value)\n })\n .join('\\n')\n}\n\nfunction renderField(key: string, field: ConfigSchemaField, value: unknown): string {\n const id = `field-${key}`\n const requiredAttr = field.required ? ' required' : ''\n const labelHtml = `${escapeHtml(field.label)}${field.required ? ' *' : ''}`\n const helpHtml = field.description ? `<p class=\"help text-sm text-gray-400 mt-1\">${escapeHtml(field.description)}</p>` : ''\n\n switch (field.type) {\n case 'string': {\n const isPassword = field.sensitive === true || field.format === 'password'\n const inputType = isPassword ? 'password' : field.format === 'email' ? 'email' : field.format === 'url' ? 'url' : 'text'\n const placeholder = field.placeholder ? ` placeholder=\"${escapeHtml(field.placeholder)}\"` : ''\n const min = field.minLength != null ? ` minlength=\"${field.minLength}\"` : ''\n const max = field.maxLength != null ? ` maxlength=\"${field.maxLength}\"` : ''\n return `\n<div class=\"field mb-4\">\n <label for=\"${id}\" class=\"block text-sm font-medium mb-1\">${labelHtml}</label>\n <input id=\"${id}\" name=\"${escapeHtml(key)}\" type=\"${inputType}\"\n class=\"w-full rounded border border-gray-700 bg-gray-800 px-3 py-2 text-sm\"\n value=\"${escapeHtml(String(value ?? ''))}\"${placeholder}${min}${max}${requiredAttr} />\n ${helpHtml}\n</div>`.trim()\n }\n case 'number': {\n const min = field.min != null ? ` min=\"${field.min}\"` : ''\n const max = field.max != null ? ` max=\"${field.max}\"` : ''\n const step = field.step != null ? ` step=\"${field.step}\"` : ''\n return `\n<div class=\"field mb-4\">\n <label for=\"${id}\" class=\"block text-sm font-medium mb-1\">${labelHtml}</label>\n <input id=\"${id}\" name=\"${escapeHtml(key)}\" type=\"number\"\n class=\"w-full rounded border border-gray-700 bg-gray-800 px-3 py-2 text-sm\"\n value=\"${value == null ? '' : escapeHtml(String(value))}\"${min}${max}${step}${requiredAttr} />\n ${helpHtml}\n</div>`.trim()\n }\n case 'boolean': {\n const checked = value === true ? ' checked' : ''\n return `\n<div class=\"field mb-4\">\n <label class=\"flex items-center gap-2 text-sm font-medium\">\n <input name=\"${escapeHtml(key)}\" type=\"checkbox\" class=\"rounded\"${checked} />\n ${labelHtml}\n </label>\n ${helpHtml}\n</div>`.trim()\n }\n case 'select': {\n const optionsHtml = field.options\n .map((o) => {\n const opt = typeof o === 'string' ? { value: o, label: o } : o\n const selected = opt.value === value ? ' selected' : ''\n return `<option value=\"${escapeHtml(opt.value)}\"${selected}>${escapeHtml(opt.label)}</option>`\n })\n .join('')\n return `\n<div class=\"field mb-4\">\n <label for=\"${id}\" class=\"block text-sm font-medium mb-1\">${labelHtml}</label>\n <select id=\"${id}\" name=\"${escapeHtml(key)}\"\n class=\"w-full rounded border border-gray-700 bg-gray-800 px-3 py-2 text-sm\"${requiredAttr}>\n ${optionsHtml}\n </select>\n ${helpHtml}\n</div>`.trim()\n }\n }\n}\n\n// ── FormData → settings ──────────────────────────────────────────────────────\n\n/**\n * Coerce FormData entries into typed settings per the schema. Notably:\n * - Unchecked checkboxes are omitted by the browser; we coalesce to `false`.\n * - Numbers parse via `Number()` and fall back to the field's default if invalid.\n * - Strings preserve empty string (NOT default) so an admin can intentionally clear.\n */\nexport function parseFormDataToSettings(schema: ConfigSchema, form: FormData): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const { key, field } of parseConfigSchema(schema)) {\n switch (field.type) {\n case 'string': {\n const raw = form.get(key)\n result[key] = raw == null ? field.default ?? '' : String(raw)\n break\n }\n case 'number': {\n const raw = form.get(key)\n if (raw == null || raw === '') {\n result[key] = field.default\n } else {\n const n = Number(raw)\n result[key] = Number.isFinite(n) ? n : field.default\n }\n break\n }\n case 'boolean': {\n // Unchecked checkbox → not present in FormData → false.\n result[key] = form.get(key) != null\n break\n }\n case 'select': {\n const raw = form.get(key)\n result[key] = raw == null ? field.default ?? '' : String(raw)\n break\n }\n }\n }\n return result\n}\n\n// ── Defaults ─────────────────────────────────────────────────────────────────\n\n/** Fill missing keys with field defaults. Existing keys (incl. `false`/`0`/'') win. */\nexport function applySchemaDefaults<S extends ConfigSchema>(\n schema: S,\n stored: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...stored }\n for (const { key, field } of parseConfigSchema(schema)) {\n if (result[key] === undefined) {\n const def = (field as { default?: unknown }).default\n if (def !== undefined) result[key] = def\n }\n }\n return result\n}\n","/**\n * In-memory registry of registered plugin definitions, indexed by id.\n *\n * Populated by `registerPlugins()` at app construction. The admin settings\n * route uses it to look up a plugin's `configSchema` so the schema-driven\n * settings form can be auto-rendered without per-plugin glue code.\n *\n * Read by the admin layer; written ONLY by registerPlugins.\n */\n\nimport type { RegisterablePlugin } from '../plugins/sdk/register-plugins'\n\nlet registry: ReadonlyMap<string, RegisterablePlugin> = new Map()\n\nexport function setPluginDefinitions(plugins: ReadonlyArray<RegisterablePlugin>): void {\n const next = new Map<string, RegisterablePlugin>()\n for (const p of plugins) next.set(p.id, p)\n registry = next\n}\n\nexport function getPluginDefinition(id: string): RegisterablePlugin | undefined {\n return registry.get(id)\n}\n\nexport function getAllPluginDefinitions(): ReadonlyArray<RegisterablePlugin> {\n return Array.from(registry.values())\n}\n\nexport function resetPluginDefinitions(): void {\n registry = new Map()\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunk2CB4KY7I_cjs = require('./chunk-2CB4KY7I.cjs');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var chunkQJNKSFDJ_cjs = require('./chunk-QJNKSFDJ.cjs');
|
|
5
|
+
var chunkORF4CT74_cjs = require('./chunk-ORF4CT74.cjs');
|
|
6
6
|
var chunkK623Q6WD_cjs = require('./chunk-K623Q6WD.cjs');
|
|
7
7
|
var chunkJ6JTWD2A_cjs = require('./chunk-J6JTWD2A.cjs');
|
|
8
8
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
@@ -70,7 +70,7 @@ var DocumentTypeRegistry = class {
|
|
|
70
70
|
now,
|
|
71
71
|
def.id
|
|
72
72
|
).run();
|
|
73
|
-
await
|
|
73
|
+
await chunkORF4CT74_cjs.ensureScalarSchema(this.db, def.id, def.queryableFields ?? []);
|
|
74
74
|
const updated = await this.findById(def.id);
|
|
75
75
|
this.cache.set(def.id, updated);
|
|
76
76
|
return updated;
|
|
@@ -92,7 +92,7 @@ var DocumentTypeRegistry = class {
|
|
|
92
92
|
now,
|
|
93
93
|
now
|
|
94
94
|
).run();
|
|
95
|
-
await
|
|
95
|
+
await chunkORF4CT74_cjs.ensureScalarSchema(this.db, def.id, def.queryableFields ?? []);
|
|
96
96
|
const created = await this.findById(def.id);
|
|
97
97
|
this.cache.set(def.id, created);
|
|
98
98
|
return created;
|
|
@@ -330,7 +330,7 @@ async function bootstrapDocumentTypes(db) {
|
|
|
330
330
|
}
|
|
331
331
|
async function autoRegisterCollectionDocumentTypes(db) {
|
|
332
332
|
const registry = new DocumentTypeRegistry(db);
|
|
333
|
-
const collections =
|
|
333
|
+
const collections = chunkQJNKSFDJ_cjs.getCollectionRegistry().listActive();
|
|
334
334
|
const registered = [];
|
|
335
335
|
for (const collection of collections) {
|
|
336
336
|
if (collection.internal) continue;
|
|
@@ -422,7 +422,7 @@ function bootstrapMiddleware(config = {}) {
|
|
|
422
422
|
try {
|
|
423
423
|
console.log("[Bootstrap] Starting system initialization...");
|
|
424
424
|
console.log("[Bootstrap] Checking schema compatibility...");
|
|
425
|
-
const migrationService = new
|
|
425
|
+
const migrationService = new chunkORF4CT74_cjs.MigrationService(c.env.DB);
|
|
426
426
|
await migrationService.ensureSchemaCompatibility();
|
|
427
427
|
try {
|
|
428
428
|
const kv = c.env.CACHE_KV;
|
|
@@ -435,8 +435,8 @@ function bootstrapMiddleware(config = {}) {
|
|
|
435
435
|
}
|
|
436
436
|
console.log("[Bootstrap] Populating collection registry...");
|
|
437
437
|
try {
|
|
438
|
-
const configs = await
|
|
439
|
-
|
|
438
|
+
const configs = await chunkQJNKSFDJ_cjs.loadCollectionConfigs();
|
|
439
|
+
chunkQJNKSFDJ_cjs.getCollectionRegistry().register(configs);
|
|
440
440
|
console.log(`[Bootstrap] Registry populated with ${configs.length} collection(s)`);
|
|
441
441
|
} catch (error) {
|
|
442
442
|
console.error("[Bootstrap] Error populating collection registry:", error);
|
|
@@ -466,7 +466,7 @@ function bootstrapMiddleware(config = {}) {
|
|
|
466
466
|
}
|
|
467
467
|
if (!config.plugins?.disableAll) {
|
|
468
468
|
console.log("[Bootstrap] Bootstrapping core plugins...");
|
|
469
|
-
const bootstrapService = new
|
|
469
|
+
const bootstrapService = new chunkQJNKSFDJ_cjs.PluginBootstrapService(c.env.DB);
|
|
470
470
|
const needsBootstrap = await bootstrapService.isBootstrapNeeded();
|
|
471
471
|
if (needsBootstrap) {
|
|
472
472
|
await bootstrapService.bootstrapCorePlugins();
|
|
@@ -477,7 +477,7 @@ function bootstrapMiddleware(config = {}) {
|
|
|
477
477
|
bootstrapComplete = true;
|
|
478
478
|
console.log("[Bootstrap] System initialization completed");
|
|
479
479
|
try {
|
|
480
|
-
const registry =
|
|
480
|
+
const registry = chunkQJNKSFDJ_cjs.getCollectionRegistry();
|
|
481
481
|
const collections = registry.listActive();
|
|
482
482
|
const countResult = await c.env.DB.prepare(
|
|
483
483
|
`SELECT type_id, COUNT(*) AS cnt FROM documents
|
|
@@ -510,7 +510,7 @@ function bootstrapMiddleware(config = {}) {
|
|
|
510
510
|
}
|
|
511
511
|
} catch {
|
|
512
512
|
}
|
|
513
|
-
const telemetry =
|
|
513
|
+
const telemetry = chunkQJNKSFDJ_cjs.getTelemetryService();
|
|
514
514
|
await telemetry.trackProjectSnapshot({
|
|
515
515
|
installation_id: installationId,
|
|
516
516
|
collection_names: collections.map((c2) => c2.name),
|
|
@@ -1215,5 +1215,5 @@ exports.securityHeadersMiddleware = securityHeadersMiddleware;
|
|
|
1215
1215
|
exports.securityLoggingMiddleware = securityLoggingMiddleware;
|
|
1216
1216
|
exports.validateCsrfToken = validateCsrfToken;
|
|
1217
1217
|
exports.verifySecurityConfig = verifySecurityConfig;
|
|
1218
|
-
//# sourceMappingURL=chunk-
|
|
1219
|
-
//# sourceMappingURL=chunk-
|
|
1218
|
+
//# sourceMappingURL=chunk-YJEBDJDV.cjs.map
|
|
1219
|
+
//# sourceMappingURL=chunk-YJEBDJDV.cjs.map
|