@ai-matrx/alchemy 0.8.60 → 0.10.1
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/CHANGELOG.md +60 -0
- package/README.md +3 -0
- package/dist/actions.cjs +1 -1
- package/dist/actions.cjs.map +1 -1
- package/dist/actions.d.cts +465 -4
- package/dist/actions.d.ts +465 -4
- package/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/checks.cjs +1 -1
- package/dist/checks.cjs.map +1 -1
- package/dist/checks.d.cts +22 -1
- package/dist/checks.d.ts +22 -1
- package/dist/checks.js +2 -2
- package/dist/checks.js.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +283 -39
- package/dist/core.d.ts +283 -39
- package/dist/core.js +2 -2
- package/dist/core.js.map +1 -1
- package/dist/declare.cjs +1 -1
- package/dist/declare.cjs.map +1 -1
- package/dist/declare.d.cts +12 -4
- package/dist/declare.d.ts +12 -4
- package/dist/declare.js +1 -1
- package/dist/declare.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +283 -39
- package/dist/index.d.ts +283 -39
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/menu.cjs +1 -1
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.d.cts +262 -3
- package/dist/menu.d.ts +262 -3
- package/dist/menu.js +1 -1
- package/dist/menu.js.map +1 -1
- package/dist/operate-server.d.cts +11 -1
- package/dist/operate-server.d.ts +11 -1
- package/dist/operate.cjs +1 -1
- package/dist/operate.cjs.map +1 -1
- package/dist/operate.d.cts +283 -39
- package/dist/operate.d.ts +283 -39
- package/dist/operate.js +2 -2
- package/dist/operate.js.map +1 -1
- package/dist/ports.cjs.map +1 -1
- package/dist/ports.d.cts +269 -2
- package/dist/ports.d.ts +269 -2
- package/dist/react-bar.cjs +1 -1
- package/dist/react-bar.cjs.map +1 -1
- package/dist/react-bar.d.cts +4 -2
- package/dist/react-bar.d.ts +4 -2
- package/dist/react-bar.js +1 -1
- package/dist/react-bar.js.map +1 -1
- package/dist/react-host.d.cts +262 -3
- package/dist/react-host.d.ts +262 -3
- package/dist/react-menu.cjs +1 -1
- package/dist/react-menu.cjs.map +1 -1
- package/dist/react-menu.d.cts +4 -2
- package/dist/react-menu.d.ts +4 -2
- package/dist/react-menu.js +1 -1
- package/dist/react-menu.js.map +1 -1
- package/dist/react-overflow.cjs +1 -1
- package/dist/react-overflow.cjs.map +1 -1
- package/dist/react-overflow.d.cts +262 -3
- package/dist/react-overflow.d.ts +262 -3
- package/dist/react-overflow.js +1 -1
- package/dist/react-overflow.js.map +1 -1
- package/dist/react-palette.cjs +1 -1
- package/dist/react-palette.cjs.map +1 -1
- package/dist/react-palette.d.cts +4 -2
- package/dist/react-palette.d.ts +4 -2
- package/dist/react-palette.js +1 -1
- package/dist/react-palette.js.map +1 -1
- package/dist/react-selection.cjs +1 -1
- package/dist/react-selection.cjs.map +1 -1
- package/dist/react-selection.d.cts +4 -2
- package/dist/react-selection.d.ts +4 -2
- package/dist/react-selection.js +1 -1
- package/dist/react-selection.js.map +1 -1
- package/dist/react-sheet.cjs +1 -1
- package/dist/react-sheet.cjs.map +1 -1
- package/dist/react-sheet.d.cts +4 -2
- package/dist/react-sheet.d.ts +4 -2
- package/dist/react-sheet.js +1 -1
- package/dist/react-sheet.js.map +1 -1
- package/package.json +1 -1
package/dist/actions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/actions/click-target.ts","../src/actions/types.ts","../src/actions/registry.ts","../src/declare/sensitivity.ts","../src/actions/projection.ts","../src/declare/keys.ts","../src/actions/target.ts","../src/actions/run.ts"],"sourcesContent":["/**\n * The click target (CONTRACT §2.4) in its own module: `/ports` references it,\n * and `/ports` must stay free of every other package (types only).\n */\nimport type { QualifiedValueKey, ResolvedItem, ResolvedSurfaceDeclaration, WriteTarget } from \"../declare/types\";\n\n/** The six universal verbs — the ONLY rows that may grey (R1 c). */\nexport const UNIVERSAL_VERBS = [\"copy\", \"cut\", \"paste\", \"undo\", \"redo\", \"find\"] as const;\nexport type UniversalVerb = (typeof UNIVERSAL_VERBS)[number];\n\n/** The transfer Payload's kinds (`actions/types.ts` asserts equality at compile time). */\nexport type PayloadKind = \"text\" | \"markdown\" | \"json\" | \"rows\" | \"registered\";\n\n/** What eligibility is computed from: everything declared at the click target. */\nexport interface ClickTarget {\n surface: { instanceId: string; surfaceName: string } | null;\n /** The resolved declaration (inheritance applied). Eligibility decides by KEY existence over it. */\n declaration: ResolvedSurfaceDeclaration | null;\n /** Declared value keys with a read path here (screen names + qualified item keys). Key existence, not population. */\n valueKeys: ReadonlySet<QualifiedValueKey>;\n /** Scope chain, most general first: [\"global\", \"<domain>\", \"<surfaceName>\"]. */\n scopeChain: readonly string[];\n /** The surface's explicit exclusions (the one override). */\n excludedActionIds: ReadonlySet<string>;\n item: ResolvedItem | null;\n level: string | null;\n /** Offsets + the live range handle, editable or not. */\n selection: {\n text: string;\n type: \"editable\" | \"non-editable\";\n start: number;\n end: number;\n /** Opaque host handle (DOM Range / element) used to restore or stream into the selection. */\n handle?: unknown;\n } | null;\n /** Payload kinds a capture of this target would produce (from declared value types/kinds). */\n payloadKinds: readonly PayloadKind[];\n /** Declared targets writable on this target right now. */\n writable: readonly WriteTarget[];\n readOnly: boolean;\n /** True when any declared value here is secret/credential or non-exportable. */\n restricted: boolean;\n organizationId: string | null;\n auth: { authenticated: boolean; admin: boolean; creator: boolean };\n /**\n * Host-owned context a provider reads to act (the rich-document source, the\n * editable field's callbacks). Opaque to the package; never crosses into the\n * model. Providers that need it narrow it themselves.\n */\n host?: unknown;\n}\n\n","/**\n * Matrx Alchemy — Actions types (CONTRACT §2.4).\n *\n * One registry of everything a person can do to a thing. Providers plug in;\n * eligibility is computed from what is declared at the click target; duplicate\n * ids are refused; an action that does not apply is ABSENT (chair ruling R1).\n *\n * Framework-neutral: zero React, zero `@ai-matrx/agents`. Icons are string KEYS\n * resolved by the host's `IconResolverPort`; labels go through `I18nPort`.\n */\nimport type { Payload, TransferOutcome } from \"@ai-matrx/kit/content-transfer\";\nimport type { Json, LiveValues } from \"../declare/types\";\nimport type { AlchemyHostPorts } from \"../ports\";\nimport type { ClickTarget, PayloadKind } from \"./click-target\";\n\nexport type { ClickTarget, PayloadKind } from \"./click-target\";\n\n/** PayloadKind is the transfer Payload's kind union, kept equal at compile time. */\ntype Equal<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;\nconst payloadKindsAgree: Equal<PayloadKind, Payload[\"kind\"]> = true;\nvoid payloadKindsAgree;\n\nexport { UNIVERSAL_VERBS, type UniversalVerb } from \"./click-target\";\nimport type { UniversalVerb } from \"./click-target\";\n\n/**\n * Chair ruling R1: an action that does not apply or cannot run now is ABSENT.\n * Only the six universal verbs may answer \"unavailable-verb\": greyed in the\n * strip/bar, the sentence as tooltip. `requiresAuth` is NOT unavailability.\n */\nexport type Eligibility =\n | { status: \"absent\" }\n | { status: \"available\" }\n | { status: \"unavailable-verb\"; verb: UniversalVerb; sentence: string }\n /**\n * ABSENT OR HONEST (coordinator ruling 2026-09-27, admin pass): a row that cannot run here but\n * SAYS WHY (\"Unchanged from the pack\", \"Manifested surfaces are managed in code\") stays visible,\n * greyed, with its reason — the menu is the same everywhere, only availability changes. A row\n * with no reason is absent (the registry refuses an empty sentence).\n */\n | { status: \"unavailable\"; sentence: string };\n\n/** rich-document's ActionCategory, unchanged, plus the three the context menu groups by. */\nexport type ActionCategory =\n | \"feedback\"\n | \"copy\"\n | \"export\"\n | \"save\"\n | \"edit\"\n | \"share\"\n | \"creator\"\n | \"app\"\n | \"listen\"\n | \"study\"\n | \"ask\"\n | \"ai\"\n | \"admin\"\n | \"clipboard\"\n | \"history\"\n | \"surface-info\";\n\nexport const ACTION_CATEGORIES: readonly ActionCategory[] = [\n \"feedback\",\n \"copy\",\n \"export\",\n \"save\",\n \"edit\",\n \"share\",\n \"creator\",\n \"app\",\n \"listen\",\n \"study\",\n \"ask\",\n \"ai\",\n \"admin\",\n \"clipboard\",\n \"history\",\n \"surface-info\",\n];\n\n/**\n * An optional named section inside the action's group (a grid's cell / row /\n * column). `primary` marks the thing the person clicked: every layout renders\n * it first, inline, heading kept (context-menu-v3's primary section law).\n */\nexport interface ActionSection {\n id: string;\n label: string;\n labelKey?: string;\n icon?: string;\n primary?: boolean;\n /**\n * \"group\" (default): a heading over related rows — must be in the package's\n * APPROVED_HEADINGS (@ai-matrx/alchemy/menu). \"target\": the label of the\n * thing the person clicked, supplied at run time (\"Row · Widget A\").\n */\n kind?: \"group\" | \"target\";\n}\n\nexport interface Action {\n /** Globally unique. A duplicate is refused (never overwritten). */\n id: string;\n /** The provider that registered it — filled by the registry. */\n provider?: string;\n /** Resolved through I18nPort.t(labelKey ?? id, label). */\n label: string | ((target: ClickTarget) => string);\n labelKey?: string;\n /** Icon KEY resolved by IconResolverPort — the model stays framework-neutral. */\n icon?: string;\n /** Host styling hint for the glyph (rich-document iconColor). Renderers may ignore it. */\n iconTone?: string;\n /** Replaces `icon` while a state holds (a spinner while speaking). */\n stateIcon?(target: ClickTarget): { icon: string; spin?: boolean } | null;\n hint?: string;\n hintKey?: string;\n description?: string;\n category: ActionCategory;\n /** Which universal verb this clipboard action is (addressed by role in every layout). */\n verb?: UniversalVerb;\n order?: number;\n /** Bar layout slot. Default \"overflow\". */\n placement?: \"primary\" | \"overflow\" | \"both\";\n section?: ActionSection;\n /** A signed-out person still sees it; running goes through AuthResumePort (sign in, then resume). */\n requiresAuth?: boolean;\n /** Declared write targets this action lands through. Absent on a read-only target. */\n writes?: readonly string[];\n destructive?: boolean;\n /**\n * STARTS A NEW GROUP inside its section: the menu draws a divider above it (never as a section's\n * first row). A delete sits in its own group, last, never beside Duplicate (DATA-V2-BASICS-2).\n */\n startsGroup?: boolean;\n preserveSelection?: boolean;\n /**\n * Running it reloads rows of the menu it sits in (a \"Couldn't load. Retry\" row): the menu and its\n * open submenu stay open and show loading, then the rows or the error again. Every other run closes.\n */\n keepsMenuOpen?: boolean;\n /** Link rows navigate instead of running. */\n href?: string | ((target: ClickTarget) => string);\n eligible(target: ClickTarget): Eligibility;\n /** Toggle/pressed state: a pressed button or a checked row. */\n pressed?(target: ClickTarget): boolean;\n /** Present = the row is a checkbox (pressed is its state). */\n toggle?: boolean;\n subscribe?(onChange: () => void, target: ClickTarget): () => void;\n /**\n * The rows behind this submenu are still loading (an agent library's first\n * fetch). The row shows as loading — never absent, never silent — and its\n * `expand` resolves once they arrive.\n */\n pending?(target: ClickTarget): boolean;\n /** Submenus whose rows load on open (agent lists). */\n expand?(target: ClickTarget, signal: AbortSignal): Promise<readonly Action[]>;\n /** Shown centred when `expand` resolves empty. */\n emptyLabel?: string;\n run(target: ClickTarget, context: ActionRunContext): Promise<TransferOutcome | void> | TransferOutcome | void;\n}\n\n/** One removed read, recorded (kit content-transfer's omission shape). */\nexport interface ReadOmission {\n path: string;\n reason: \"excluded\" | \"filtered\";\n classification?: \"secret\" | \"credential\";\n}\n\n/**\n * PROJECTION BEFORE PROVIDERS. Providers never receive a raw read. Every read\n * they can make is projected first: secret and credential values, values\n * declared `exportable: false`, and values nobody declared are removed, with an\n * omission recorded. Raw reads never leave the package.\n */\nexport interface ProjectedReads {\n values(signal: AbortSignal): Promise<{ values: Record<string, Json>; omissions: readonly ReadOmission[] }>;\n item(signal: AbortSignal): Promise<{ values: Record<string, Json>; omissions: readonly ReadOmission[] } | null>;\n live(signal: AbortSignal): Promise<LiveValues>;\n}\n\n/**\n * What a running action receives. `door` (ALC-17) and `operate` (ALC-16) join\n * with their waves; until then those capabilities are absent (N8).\n */\nexport interface ActionRunContext {\n reads: ProjectedReads;\n ports: AlchemyHostPorts;\n signal: AbortSignal;\n}\n\nexport interface ActionProvider {\n id: string;\n /** T0 providers are known at mount; T1 providers load with the menu on first open. */\n tier: \"T0\" | \"T1\";\n /**\n * The ids this provider can ever yield, when known up front. Lets the\n * registry refuse a duplicate at registration instead of at first open.\n */\n declaredIds?(): readonly string[];\n actions(target: ClickTarget): readonly Action[] | Promise<readonly Action[]>;\n}\n\nexport interface ResolvedAction {\n action: Action;\n eligibility: Exclude<Eligibility, { status: \"absent\" }>;\n}\n\nexport interface ResolveRestriction {\n exclude?: readonly string[];\n categories?: readonly ActionCategory[];\n}\n\nexport interface ActionRegistry {\n /** Throws DuplicateActionError naming both providers; nothing is overwritten. */\n register(provider: ActionProvider): () => void;\n /** restrict: a host may remove ids or categories, never add ineligible ones. */\n resolve(target: ClickTarget, restrict?: ResolveRestriction): Promise<readonly ResolvedAction[]>;\n /** Registered provider ids, in registration order. */\n providers(): readonly string[];\n /** Change notification (a provider registered or unregistered). */\n subscribe(listener: () => void): () => void;\n}\n","/**\n * The one action registry (CONTRACT §2.4).\n *\n * - Duplicate ids are REFUSED, never overwritten (rich-document's registry\n * silently overwrote — R12). A duplicate known at registration throws; one\n * that only appears when a provider yields it is dropped and captured.\n * - Eligibility is one pure pass over the resolved click target, under\n * \"restrict, never relax\": a host may remove ids or categories, never add.\n * - R1: an action that does not apply is ABSENT. Only the six universal verbs\n * (category \"clipboard\") may answer `unavailable-verb`, with a sentence; any\n * other action answering it is a contract break → absent + diagnostics.\n */\nimport type { AlchemyHostPorts, Json } from \"../ports\";\nimport {\n UNIVERSAL_VERBS,\n type Action,\n type ActionProvider,\n type ActionRegistry,\n type ClickTarget,\n type Eligibility,\n type ResolveRestriction,\n type ResolvedAction,\n} from \"./types\";\n\nexport class DuplicateActionError extends Error {\n readonly actionId: string;\n readonly providers: readonly [string, string];\n constructor(actionId: string, first: string, second: string) {\n super(\n first === second\n ? `Action \"${actionId}\" is yielded twice by provider \"${first}\". Ids are unique; the second was refused.`\n : `Action \"${actionId}\" is registered by provider \"${first}\" and again by \"${second}\". Ids are unique; \"${second}\"'s copy was refused.`,\n );\n this.name = \"DuplicateActionError\";\n this.actionId = actionId;\n this.providers = [first, second];\n }\n}\n\nexport class DuplicateProviderError extends Error {\n readonly providerId: string;\n constructor(providerId: string) {\n super(`Action provider \"${providerId}\" is already registered. Unregister it first; nothing was overwritten.`);\n this.name = \"DuplicateProviderError\";\n this.providerId = providerId;\n }\n}\n\nexport interface ActionRegistryOptions {\n /** `diagnostics` is required (nothing fails silently); `auth` decides whether requiresAuth actions reach a signed-out person. */\n ports: Pick<AlchemyHostPorts, \"diagnostics\" | \"auth\">;\n}\n\nconst VERBS = new Set<string>(UNIVERSAL_VERBS);\n\nfunction capture(ports: ActionRegistryOptions[\"ports\"], error: unknown, detail: Json): void {\n try {\n ports.diagnostics.capture(error, { area: \"actions\", detail });\n } catch {\n // A broken diagnostics port must never take the menu down with it.\n }\n}\n\n/**\n * Eligibility of one action at one target — the ONE pure pass (CONTRACT §1.6).\n * Exported for providers' tests; hosts call `registry.resolve`.\n */\nexport function computeEligibility(\n action: Action,\n target: ClickTarget,\n options: { restrict?: ResolveRestriction; authResumable: boolean },\n): Eligibility | { status: \"contract-break\"; reason: string } {\n const restrict = options.restrict;\n if (target.excludedActionIds.has(action.id)) return { status: \"absent\" };\n if (restrict?.exclude?.includes(action.id)) return { status: \"absent\" };\n if (restrict?.categories && !restrict.categories.includes(action.category)) return { status: \"absent\" };\n if (action.writes && action.writes.length > 0) {\n // A read-only target offers nothing that would change the record.\n if (target.readOnly) return { status: \"absent\" };\n const writable = new Set(target.writable.map((w) => w.name));\n if (!action.writes.some((name) => writable.has(name))) return { status: \"absent\" };\n }\n if (action.requiresAuth && !target.auth.authenticated && !options.authResumable) {\n // Sign-in-then-resume is the capability; without the auth port it is absent (N8).\n return { status: \"absent\" };\n }\n const own = action.eligible(target);\n if (own.status === \"unavailable\") {\n // A greyed row must say why; without a sentence it is absent.\n return own.sentence.trim() ? own : { status: \"absent\" };\n }\n if (own.status !== \"unavailable-verb\") return own;\n if (action.category !== \"clipboard\" || !VERBS.has(own.verb)) {\n return {\n status: \"contract-break\",\n reason: `Action \"${action.id}\" answered unavailable-verb but only the six universal verbs (category \"clipboard\") may grey; it is absent instead.`,\n };\n }\n if (!own.sentence.trim()) {\n return {\n status: \"contract-break\",\n reason: `Universal verb \"${action.id}\" greyed without a sentence; a greyed verb must say why.`,\n };\n }\n return own;\n}\n\ninterface Entry {\n provider: ActionProvider;\n declared: readonly string[];\n}\n\nexport function createActionRegistry(options: ActionRegistryOptions): ActionRegistry {\n const ports = options.ports;\n const entries = new Map<string, Entry>();\n const listeners = new Set<() => void>();\n const notify = () => {\n for (const l of [...listeners]) l();\n };\n\n return {\n register(provider) {\n if (entries.has(provider.id)) throw new DuplicateProviderError(provider.id);\n const declared = provider.declaredIds?.() ?? [];\n const own = new Set<string>();\n for (const id of declared) {\n if (own.has(id)) throw new DuplicateActionError(id, provider.id, provider.id);\n own.add(id);\n for (const [otherId, other] of entries) {\n if (other.declared.includes(id)) throw new DuplicateActionError(id, otherId, provider.id);\n }\n }\n const entry: Entry = { provider, declared };\n entries.set(provider.id, entry);\n notify();\n return () => {\n if (entries.get(provider.id) === entry) {\n entries.delete(provider.id);\n notify();\n }\n };\n },\n\n async resolve(target, restrict) {\n const authResumable = Boolean(ports.auth);\n const seen = new Map<string, string>();\n const out: ResolvedAction[] = [];\n for (const [providerId, { provider }] of [...entries]) {\n let actions: readonly Action[];\n try {\n actions = await provider.actions(target);\n } catch (error) {\n capture(ports, error, { providerId, stage: \"actions\" });\n continue;\n }\n for (const raw of actions) {\n const first = seen.get(raw.id);\n if (first !== undefined) {\n capture(ports, new DuplicateActionError(raw.id, first, providerId), { actionId: raw.id });\n continue;\n }\n seen.set(raw.id, providerId);\n const action: Action = raw.provider === providerId ? raw : { ...raw, provider: providerId };\n let eligibility: ReturnType<typeof computeEligibility>;\n try {\n eligibility = computeEligibility(action, target, { restrict: restrict ?? {}, authResumable });\n } catch (error) {\n capture(ports, error, { actionId: action.id, stage: \"eligible\" });\n continue;\n }\n if (eligibility.status === \"contract-break\") {\n capture(ports, new Error(eligibility.reason), { actionId: action.id, stage: \"eligible\" });\n continue;\n }\n if (eligibility.status === \"absent\") continue;\n out.push({ action, eligibility });\n }\n }\n return out;\n },\n\n providers() {\n return [...entries.keys()];\n },\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n\n/** A provider over a fixed list; its ids are declared up front so duplicates fail at registration. */\nexport function staticActionProvider(\n id: string,\n actions: readonly Action[],\n tier: ActionProvider[\"tier\"] = \"T0\",\n): ActionProvider {\n const list = actions.map((a) => (a.provider === id ? a : { ...a, provider: id }));\n return {\n id,\n tier,\n declaredIds: () => list.map((a) => a.id),\n actions: () => list,\n };\n}\n\n/** Always-available eligibility, for actions with no rule of their own. */\nexport const alwaysEligible = (): Eligibility => ({ status: \"available\" });\n","/**\n * Sensitivity defaults and resolution (CONTRACT §2.1). Its own module so the\n * lightweight entries (`/actions`, the T0 React host) can project without\n * pulling the declaration registry.\n */\nimport type { DeclaredValue, Sensitivity } from \"./types\";\n\nexport const DEFAULT_SENSITIVITY: Sensitivity = Object.freeze({\n exportable: true,\n classification: \"ordinary\",\n includedByDefault: true,\n});\n\nexport function resolveSensitivity(value: Pick<DeclaredValue, \"sensitivity\">): Sensitivity {\n return {\n exportable: value.sensitivity?.exportable ?? DEFAULT_SENSITIVITY.exportable,\n classification: value.sensitivity?.classification ?? DEFAULT_SENSITIVITY.classification,\n includedByDefault: value.sensitivity?.includedByDefault ?? DEFAULT_SENSITIVITY.includedByDefault,\n };\n}\n","/**\n * PROJECTION BEFORE PROVIDERS (CONTRACT §2.4).\n *\n * The only place a raw read (`MountedSurface.readValues`,\n * `InternalResolvedItem.readValues`) is consumed on behalf of an action.\n * What leaves is projected: a value is kept only when it is DECLARED, its\n * classification is \"ordinary\" and it is exportable. Everything removed is\n * recorded as an omission, so the person and the agent can see what was held\n * back. No caller can relax this.\n */\nimport { resolveSensitivity } from \"../declare/sensitivity\";\nimport type { InternalResolvedItem, MountedSurface } from \"../declare/host\";\nimport type { DeclaredValue, Json, LiveValues, ResolvedSurfaceDeclaration } from \"../declare/types\";\nimport type { ProjectedReads, ReadOmission } from \"./types\";\n\nexport interface ProjectionSource {\n surface: MountedSurface | null;\n declaration: ResolvedSurfaceDeclaration | null;\n item: InternalResolvedItem | null;\n}\n\nfunction toJson(value: unknown): Json | undefined {\n if (value === undefined || typeof value === \"function\" || typeof value === \"symbol\") return undefined;\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n if (typeof value === \"number\") return Number.isFinite(value) ? value : null;\n if (typeof value === \"bigint\") return value.toString();\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return value.map((v) => toJson(v) ?? null);\n if (typeof value === \"object\") {\n const out: { [key: string]: Json } = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n const j = toJson(v);\n if (j !== undefined) out[k] = j;\n }\n return out;\n }\n return undefined;\n}\n\n/** Keep declared, ordinary, exportable values; record every removal. */\nexport function projectValues(\n raw: Record<string, unknown>,\n declared: readonly Pick<DeclaredValue, \"name\" | \"sensitivity\">[],\n pathPrefix = \"\",\n): { values: Record<string, Json>; omissions: ReadOmission[] } {\n const byName = new Map(declared.map((d) => [d.name, d]));\n const values: Record<string, Json> = {};\n const omissions: ReadOmission[] = [];\n for (const [name, value] of Object.entries(raw)) {\n const path = pathPrefix ? `${pathPrefix}.${name}` : name;\n const decl = byName.get(name);\n if (!decl) {\n omissions.push({ path, reason: \"filtered\" });\n continue;\n }\n const sensitivity = resolveSensitivity(decl);\n if (sensitivity.classification !== \"ordinary\") {\n omissions.push({ path, reason: \"excluded\", classification: sensitivity.classification });\n continue;\n }\n if (!sensitivity.exportable) {\n omissions.push({ path, reason: \"excluded\" });\n continue;\n }\n const json = toJson(value);\n if (json === undefined) continue;\n values[name] = json;\n }\n return { values, omissions };\n}\n\nexport function createProjectedReads(source: ProjectionSource): ProjectedReads {\n return {\n async values(signal) {\n if (!source.surface || !source.declaration) return { values: {}, omissions: [] };\n const raw = await source.surface.readValues(signal);\n const screenValues = source.declaration.values;\n return projectValues(raw, screenValues);\n },\n async item(signal) {\n const item = source.item;\n if (!item || !source.declaration) return null;\n const type = source.declaration.itemTypes?.find((t) => t.name === item.itemType);\n if (!type) return { values: {}, omissions: [{ path: item.itemType, reason: \"filtered\" }] };\n const raw = await item.readValues(signal);\n return projectValues(raw, type.values, item.itemType);\n },\n async live(signal): Promise<LiveValues> {\n if (!source.surface?.readLive) return {};\n return source.surface.readLive(signal);\n },\n };\n}\n","import type { QualifiedValueKey } from \"./types\";\n\n/** Every value, write-target, item-type and group name (the DB CHECK rule). */\nexport const DECLARATION_NAME_RE = /^[a-z][a-z0-9_]*$/;\n\n/** \"<client>/<local>\" — the surface naming convention. */\nexport const SURFACE_NAME_RE = /^[a-z][a-z0-9-]*\\/[a-z0-9-/]+$/;\n\n/** A bare screen value (`status`) or an item value (`table_row.status`). */\nexport const QUALIFIED_VALUE_KEY_RE = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)?$/;\n\nexport interface ParsedValueKey {\n /** \"\" for a screen-level value. */\n itemType: string;\n name: string;\n}\n\n/** Split a qualified key; null when it is not a valid bare or qualified key. */\nexport function parseQualifiedValueKey(key: string): ParsedValueKey | null {\n if (!QUALIFIED_VALUE_KEY_RE.test(key)) return null;\n const dot = key.indexOf(\".\");\n if (dot === -1) return { itemType: \"\", name: key };\n return { itemType: key.slice(0, dot), name: key.slice(dot + 1) };\n}\n\nexport function qualifyValueKey(itemType: string, name: string): QualifiedValueKey {\n return itemType ? `${itemType}.${name}` : name;\n}\n\n/** The client that owns a surface: its name prefix. */\nexport function surfaceClientOf(surfaceName: string): string {\n return surfaceName.split(\"/\")[0] ?? \"\";\n}\n","/**\n * Building a ClickTarget from what is declared at the click (CONTRACT §2.4).\n * Key existence, never value population: a value key is present when the\n * declaration gives it a read path here.\n */\nimport { resolveSensitivity } from \"../declare/sensitivity\";\nimport { qualifyValueKey } from \"../declare/keys\";\nimport type { ResolvedItem, ResolvedSurfaceDeclaration, WriteTarget } from \"../declare/types\";\nimport type { ClickTarget } from \"./types\";\n\nexport interface ClickTargetInput {\n surface?: ClickTarget[\"surface\"];\n declaration?: ResolvedSurfaceDeclaration | null;\n item?: ResolvedItem | null;\n level?: string | null;\n selection?: ClickTarget[\"selection\"];\n payloadKinds?: ClickTarget[\"payloadKinds\"];\n /** Defaults to the item's readOnly (or false). */\n readOnly?: boolean;\n /** Extra exclusions on top of the declaration's own. */\n excludedActionIds?: Iterable<string>;\n scopeChain?: readonly string[];\n organizationId?: string | null;\n auth?: Partial<ClickTarget[\"auth\"]>;\n /** Write targets the host can serve right now; defaults to every declared target for the screen/item. */\n writable?: readonly WriteTarget[];\n host?: unknown;\n}\n\nfunction domainOf(surfaceName: string): string {\n const slash = surfaceName.indexOf(\"/\");\n return slash > 0 ? surfaceName.slice(0, slash) : surfaceName;\n}\n\nexport function createClickTarget(input: ClickTargetInput = {}): ClickTarget {\n const declaration = input.declaration ?? null;\n const item = input.item ?? null;\n const valueKeys = new Set<string>();\n let restricted = false;\n const writable: WriteTarget[] = [];\n if (declaration) {\n for (const value of declaration.values) {\n valueKeys.add(value.name);\n const s = resolveSensitivity(value);\n if (s.classification !== \"ordinary\" || !s.exportable) restricted = true;\n }\n const itemType = item ? declaration.itemTypes?.find((t) => t.name === item.itemType) : undefined;\n if (itemType) {\n for (const value of itemType.values) {\n valueKeys.add(qualifyValueKey(itemType.name, value.name));\n const s = resolveSensitivity(value);\n if (s.classification !== \"ordinary\" || !s.exportable) restricted = true;\n }\n for (const t of itemType.writeTargets ?? []) writable.push(t);\n }\n for (const t of declaration.writeTargets ?? []) {\n if (!t.itemType || t.itemType === item?.itemType) writable.push(t);\n }\n }\n const readOnly = input.readOnly ?? item?.readOnly ?? false;\n const surfaceName = input.surface?.surfaceName ?? declaration?.surfaceName ?? null;\n const scopeChain = input.scopeChain ?? (surfaceName ? [\"global\", domainOf(surfaceName), surfaceName] : [\"global\"]);\n return {\n surface: input.surface ?? null,\n declaration,\n valueKeys,\n scopeChain,\n excludedActionIds: new Set(input.excludedActionIds ?? []),\n item,\n level: input.level ?? item?.level ?? null,\n selection: input.selection ?? null,\n payloadKinds: input.payloadKinds ?? [],\n writable: readOnly ? [] : (input.writable ?? writable),\n readOnly,\n restricted,\n organizationId: input.organizationId ?? null,\n auth: {\n authenticated: input.auth?.authenticated ?? false,\n admin: input.auth?.admin ?? false,\n creator: input.auth?.creator ?? false,\n },\n host: input.host,\n };\n}\n","/**\n * The one run path (T1e). Every layout runs an action through here, so the\n * sign-in-then-resume rule, projection and failure capture live once.\n */\nimport type { TransferOutcome } from \"@ai-matrx/kit/content-transfer\";\nimport type { AlchemyHostPorts } from \"../ports\";\nimport { createProjectedReads, type ProjectionSource } from \"./projection\";\nimport type { Action, ClickTarget } from \"./types\";\n\nexport interface RunActionOptions {\n ports: AlchemyHostPorts;\n /** Raw sources; projected before the action sees them. */\n source?: ProjectionSource;\n /** Stable fingerprint of the content, for sign-in-then-resume. */\n contentFingerprint?: string;\n signal?: AbortSignal;\n}\n\nexport type RunResult =\n | { status: \"ran\"; outcome: TransferOutcome | void }\n | { status: \"auth-pending\" }\n | { status: \"failed\"; error: unknown };\n\nexport async function runAction(action: Action, target: ClickTarget, options: RunActionOptions): Promise<RunResult> {\n const { ports } = options;\n if (action.requiresAuth && !target.auth.authenticated) {\n if (!ports.auth) {\n // Unreachable through resolve (the action is absent without the port); guard direct callers.\n ports.diagnostics.capture(new Error(`requiresAuth action \"${action.id}\" ran signed out with no auth port`), {\n area: \"actions\",\n detail: { actionId: action.id },\n });\n return { status: \"failed\", error: new Error(\"sign-in unavailable\") };\n }\n ports.auth.signInThenResume({ actionId: action.id, contentFingerprint: options.contentFingerprint ?? action.id });\n return { status: \"auth-pending\" };\n }\n const reads = createProjectedReads(options.source ?? { surface: null, declaration: target.declaration, item: null });\n const signal = options.signal ?? new AbortController().signal;\n try {\n const outcome = await action.run(target, { reads, ports, signal });\n return { status: \"ran\", outcome };\n } catch (error) {\n ports.diagnostics.capture(error, { area: \"actions\", detail: { actionId: action.id, stage: \"run\" } });\n const label = typeof action.label === \"string\" ? action.label : action.id;\n ports.notify?.error(`${label} did not finish.`, \"Try again; if it keeps failing, report it from the feedback button.\");\n return { status: \"failed\", error };\n }\n}\n"],"mappings":"AAOO,IAAM,gBAAkB,CAAC,OAAQ,MAAO,QAAS,OAAQ,OAAQ,MAAM,ECsDvE,IAAM,kBAA+C,CAC1D,WACA,OACA,SACA,OACA,OACA,QACA,UACA,MACA,SACA,QACA,MACA,KACA,QACA,YACA,UACA,cACF,ECtDO,IAAM,qBAAN,cAAmC,KAAM,CACrC,SACA,UACT,YAAY,SAAkB,MAAe,OAAgB,CAC3D,MACE,QAAU,OACN,WAAW,QAAQ,mCAAmC,KAAK,6CAC3D,WAAW,QAAQ,gCAAgC,KAAK,mBAAmB,MAAM,uBAAuB,MAAM,uBACpH,EACA,KAAK,KAAO,uBACZ,KAAK,SAAW,SAChB,KAAK,UAAY,CAAC,MAAO,MAAM,CACjC,CACF,EAEa,uBAAN,cAAqC,KAAM,CACvC,WACT,YAAY,WAAoB,CAC9B,MAAM,oBAAoB,UAAU,wEAAwE,EAC5G,KAAK,KAAO,yBACZ,KAAK,WAAa,UACpB,CACF,EAOM,MAAQ,IAAI,IAAY,eAAe,EAE7C,SAAS,QAAQ,MAAuC,MAAgB,OAAoB,CAC1F,GAAI,CACF,MAAM,YAAY,QAAQ,MAAO,CAAE,KAAM,UAAW,MAAO,CAAC,CAC9D,MAAQ,CAER,CACF,CAMO,SAAS,mBACd,OACA,OACA,QAC4D,CAC5D,IAAM,SAAW,QAAQ,SACzB,GAAI,OAAO,kBAAkB,IAAI,OAAO,EAAE,EAAG,MAAO,CAAE,OAAQ,QAAS,EACvE,GAAI,UAAU,SAAS,SAAS,OAAO,EAAE,EAAG,MAAO,CAAE,OAAQ,QAAS,EACtE,GAAI,UAAU,YAAc,CAAC,SAAS,WAAW,SAAS,OAAO,QAAQ,EAAG,MAAO,CAAE,OAAQ,QAAS,EACtG,GAAI,OAAO,QAAU,OAAO,OAAO,OAAS,EAAG,CAE7C,GAAI,OAAO,SAAU,MAAO,CAAE,OAAQ,QAAS,EAC/C,IAAM,SAAW,IAAI,IAAI,OAAO,SAAS,IAAK,GAAM,EAAE,IAAI,CAAC,EAC3D,GAAI,CAAC,OAAO,OAAO,KAAM,MAAS,SAAS,IAAI,IAAI,CAAC,EAAG,MAAO,CAAE,OAAQ,QAAS,CACnF,CACA,GAAI,OAAO,cAAgB,CAAC,OAAO,KAAK,eAAiB,CAAC,QAAQ,cAEhE,MAAO,CAAE,OAAQ,QAAS,EAE5B,IAAM,IAAM,OAAO,SAAS,MAAM,EAClC,OAAI,IAAI,SAAW,cAEV,IAAI,SAAS,KAAK,EAAI,IAAM,CAAE,OAAQ,QAAS,EAEpD,IAAI,SAAW,mBAA2B,IAC1C,OAAO,WAAa,aAAe,CAAC,MAAM,IAAI,IAAI,IAAI,EACjD,CACL,OAAQ,iBACR,OAAQ,WAAW,OAAO,EAAE,qHAC9B,EAEG,IAAI,SAAS,KAAK,EAMhB,IALE,CACL,OAAQ,iBACR,OAAQ,mBAAmB,OAAO,EAAE,0DACtC,CAGJ,CAOO,SAAS,qBAAqB,QAAgD,CACnF,IAAM,MAAQ,QAAQ,MAChB,QAAU,IAAI,IACd,UAAY,IAAI,IAChB,OAAS,IAAM,CACnB,QAAW,IAAK,CAAC,GAAG,SAAS,EAAG,EAAE,CACpC,EAEA,MAAO,CACL,SAAS,SAAU,CACjB,GAAI,QAAQ,IAAI,SAAS,EAAE,EAAG,MAAM,IAAI,uBAAuB,SAAS,EAAE,EAC1E,IAAM,SAAW,SAAS,cAAc,GAAK,CAAC,EACxC,IAAM,IAAI,IAChB,QAAW,MAAM,SAAU,CACzB,GAAI,IAAI,IAAI,EAAE,EAAG,MAAM,IAAI,qBAAqB,GAAI,SAAS,GAAI,SAAS,EAAE,EAC5E,IAAI,IAAI,EAAE,EACV,OAAW,CAAC,QAAS,KAAK,IAAK,QAC7B,GAAI,MAAM,SAAS,SAAS,EAAE,EAAG,MAAM,IAAI,qBAAqB,GAAI,QAAS,SAAS,EAAE,CAE5F,CACA,IAAM,MAAe,CAAE,SAAU,QAAS,EAC1C,eAAQ,IAAI,SAAS,GAAI,KAAK,EAC9B,OAAO,EACA,IAAM,CACP,QAAQ,IAAI,SAAS,EAAE,IAAM,QAC/B,QAAQ,OAAO,SAAS,EAAE,EAC1B,OAAO,EAEX,CACF,EAEA,MAAM,QAAQ,OAAQ,SAAU,CAC9B,IAAM,cAAgB,EAAQ,MAAM,KAC9B,KAAO,IAAI,IACX,IAAwB,CAAC,EAC/B,OAAW,CAAC,WAAY,CAAE,QAAS,CAAC,GAAK,CAAC,GAAG,OAAO,EAAG,CACrD,IAAI,QACJ,GAAI,CACF,QAAU,MAAM,SAAS,QAAQ,MAAM,CACzC,OAAS,MAAO,CACd,QAAQ,MAAO,MAAO,CAAE,WAAY,MAAO,SAAU,CAAC,EACtD,QACF,CACA,QAAW,OAAO,QAAS,CACzB,IAAM,MAAQ,KAAK,IAAI,IAAI,EAAE,EAC7B,GAAI,QAAU,OAAW,CACvB,QAAQ,MAAO,IAAI,qBAAqB,IAAI,GAAI,MAAO,UAAU,EAAG,CAAE,SAAU,IAAI,EAAG,CAAC,EACxF,QACF,CACA,KAAK,IAAI,IAAI,GAAI,UAAU,EAC3B,IAAM,OAAiB,IAAI,WAAa,WAAa,IAAM,CAAE,GAAG,IAAK,SAAU,UAAW,EACtF,YACJ,GAAI,CACF,YAAc,mBAAmB,OAAQ,OAAQ,CAAE,SAAU,UAAY,CAAC,EAAG,aAAc,CAAC,CAC9F,OAAS,MAAO,CACd,QAAQ,MAAO,MAAO,CAAE,SAAU,OAAO,GAAI,MAAO,UAAW,CAAC,EAChE,QACF,CACA,GAAI,YAAY,SAAW,iBAAkB,CAC3C,QAAQ,MAAO,IAAI,MAAM,YAAY,MAAM,EAAG,CAAE,SAAU,OAAO,GAAI,MAAO,UAAW,CAAC,EACxF,QACF,CACI,YAAY,SAAW,UAC3B,IAAI,KAAK,CAAE,OAAQ,WAAY,CAAC,CAClC,CACF,CACA,OAAO,GACT,EAEA,WAAY,CACV,MAAO,CAAC,GAAG,QAAQ,KAAK,CAAC,CAC3B,EAEA,UAAU,SAAU,CAClB,iBAAU,IAAI,QAAQ,EACf,IAAM,CACX,UAAU,OAAO,QAAQ,CAC3B,CACF,CACF,CACF,CAGO,SAAS,qBACd,GACA,QACA,KAA+B,KACf,CAChB,IAAM,KAAO,QAAQ,IAAK,GAAO,EAAE,WAAa,GAAK,EAAI,CAAE,GAAG,EAAG,SAAU,EAAG,CAAE,EAChF,MAAO,CACL,GACA,KACA,YAAa,IAAM,KAAK,IAAK,GAAM,EAAE,EAAE,EACvC,QAAS,IAAM,IACjB,CACF,CAGO,IAAM,eAAiB,KAAoB,CAAE,OAAQ,WAAY,GC3MjE,IAAM,oBAAmC,OAAO,OAAO,CAC5D,WAAY,GACZ,eAAgB,WAChB,kBAAmB,EACrB,CAAC,EAEM,SAAS,mBAAmB,MAAwD,CACzF,MAAO,CACL,WAAY,MAAM,aAAa,YAAc,oBAAoB,WACjE,eAAgB,MAAM,aAAa,gBAAkB,oBAAoB,eACzE,kBAAmB,MAAM,aAAa,mBAAqB,oBAAoB,iBACjF,CACF,CCEA,SAAS,OAAO,MAAkC,CAChD,GAAI,UAAU,QAAa,OAAO,OAAU,YAAc,OAAO,OAAU,UAC3E,IAAI,QAAU,MAAQ,OAAO,OAAU,UAAY,OAAO,OAAU,UAAW,OAAO,MACtF,GAAI,OAAO,OAAU,SAAU,OAAO,OAAO,SAAS,KAAK,EAAI,MAAQ,KACvE,GAAI,OAAO,OAAU,SAAU,OAAO,MAAM,SAAS,EACrD,GAAI,iBAAiB,KAAM,OAAO,MAAM,YAAY,EACpD,GAAI,MAAM,QAAQ,KAAK,EAAG,OAAO,MAAM,IAAK,GAAM,OAAO,CAAC,GAAK,IAAI,EACnE,GAAI,OAAO,OAAU,SAAU,CAC7B,IAAM,IAA+B,CAAC,EACtC,OAAW,CAAC,EAAG,CAAC,IAAK,OAAO,QAAQ,KAAgC,EAAG,CACrE,IAAM,EAAI,OAAO,CAAC,EACd,IAAM,SAAW,IAAI,CAAC,EAAI,EAChC,CACA,OAAO,GACT,EAEF,CAGO,SAAS,cACd,IACA,SACA,WAAa,GACgD,CAC7D,IAAM,OAAS,IAAI,IAAI,SAAS,IAAK,GAAM,CAAC,EAAE,KAAM,CAAC,CAAC,CAAC,EACjD,OAA+B,CAAC,EAChC,UAA4B,CAAC,EACnC,OAAW,CAAC,KAAM,KAAK,IAAK,OAAO,QAAQ,GAAG,EAAG,CAC/C,IAAM,KAAO,WAAa,GAAG,UAAU,IAAI,IAAI,GAAK,KAC9C,KAAO,OAAO,IAAI,IAAI,EAC5B,GAAI,CAAC,KAAM,CACT,UAAU,KAAK,CAAE,KAAM,OAAQ,UAAW,CAAC,EAC3C,QACF,CACA,IAAM,YAAc,mBAAmB,IAAI,EAC3C,GAAI,YAAY,iBAAmB,WAAY,CAC7C,UAAU,KAAK,CAAE,KAAM,OAAQ,WAAY,eAAgB,YAAY,cAAe,CAAC,EACvF,QACF,CACA,GAAI,CAAC,YAAY,WAAY,CAC3B,UAAU,KAAK,CAAE,KAAM,OAAQ,UAAW,CAAC,EAC3C,QACF,CACA,IAAM,KAAO,OAAO,KAAK,EACrB,OAAS,SACb,OAAO,IAAI,EAAI,KACjB,CACA,MAAO,CAAE,OAAQ,SAAU,CAC7B,CAEO,SAAS,qBAAqB,OAA0C,CAC7E,MAAO,CACL,MAAM,OAAO,OAAQ,CACnB,GAAI,CAAC,OAAO,SAAW,CAAC,OAAO,YAAa,MAAO,CAAE,OAAQ,CAAC,EAAG,UAAW,CAAC,CAAE,EAC/E,IAAM,IAAM,MAAM,OAAO,QAAQ,WAAW,MAAM,EAC5C,aAAe,OAAO,YAAY,OACxC,OAAO,cAAc,IAAK,YAAY,CACxC,EACA,MAAM,KAAK,OAAQ,CACjB,IAAM,KAAO,OAAO,KACpB,GAAI,CAAC,MAAQ,CAAC,OAAO,YAAa,OAAO,KACzC,IAAM,KAAO,OAAO,YAAY,WAAW,KAAM,GAAM,EAAE,OAAS,KAAK,QAAQ,EAC/E,GAAI,CAAC,KAAM,MAAO,CAAE,OAAQ,CAAC,EAAG,UAAW,CAAC,CAAE,KAAM,KAAK,SAAU,OAAQ,UAAW,CAAC,CAAE,EACzF,IAAM,IAAM,MAAM,KAAK,WAAW,MAAM,EACxC,OAAO,cAAc,IAAK,KAAK,OAAQ,KAAK,QAAQ,CACtD,EACA,MAAM,KAAK,OAA6B,CACtC,OAAK,OAAO,SAAS,SACd,OAAO,QAAQ,SAAS,MAAM,EADC,CAAC,CAEzC,CACF,CACF,CCnEO,SAAS,gBAAgB,SAAkB,KAAiC,CACjF,OAAO,SAAW,GAAG,QAAQ,IAAI,IAAI,GAAK,IAC5C,CCEA,SAAS,SAAS,YAA6B,CAC7C,IAAM,MAAQ,YAAY,QAAQ,GAAG,EACrC,OAAO,MAAQ,EAAI,YAAY,MAAM,EAAG,KAAK,EAAI,WACnD,CAEO,SAAS,kBAAkB,MAA0B,CAAC,EAAgB,CAC3E,IAAM,YAAc,MAAM,aAAe,KACnC,KAAO,MAAM,MAAQ,KACrB,UAAY,IAAI,IAClB,WAAa,GACX,SAA0B,CAAC,EACjC,GAAI,YAAa,CACf,QAAW,SAAS,YAAY,OAAQ,CACtC,UAAU,IAAI,MAAM,IAAI,EACxB,IAAM,EAAI,mBAAmB,KAAK,GAC9B,EAAE,iBAAmB,YAAc,CAAC,EAAE,cAAY,WAAa,GACrE,CACA,IAAM,SAAW,KAAO,YAAY,WAAW,KAAM,GAAM,EAAE,OAAS,KAAK,QAAQ,EAAI,OACvF,GAAI,SAAU,CACZ,QAAW,SAAS,SAAS,OAAQ,CACnC,UAAU,IAAI,gBAAgB,SAAS,KAAM,MAAM,IAAI,CAAC,EACxD,IAAM,EAAI,mBAAmB,KAAK,GAC9B,EAAE,iBAAmB,YAAc,CAAC,EAAE,cAAY,WAAa,GACrE,CACA,QAAW,KAAK,SAAS,cAAgB,CAAC,EAAG,SAAS,KAAK,CAAC,CAC9D,CACA,QAAW,KAAK,YAAY,cAAgB,CAAC,GACvC,CAAC,EAAE,UAAY,EAAE,WAAa,MAAM,WAAU,SAAS,KAAK,CAAC,CAErE,CACA,IAAM,SAAW,MAAM,UAAY,MAAM,UAAY,GAC/C,YAAc,MAAM,SAAS,aAAe,aAAa,aAAe,KACxE,WAAa,MAAM,aAAe,YAAc,CAAC,SAAU,SAAS,WAAW,EAAG,WAAW,EAAI,CAAC,QAAQ,GAChH,MAAO,CACL,QAAS,MAAM,SAAW,KAC1B,YACA,UACA,WACA,kBAAmB,IAAI,IAAI,MAAM,mBAAqB,CAAC,CAAC,EACxD,KACA,MAAO,MAAM,OAAS,MAAM,OAAS,KACrC,UAAW,MAAM,WAAa,KAC9B,aAAc,MAAM,cAAgB,CAAC,EACrC,SAAU,SAAW,CAAC,EAAK,MAAM,UAAY,SAC7C,SACA,WACA,eAAgB,MAAM,gBAAkB,KACxC,KAAM,CACJ,cAAe,MAAM,MAAM,eAAiB,GAC5C,MAAO,MAAM,MAAM,OAAS,GAC5B,QAAS,MAAM,MAAM,SAAW,EAClC,EACA,KAAM,MAAM,IACd,CACF,CC5DA,eAAsB,UAAU,OAAgB,OAAqB,QAA+C,CAClH,GAAM,CAAE,KAAM,EAAI,QAClB,GAAI,OAAO,cAAgB,CAAC,OAAO,KAAK,cACtC,OAAK,MAAM,MAQX,MAAM,KAAK,iBAAiB,CAAE,SAAU,OAAO,GAAI,mBAAoB,QAAQ,oBAAsB,OAAO,EAAG,CAAC,EACzG,CAAE,OAAQ,cAAe,IAP9B,MAAM,YAAY,QAAQ,IAAI,MAAM,wBAAwB,OAAO,EAAE,oCAAoC,EAAG,CAC1G,KAAM,UACN,OAAQ,CAAE,SAAU,OAAO,EAAG,CAChC,CAAC,EACM,CAAE,OAAQ,SAAU,MAAO,IAAI,MAAM,qBAAqB,CAAE,GAKvE,IAAM,MAAQ,qBAAqB,QAAQ,QAAU,CAAE,QAAS,KAAM,YAAa,OAAO,YAAa,KAAM,IAAK,CAAC,EAC7G,OAAS,QAAQ,QAAU,IAAI,gBAAgB,EAAE,OACvD,GAAI,CAEF,MAAO,CAAE,OAAQ,MAAO,QADR,MAAM,OAAO,IAAI,OAAQ,CAAE,MAAO,MAAO,MAAO,CAAC,CACjC,CAClC,OAAS,MAAO,CACd,MAAM,YAAY,QAAQ,MAAO,CAAE,KAAM,UAAW,OAAQ,CAAE,SAAU,OAAO,GAAI,MAAO,KAAM,CAAE,CAAC,EACnG,IAAM,MAAQ,OAAO,OAAO,OAAU,SAAW,OAAO,MAAQ,OAAO,GACvE,aAAM,QAAQ,MAAM,GAAG,KAAK,mBAAoB,qEAAqE,EAC9G,CAAE,OAAQ,SAAU,KAAM,CACnC,CACF","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/actions/click-target.ts","../src/actions/types.ts","../src/actions/registry.ts","../src/declare/sensitivity.ts","../src/actions/projection.ts","../src/declare/keys.ts","../src/actions/target.ts","../src/actions/run.ts","../src/declare/registry.ts","../src/actions/declarations.ts","../src/actions/surface-run.ts"],"sourcesContent":["/**\n * The click target (CONTRACT §2.4) in its own module: `/ports` references it,\n * and `/ports` must stay free of every other package (types only).\n */\nimport type { QualifiedValueKey, ResolvedItem, ResolvedSurfaceDeclaration, WriteTarget } from \"../declare/types\";\n\n/** The six universal verbs — the ONLY rows that may grey (R1 c). */\nexport const UNIVERSAL_VERBS = [\"copy\", \"cut\", \"paste\", \"undo\", \"redo\", \"find\"] as const;\nexport type UniversalVerb = (typeof UNIVERSAL_VERBS)[number];\n\n/** The transfer Payload's kinds (`actions/types.ts` asserts equality at compile time). */\nexport type PayloadKind = \"text\" | \"markdown\" | \"json\" | \"rows\" | \"registered\";\n\n/** What eligibility is computed from: everything declared at the click target. */\nexport interface ClickTarget {\n surface: { instanceId: string; surfaceName: string } | null;\n /** The resolved declaration (inheritance applied). Eligibility decides by KEY existence over it. */\n declaration: ResolvedSurfaceDeclaration | null;\n /** Declared value keys with a read path here (screen names + qualified item keys). Key existence, not population. */\n valueKeys: ReadonlySet<QualifiedValueKey>;\n /** Scope chain, most general first: [\"global\", \"<domain>\", \"<surfaceName>\"]. */\n scopeChain: readonly string[];\n /** The surface's explicit exclusions (the one override). */\n excludedActionIds: ReadonlySet<string>;\n item: ResolvedItem | null;\n level: string | null;\n /** Offsets + the live range handle, editable or not. */\n selection: {\n text: string;\n type: \"editable\" | \"non-editable\";\n start: number;\n end: number;\n /** Opaque host handle (DOM Range / element) used to restore or stream into the selection. */\n handle?: unknown;\n } | null;\n /** Payload kinds a capture of this target would produce (from declared value types/kinds). */\n payloadKinds: readonly PayloadKind[];\n /** Declared targets writable on this target right now. */\n writable: readonly WriteTarget[];\n readOnly: boolean;\n /** True when any declared value here is secret/credential or non-exportable. */\n restricted: boolean;\n organizationId: string | null;\n auth: { authenticated: boolean; admin: boolean; creator: boolean };\n /**\n * Host-owned context a provider reads to act (the rich-document source, the\n * editable field's callbacks). Opaque to the package; never crosses into the\n * model. Providers that need it narrow it themselves.\n */\n host?: unknown;\n}\n\n","/**\n * Matrx Alchemy — Actions types (CONTRACT §2.4).\n *\n * One registry of everything a person can do to a thing. Providers plug in;\n * eligibility is computed from what is declared at the click target; duplicate\n * ids are refused; an action that does not apply is ABSENT (chair ruling R1).\n *\n * Framework-neutral: zero React, zero `@ai-matrx/agents`. Icons are string KEYS\n * resolved by the host's `IconResolverPort`; labels go through `I18nPort`.\n */\nimport type { Payload, TransferOutcome } from \"@ai-matrx/kit/content-transfer\";\nimport type { Json, LiveValues } from \"../declare/types\";\nimport type { AlchemyHostPorts } from \"../ports\";\nimport type { ClickTarget, PayloadKind } from \"./click-target\";\n\nexport type { ClickTarget, PayloadKind } from \"./click-target\";\n\n/** PayloadKind is the transfer Payload's kind union, kept equal at compile time. */\ntype Equal<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;\nconst payloadKindsAgree: Equal<PayloadKind, Payload[\"kind\"]> = true;\nvoid payloadKindsAgree;\n\nexport { UNIVERSAL_VERBS, type UniversalVerb } from \"./click-target\";\nimport type { UniversalVerb } from \"./click-target\";\n\n/**\n * Chair ruling R1: an action that does not apply or cannot run now is ABSENT.\n * Only the six universal verbs may answer \"unavailable-verb\": greyed in the\n * strip/bar, the sentence as tooltip. `requiresAuth` is NOT unavailability.\n */\nexport type Eligibility =\n | { status: \"absent\" }\n | { status: \"available\" }\n | { status: \"unavailable-verb\"; verb: UniversalVerb; sentence: string }\n /**\n * ABSENT OR HONEST (coordinator ruling 2026-09-27, admin pass): a row that cannot run here but\n * SAYS WHY (\"Unchanged from the pack\", \"Manifested surfaces are managed in code\") stays visible,\n * greyed, with its reason — the menu is the same everywhere, only availability changes. A row\n * with no reason is absent (the registry refuses an empty sentence).\n */\n | { status: \"unavailable\"; sentence: string };\n\n/** rich-document's ActionCategory, unchanged, plus the three the context menu groups by, plus \"applet\" (surface Actions). */\nexport type ActionCategory =\n | \"feedback\"\n | \"copy\"\n | \"export\"\n | \"save\"\n | \"edit\"\n | \"share\"\n | \"creator\"\n | \"app\"\n | \"listen\"\n | \"study\"\n | \"ask\"\n | \"ai\"\n | \"admin\"\n | \"clipboard\"\n | \"history\"\n | \"surface-info\"\n /** Surface Actions (Applets CONTRACTS §6): the default category of an `ActionDeclaration`. */\n | \"applet\";\n\nexport const ACTION_CATEGORIES: readonly ActionCategory[] = [\n \"feedback\",\n \"copy\",\n \"export\",\n \"save\",\n \"edit\",\n \"share\",\n \"creator\",\n \"app\",\n \"listen\",\n \"study\",\n \"ask\",\n \"ai\",\n \"admin\",\n \"clipboard\",\n \"history\",\n \"surface-info\",\n \"applet\",\n];\n\n/**\n * An optional named section inside the action's group (a grid's cell / row /\n * column). `primary` marks the thing the person clicked: every layout renders\n * it first, inline, heading kept (context-menu-v3's primary section law).\n */\nexport interface ActionSection {\n id: string;\n label: string;\n labelKey?: string;\n icon?: string;\n primary?: boolean;\n /**\n * \"group\" (default): a heading over related rows — must be in the package's\n * APPROVED_HEADINGS (@ai-matrx/alchemy/menu). \"target\": the label of the\n * thing the person clicked, supplied at run time (\"Row · Widget A\").\n */\n kind?: \"group\" | \"target\";\n}\n\nexport interface Action {\n /** Globally unique. A duplicate is refused (never overwritten). */\n id: string;\n /** The provider that registered it — filled by the registry. */\n provider?: string;\n /** Resolved through I18nPort.t(labelKey ?? id, label). */\n label: string | ((target: ClickTarget) => string);\n labelKey?: string;\n /** Icon KEY resolved by IconResolverPort — the model stays framework-neutral. */\n icon?: string;\n /** Host styling hint for the glyph (rich-document iconColor). Renderers may ignore it. */\n iconTone?: string;\n /** Replaces `icon` while a state holds (a spinner while speaking). */\n stateIcon?(target: ClickTarget): { icon: string; spin?: boolean } | null;\n hint?: string;\n hintKey?: string;\n description?: string;\n category: ActionCategory;\n /** Which universal verb this clipboard action is (addressed by role in every layout). */\n verb?: UniversalVerb;\n order?: number;\n /** Bar layout slot. Default \"overflow\". */\n placement?: \"primary\" | \"overflow\" | \"both\";\n section?: ActionSection;\n /** A signed-out person still sees it; running goes through AuthResumePort (sign in, then resume). */\n requiresAuth?: boolean;\n /** Declared write targets this action lands through. Absent on a read-only target. */\n writes?: readonly string[];\n destructive?: boolean;\n /**\n * STARTS A NEW GROUP inside its section: the menu draws a divider above it (never as a section's\n * first row). A delete sits in its own group, last, never beside Duplicate (DATA-V2-BASICS-2).\n */\n startsGroup?: boolean;\n preserveSelection?: boolean;\n /**\n * Running it reloads rows of the menu it sits in (a \"Couldn't load. Retry\" row): the menu and its\n * open submenu stay open and show loading, then the rows or the error again. Every other run closes.\n */\n keepsMenuOpen?: boolean;\n /** Link rows navigate instead of running. */\n href?: string | ((target: ClickTarget) => string);\n eligible(target: ClickTarget): Eligibility;\n /** Toggle/pressed state: a pressed button or a checked row. */\n pressed?(target: ClickTarget): boolean;\n /** Present = the row is a checkbox (pressed is its state). */\n toggle?: boolean;\n subscribe?(onChange: () => void, target: ClickTarget): () => void;\n /**\n * The rows behind this submenu are still loading (an agent library's first\n * fetch). The row shows as loading — never absent, never silent — and its\n * `expand` resolves once they arrive.\n */\n pending?(target: ClickTarget): boolean;\n /** Submenus whose rows load on open (agent lists). */\n expand?(target: ClickTarget, signal: AbortSignal): Promise<readonly Action[]>;\n /** Shown centred when `expand` resolves empty. */\n emptyLabel?: string;\n run(target: ClickTarget, context: ActionRunContext): Promise<TransferOutcome | void> | TransferOutcome | void;\n}\n\n/** One removed read, recorded (kit content-transfer's omission shape). */\nexport interface ReadOmission {\n path: string;\n reason: \"excluded\" | \"filtered\";\n classification?: \"secret\" | \"credential\";\n}\n\n/**\n * PROJECTION BEFORE PROVIDERS. Providers never receive a raw read. Every read\n * they can make is projected first: secret and credential values, values\n * declared `exportable: false`, and values nobody declared are removed, with an\n * omission recorded. Raw reads never leave the package.\n */\nexport interface ProjectedReads {\n values(signal: AbortSignal): Promise<{ values: Record<string, Json>; omissions: readonly ReadOmission[] }>;\n item(signal: AbortSignal): Promise<{ values: Record<string, Json>; omissions: readonly ReadOmission[] } | null>;\n live(signal: AbortSignal): Promise<LiveValues>;\n}\n\n/**\n * What a running action receives. `door` (ALC-17) and `operate` (ALC-16) join\n * with their waves; until then those capabilities are absent (N8).\n */\nexport interface ActionRunContext {\n reads: ProjectedReads;\n ports: AlchemyHostPorts;\n signal: AbortSignal;\n}\n\nexport interface ActionProvider {\n id: string;\n /** T0 providers are known at mount; T1 providers load with the menu on first open. */\n tier: \"T0\" | \"T1\";\n /**\n * The ids this provider can ever yield, when known up front. Lets the\n * registry refuse a duplicate at registration instead of at first open.\n */\n declaredIds?(): readonly string[];\n actions(target: ClickTarget): readonly Action[] | Promise<readonly Action[]>;\n}\n\nexport interface ResolvedAction {\n action: Action;\n eligibility: Exclude<Eligibility, { status: \"absent\" }>;\n}\n\nexport interface ResolveRestriction {\n exclude?: readonly string[];\n categories?: readonly ActionCategory[];\n}\n\nexport interface ActionRegistry {\n /** Throws DuplicateActionError naming both providers; nothing is overwritten. */\n register(provider: ActionProvider): () => void;\n /** restrict: a host may remove ids or categories, never add ineligible ones. */\n resolve(target: ClickTarget, restrict?: ResolveRestriction): Promise<readonly ResolvedAction[]>;\n /** Registered provider ids, in registration order. */\n providers(): readonly string[];\n /** Change notification (a provider registered or unregistered). */\n subscribe(listener: () => void): () => void;\n}\n","/**\n * The one action registry (CONTRACT §2.4).\n *\n * - Duplicate ids are REFUSED, never overwritten (rich-document's registry\n * silently overwrote — R12). A duplicate known at registration throws; one\n * that only appears when a provider yields it is dropped and captured.\n * - Eligibility is one pure pass over the resolved click target, under\n * \"restrict, never relax\": a host may remove ids or categories, never add.\n * - R1: an action that does not apply is ABSENT. Only the six universal verbs\n * (category \"clipboard\") may answer `unavailable-verb`, with a sentence; any\n * other action answering it is a contract break → absent + diagnostics.\n */\nimport type { AlchemyHostPorts, Json } from \"../ports\";\nimport {\n UNIVERSAL_VERBS,\n type Action,\n type ActionProvider,\n type ActionRegistry,\n type ClickTarget,\n type Eligibility,\n type ResolveRestriction,\n type ResolvedAction,\n} from \"./types\";\n\nexport class DuplicateActionError extends Error {\n readonly actionId: string;\n readonly providers: readonly [string, string];\n constructor(actionId: string, first: string, second: string) {\n super(\n first === second\n ? `Action \"${actionId}\" is yielded twice by provider \"${first}\". Ids are unique; the second was refused.`\n : `Action \"${actionId}\" is registered by provider \"${first}\" and again by \"${second}\". Ids are unique; \"${second}\"'s copy was refused.`,\n );\n this.name = \"DuplicateActionError\";\n this.actionId = actionId;\n this.providers = [first, second];\n }\n}\n\nexport class DuplicateProviderError extends Error {\n readonly providerId: string;\n constructor(providerId: string) {\n super(`Action provider \"${providerId}\" is already registered. Unregister it first; nothing was overwritten.`);\n this.name = \"DuplicateProviderError\";\n this.providerId = providerId;\n }\n}\n\nexport interface ActionRegistryOptions {\n /** `diagnostics` is required (nothing fails silently); `auth` decides whether requiresAuth actions reach a signed-out person. */\n ports: Pick<AlchemyHostPorts, \"diagnostics\" | \"auth\">;\n}\n\nconst VERBS = new Set<string>(UNIVERSAL_VERBS);\n\nfunction capture(ports: ActionRegistryOptions[\"ports\"], error: unknown, detail: Json): void {\n try {\n ports.diagnostics.capture(error, { area: \"actions\", detail });\n } catch {\n // A broken diagnostics port must never take the menu down with it.\n }\n}\n\n/**\n * Eligibility of one action at one target — the ONE pure pass (CONTRACT §1.6).\n * Exported for providers' tests; hosts call `registry.resolve`.\n */\nexport function computeEligibility(\n action: Action,\n target: ClickTarget,\n options: { restrict?: ResolveRestriction; authResumable: boolean },\n): Eligibility | { status: \"contract-break\"; reason: string } {\n const restrict = options.restrict;\n if (target.excludedActionIds.has(action.id)) return { status: \"absent\" };\n if (restrict?.exclude?.includes(action.id)) return { status: \"absent\" };\n if (restrict?.categories && !restrict.categories.includes(action.category)) return { status: \"absent\" };\n if (action.writes && action.writes.length > 0) {\n // A read-only target offers nothing that would change the record.\n if (target.readOnly) return { status: \"absent\" };\n const writable = new Set(target.writable.map((w) => w.name));\n if (!action.writes.some((name) => writable.has(name))) return { status: \"absent\" };\n }\n if (action.requiresAuth && !target.auth.authenticated && !options.authResumable) {\n // Sign-in-then-resume is the capability; without the auth port it is absent (N8).\n return { status: \"absent\" };\n }\n const own = action.eligible(target);\n if (own.status === \"unavailable\") {\n // A greyed row must say why; without a sentence it is absent.\n return own.sentence.trim() ? own : { status: \"absent\" };\n }\n if (own.status !== \"unavailable-verb\") return own;\n if (action.category !== \"clipboard\" || !VERBS.has(own.verb)) {\n return {\n status: \"contract-break\",\n reason: `Action \"${action.id}\" answered unavailable-verb but only the six universal verbs (category \"clipboard\") may grey; it is absent instead.`,\n };\n }\n if (!own.sentence.trim()) {\n return {\n status: \"contract-break\",\n reason: `Universal verb \"${action.id}\" greyed without a sentence; a greyed verb must say why.`,\n };\n }\n return own;\n}\n\ninterface Entry {\n provider: ActionProvider;\n declared: readonly string[];\n}\n\nexport function createActionRegistry(options: ActionRegistryOptions): ActionRegistry {\n const ports = options.ports;\n const entries = new Map<string, Entry>();\n const listeners = new Set<() => void>();\n const notify = () => {\n for (const l of [...listeners]) l();\n };\n\n return {\n register(provider) {\n if (entries.has(provider.id)) throw new DuplicateProviderError(provider.id);\n const declared = provider.declaredIds?.() ?? [];\n const own = new Set<string>();\n for (const id of declared) {\n if (own.has(id)) throw new DuplicateActionError(id, provider.id, provider.id);\n own.add(id);\n for (const [otherId, other] of entries) {\n if (other.declared.includes(id)) throw new DuplicateActionError(id, otherId, provider.id);\n }\n }\n const entry: Entry = { provider, declared };\n entries.set(provider.id, entry);\n notify();\n return () => {\n if (entries.get(provider.id) === entry) {\n entries.delete(provider.id);\n notify();\n }\n };\n },\n\n async resolve(target, restrict) {\n const authResumable = Boolean(ports.auth);\n const seen = new Map<string, string>();\n const out: ResolvedAction[] = [];\n for (const [providerId, { provider }] of [...entries]) {\n let actions: readonly Action[];\n try {\n actions = await provider.actions(target);\n } catch (error) {\n capture(ports, error, { providerId, stage: \"actions\" });\n continue;\n }\n for (const raw of actions) {\n const first = seen.get(raw.id);\n if (first !== undefined) {\n capture(ports, new DuplicateActionError(raw.id, first, providerId), { actionId: raw.id });\n continue;\n }\n seen.set(raw.id, providerId);\n const action: Action = raw.provider === providerId ? raw : { ...raw, provider: providerId };\n let eligibility: ReturnType<typeof computeEligibility>;\n try {\n eligibility = computeEligibility(action, target, { restrict: restrict ?? {}, authResumable });\n } catch (error) {\n capture(ports, error, { actionId: action.id, stage: \"eligible\" });\n continue;\n }\n if (eligibility.status === \"contract-break\") {\n capture(ports, new Error(eligibility.reason), { actionId: action.id, stage: \"eligible\" });\n continue;\n }\n if (eligibility.status === \"absent\") continue;\n out.push({ action, eligibility });\n }\n }\n return out;\n },\n\n providers() {\n return [...entries.keys()];\n },\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n\n/** A provider over a fixed list; its ids are declared up front so duplicates fail at registration. */\nexport function staticActionProvider(\n id: string,\n actions: readonly Action[],\n tier: ActionProvider[\"tier\"] = \"T0\",\n): ActionProvider {\n const list = actions.map((a) => (a.provider === id ? a : { ...a, provider: id }));\n return {\n id,\n tier,\n declaredIds: () => list.map((a) => a.id),\n actions: () => list,\n };\n}\n\n/** Always-available eligibility, for actions with no rule of their own. */\nexport const alwaysEligible = (): Eligibility => ({ status: \"available\" });\n","/**\n * Sensitivity defaults and resolution (CONTRACT §2.1). Its own module so the\n * lightweight entries (`/actions`, the T0 React host) can project without\n * pulling the declaration registry.\n */\nimport type { DeclaredValue, Sensitivity } from \"./types\";\n\nexport const DEFAULT_SENSITIVITY: Sensitivity = Object.freeze({\n exportable: true,\n classification: \"ordinary\",\n includedByDefault: true,\n});\n\nexport function resolveSensitivity(value: Pick<DeclaredValue, \"sensitivity\">): Sensitivity {\n return {\n exportable: value.sensitivity?.exportable ?? DEFAULT_SENSITIVITY.exportable,\n classification: value.sensitivity?.classification ?? DEFAULT_SENSITIVITY.classification,\n includedByDefault: value.sensitivity?.includedByDefault ?? DEFAULT_SENSITIVITY.includedByDefault,\n };\n}\n","/**\n * PROJECTION BEFORE PROVIDERS (CONTRACT §2.4).\n *\n * The only place a raw read (`MountedSurface.readValues`,\n * `InternalResolvedItem.readValues`) is consumed on behalf of an action.\n * What leaves is projected: a value is kept only when it is DECLARED, its\n * classification is \"ordinary\" and it is exportable. Everything removed is\n * recorded as an omission, so the person and the agent can see what was held\n * back. No caller can relax this.\n */\nimport { resolveSensitivity } from \"../declare/sensitivity\";\nimport type { InternalResolvedItem, MountedSurface } from \"../declare/host\";\nimport type { DeclaredValue, Json, LiveValues, ResolvedSurfaceDeclaration } from \"../declare/types\";\nimport type { ProjectedReads, ReadOmission } from \"./types\";\n\nexport interface ProjectionSource {\n surface: MountedSurface | null;\n declaration: ResolvedSurfaceDeclaration | null;\n item: InternalResolvedItem | null;\n}\n\nfunction toJson(value: unknown): Json | undefined {\n if (value === undefined || typeof value === \"function\" || typeof value === \"symbol\") return undefined;\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n if (typeof value === \"number\") return Number.isFinite(value) ? value : null;\n if (typeof value === \"bigint\") return value.toString();\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return value.map((v) => toJson(v) ?? null);\n if (typeof value === \"object\") {\n const out: { [key: string]: Json } = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n const j = toJson(v);\n if (j !== undefined) out[k] = j;\n }\n return out;\n }\n return undefined;\n}\n\n/** Keep declared, ordinary, exportable values; record every removal. */\nexport function projectValues(\n raw: Record<string, unknown>,\n declared: readonly Pick<DeclaredValue, \"name\" | \"sensitivity\">[],\n pathPrefix = \"\",\n): { values: Record<string, Json>; omissions: ReadOmission[] } {\n const byName = new Map(declared.map((d) => [d.name, d]));\n const values: Record<string, Json> = {};\n const omissions: ReadOmission[] = [];\n for (const [name, value] of Object.entries(raw)) {\n const path = pathPrefix ? `${pathPrefix}.${name}` : name;\n const decl = byName.get(name);\n if (!decl) {\n omissions.push({ path, reason: \"filtered\" });\n continue;\n }\n const sensitivity = resolveSensitivity(decl);\n if (sensitivity.classification !== \"ordinary\") {\n omissions.push({ path, reason: \"excluded\", classification: sensitivity.classification });\n continue;\n }\n if (!sensitivity.exportable) {\n omissions.push({ path, reason: \"excluded\" });\n continue;\n }\n const json = toJson(value);\n if (json === undefined) continue;\n values[name] = json;\n }\n return { values, omissions };\n}\n\nexport function createProjectedReads(source: ProjectionSource): ProjectedReads {\n return {\n async values(signal) {\n if (!source.surface || !source.declaration) return { values: {}, omissions: [] };\n const raw = await source.surface.readValues(signal);\n const screenValues = source.declaration.values;\n return projectValues(raw, screenValues);\n },\n async item(signal) {\n const item = source.item;\n if (!item || !source.declaration) return null;\n const type = source.declaration.itemTypes?.find((t) => t.name === item.itemType);\n if (!type) return { values: {}, omissions: [{ path: item.itemType, reason: \"filtered\" }] };\n const raw = await item.readValues(signal);\n return projectValues(raw, type.values, item.itemType);\n },\n async live(signal): Promise<LiveValues> {\n if (!source.surface?.readLive) return {};\n return source.surface.readLive(signal);\n },\n };\n}\n","import type { QualifiedValueKey } from \"./types\";\n\n/** Every value, write-target, item-type and group name (the DB CHECK rule). */\nexport const DECLARATION_NAME_RE = /^[a-z][a-z0-9_]*$/;\n\n/** \"<client>/<local>\" — the surface naming convention. */\nexport const SURFACE_NAME_RE = /^[a-z][a-z0-9-]*\\/[a-z0-9-/]+$/;\n\n/** A bare screen value (`status`) or an item value (`table_row.status`). */\nexport const QUALIFIED_VALUE_KEY_RE = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)?$/;\n\nexport interface ParsedValueKey {\n /** \"\" for a screen-level value. */\n itemType: string;\n name: string;\n}\n\n/** Split a qualified key; null when it is not a valid bare or qualified key. */\nexport function parseQualifiedValueKey(key: string): ParsedValueKey | null {\n if (!QUALIFIED_VALUE_KEY_RE.test(key)) return null;\n const dot = key.indexOf(\".\");\n if (dot === -1) return { itemType: \"\", name: key };\n return { itemType: key.slice(0, dot), name: key.slice(dot + 1) };\n}\n\nexport function qualifyValueKey(itemType: string, name: string): QualifiedValueKey {\n return itemType ? `${itemType}.${name}` : name;\n}\n\n/** The client that owns a surface: its name prefix. */\nexport function surfaceClientOf(surfaceName: string): string {\n return surfaceName.split(\"/\")[0] ?? \"\";\n}\n","/**\n * Building a ClickTarget from what is declared at the click (CONTRACT §2.4).\n * Key existence, never value population: a value key is present when the\n * declaration gives it a read path here.\n */\nimport { resolveSensitivity } from \"../declare/sensitivity\";\nimport { qualifyValueKey } from \"../declare/keys\";\nimport type { ResolvedItem, ResolvedSurfaceDeclaration, WriteTarget } from \"../declare/types\";\nimport type { ClickTarget } from \"./types\";\n\nexport interface ClickTargetInput {\n surface?: ClickTarget[\"surface\"];\n declaration?: ResolvedSurfaceDeclaration | null;\n item?: ResolvedItem | null;\n level?: string | null;\n selection?: ClickTarget[\"selection\"];\n payloadKinds?: ClickTarget[\"payloadKinds\"];\n /** Defaults to the item's readOnly (or false). */\n readOnly?: boolean;\n /** Extra exclusions on top of the declaration's own. */\n excludedActionIds?: Iterable<string>;\n scopeChain?: readonly string[];\n organizationId?: string | null;\n auth?: Partial<ClickTarget[\"auth\"]>;\n /** Write targets the host can serve right now; defaults to every declared target for the screen/item. */\n writable?: readonly WriteTarget[];\n host?: unknown;\n}\n\nfunction domainOf(surfaceName: string): string {\n const slash = surfaceName.indexOf(\"/\");\n return slash > 0 ? surfaceName.slice(0, slash) : surfaceName;\n}\n\nexport function createClickTarget(input: ClickTargetInput = {}): ClickTarget {\n const declaration = input.declaration ?? null;\n const item = input.item ?? null;\n const valueKeys = new Set<string>();\n let restricted = false;\n const writable: WriteTarget[] = [];\n if (declaration) {\n for (const value of declaration.values) {\n valueKeys.add(value.name);\n const s = resolveSensitivity(value);\n if (s.classification !== \"ordinary\" || !s.exportable) restricted = true;\n }\n const itemType = item ? declaration.itemTypes?.find((t) => t.name === item.itemType) : undefined;\n if (itemType) {\n for (const value of itemType.values) {\n valueKeys.add(qualifyValueKey(itemType.name, value.name));\n const s = resolveSensitivity(value);\n if (s.classification !== \"ordinary\" || !s.exportable) restricted = true;\n }\n for (const t of itemType.writeTargets ?? []) writable.push(t);\n }\n for (const t of declaration.writeTargets ?? []) {\n if (!t.itemType || t.itemType === item?.itemType) writable.push(t);\n }\n }\n const readOnly = input.readOnly ?? item?.readOnly ?? false;\n const surfaceName = input.surface?.surfaceName ?? declaration?.surfaceName ?? null;\n const scopeChain = input.scopeChain ?? (surfaceName ? [\"global\", domainOf(surfaceName), surfaceName] : [\"global\"]);\n return {\n surface: input.surface ?? null,\n declaration,\n valueKeys,\n scopeChain,\n excludedActionIds: new Set(input.excludedActionIds ?? []),\n item,\n level: input.level ?? item?.level ?? null,\n selection: input.selection ?? null,\n payloadKinds: input.payloadKinds ?? [],\n writable: readOnly ? [] : (input.writable ?? writable),\n readOnly,\n restricted,\n organizationId: input.organizationId ?? null,\n auth: {\n authenticated: input.auth?.authenticated ?? false,\n admin: input.auth?.admin ?? false,\n creator: input.auth?.creator ?? false,\n },\n host: input.host,\n };\n}\n","/**\n * The one run path (T1e). Every layout runs an action through here, so the\n * sign-in-then-resume rule, projection and failure capture live once.\n */\nimport type { TransferOutcome } from \"@ai-matrx/kit/content-transfer\";\nimport type { AlchemyHostPorts } from \"../ports\";\nimport { createProjectedReads, type ProjectionSource } from \"./projection\";\nimport type { Action, ClickTarget } from \"./types\";\n\nexport interface RunActionOptions {\n ports: AlchemyHostPorts;\n /** Raw sources; projected before the action sees them. */\n source?: ProjectionSource;\n /** Stable fingerprint of the content, for sign-in-then-resume. */\n contentFingerprint?: string;\n signal?: AbortSignal;\n}\n\nexport type RunResult =\n | { status: \"ran\"; outcome: TransferOutcome | void }\n | { status: \"auth-pending\" }\n | { status: \"failed\"; error: unknown };\n\nexport async function runAction(action: Action, target: ClickTarget, options: RunActionOptions): Promise<RunResult> {\n const { ports } = options;\n if (action.requiresAuth && !target.auth.authenticated) {\n if (!ports.auth) {\n // Unreachable through resolve (the action is absent without the port); guard direct callers.\n ports.diagnostics.capture(new Error(`requiresAuth action \"${action.id}\" ran signed out with no auth port`), {\n area: \"actions\",\n detail: { actionId: action.id },\n });\n return { status: \"failed\", error: new Error(\"sign-in unavailable\") };\n }\n ports.auth.signInThenResume({ actionId: action.id, contentFingerprint: options.contentFingerprint ?? action.id });\n return { status: \"auth-pending\" };\n }\n const reads = createProjectedReads(options.source ?? { surface: null, declaration: target.declaration, item: null });\n const signal = options.signal ?? new AbortController().signal;\n try {\n const outcome = await action.run(target, { reads, ports, signal });\n return { status: \"ran\", outcome };\n } catch (error) {\n ports.diagnostics.capture(error, { area: \"actions\", detail: { actionId: action.id, stage: \"run\" } });\n const label = typeof action.label === \"string\" ? action.label : action.id;\n ports.notify?.error(`${label} did not finish.`, \"Try again; if it keeps failing, report it from the feedback button.\");\n return { status: \"failed\", error };\n }\n}\n","/**\n * The declaration registry: inheritance, baseline injection, provenance and\n * group synthesis (CONTRACT §2.1 `DeclarationRegistry`). Ported verbatim in\n * behaviour from matrx-frontend `features/surfaces/manifests/registry.ts`\n * (ALC-14); the app now supplies its declarations and baselines.\n *\n * Guards are LOUD by design: an unknown parent, a cycle, a chain deeper than\n * the limit, a reserved or duplicate group key, a value naming an undeclared\n * group, or a reserved platform name throws on resolution — a build fails\n * instead of silently dropping values.\n */\nimport { declarationHash } from \"./hash\";\nimport type {\n DeclarationExtension,\n DeclarationIssue,\n DeclaredValue,\n ResolvedSurfaceDeclaration,\n ResolvedValue,\n Sensitivity,\n SurfaceDeclaration,\n ValueGroup,\n ValueProvenance,\n} from \"./types\";\nimport { validateDeclarations, type ValidateOptions } from \"./validate\";\n\nexport const RESERVED_GROUP_KEYS = {\n general: \"general\",\n baseline: \"baseline\",\n inheritedPrefix: \"inherited:\",\n} as const;\n\n/** Group sortOrder bands. Curated groups author 0–899; the rest is reserved. */\nexport const GENERAL_GROUP_ORDER = 850;\nexport const INHERITED_GROUP_ORDER_BASE = 9000;\nexport const BASELINE_GROUP_ORDER = 9900;\nexport const DEFAULT_MAX_INHERITANCE_DEPTH = 3;\n\nimport { DEFAULT_SENSITIVITY, resolveSensitivity } from \"./sensitivity\";\nexport { DEFAULT_SENSITIVITY, resolveSensitivity };\n\nexport type Resolved<D extends SurfaceDeclaration> = Omit<D, \"values\" | \"groups\"> & {\n values: readonly (D[\"values\"][number] & ResolvedValue)[];\n groups: readonly ValueGroup[];\n contentHash: string;\n};\n\nexport interface DeclarationRegistryOptions {\n /** Generic values injected into every declaration unless `skipBaselineValues`. */\n baselineValues?: readonly DeclaredValue[];\n /** Value names only the platform writes; a declaration claiming one is refused. */\n reservedValueNames?: readonly string[];\n /** Write-target names only the platform writes. */\n reservedWriteTargetNames?: readonly string[];\n maxInheritanceDepth?: number;\n}\n\nexport interface DeclarationRegistry<D extends SurfaceDeclaration> {\n /** Refuses a second declaration of the same surfaceName. */\n register(declaration: D): void;\n registerExtension(extension: DeclarationExtension<D>): void;\n extensions(): readonly DeclarationExtension<D>[];\n /** Declarations exactly as authored (inheritance unresolved, no baselines). */\n raw(): readonly D[];\n getRaw(surfaceName: string): D | undefined;\n /** Parent chain, ROOT FIRST. Unknown surfaces return []. */\n ancestry(surfaceName: string): string[];\n /** Direct children (declarations naming it in `inheritsFrom`), in declaration order. */\n children(surfaceName: string): string[];\n /** Inheritance + baseline + groups resolved; provenance kept. */\n all(): readonly Resolved<D>[];\n get(surfaceName: string): Resolved<D> | undefined;\n validate(options?: ValidateOptions): readonly DeclarationIssue[];\n}\n\nexport function createDeclarationRegistry<D extends SurfaceDeclaration>(\n options: DeclarationRegistryOptions = {},\n): DeclarationRegistry<D> {\n const baselineValues = options.baselineValues ?? [];\n const baselineNames = new Set(baselineValues.map((v) => v.name));\n const reservedValues = new Set(options.reservedValueNames ?? []);\n const reservedTargets = new Set(options.reservedWriteTargetNames ?? []);\n const maxDepth = options.maxInheritanceDepth ?? DEFAULT_MAX_INHERITANCE_DEPTH;\n const declarations: D[] = [];\n const index = new Map<string, D>();\n const extensionList: DeclarationExtension<D>[] = [];\n let resolvedCache: Resolved<D>[] | null = null;\n let resolvedIndex = new Map<string, Resolved<D>>();\n\n function ancestry(surfaceName: string): string[] {\n const chain: string[] = [];\n const seen = new Set<string>([surfaceName]);\n let current = index.get(surfaceName)?.inheritsFrom;\n while (current) {\n if (seen.has(current)) {\n throw new Error(\n `[surfaces] inheritsFrom CYCLE detected at \"${current}\" (from \"${surfaceName}\"). ` +\n `Fix the manifest chain: ${[...seen].join(\" → \")} → ${current}`,\n );\n }\n const parent = index.get(current);\n if (!parent) {\n throw new Error(\n `[surfaces] \"${surfaceName}\" inheritsFrom unknown surface \"${current}\" — ` +\n `the parent must be a registered declaration`,\n );\n }\n seen.add(current);\n chain.unshift(current);\n if (chain.length > maxDepth) {\n throw new Error(\n `[surfaces] inheritance chain for \"${surfaceName}\" exceeds depth ${maxDepth}: ` + chain.join(\" → \"),\n );\n }\n current = parent.inheritsFrom;\n }\n return chain;\n }\n\n function groupKeyFor(value: DeclaredValue, provenance: ValueProvenance): string {\n if (provenance.kind === \"own\" && value.group) return value.group;\n if (baselineNames.has(value.name)) return RESERVED_GROUP_KEYS.baseline;\n if (provenance.kind === \"inherited\") return `${RESERVED_GROUP_KEYS.inheritedPrefix}${provenance.from}`;\n if (provenance.kind === \"baseline\") return RESERVED_GROUP_KEYS.baseline;\n return RESERVED_GROUP_KEYS.general;\n }\n\n function resolve(declaration: D): Resolved<D> {\n const chain = ancestry(declaration.surfaceName);\n const lineage: { layer: D; from: string | null }[] = [\n ...chain.map((name) => {\n const layer = index.get(name);\n if (!layer) throw new Error(`[surfaces] missing inherited declaration \"${name}\"`);\n return { layer, from: name };\n }),\n { layer: declaration, from: null },\n ];\n\n const curatedKeys = new Set<string>();\n for (const group of declaration.groups ?? []) {\n if (\n group.key === RESERVED_GROUP_KEYS.general ||\n group.key === RESERVED_GROUP_KEYS.baseline ||\n group.key.startsWith(RESERVED_GROUP_KEYS.inheritedPrefix)\n ) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" declares reserved group key \"${group.key}\" — ` +\n `general/baseline/inherited:* are synthesized by the registry`,\n );\n }\n if (curatedKeys.has(group.key)) {\n throw new Error(`[surfaces] \"${declaration.surfaceName}\" declares duplicate group key \"${group.key}\"`);\n }\n curatedKeys.add(group.key);\n }\n for (const value of declaration.values) {\n if (reservedValues.has(value.name)) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" declares value \"${value.name}\" — that name is written by the platform; choose another name`,\n );\n }\n if (value.group && !curatedKeys.has(value.group)) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" value \"${value.name}\" references undeclared ` +\n `group \"${value.group}\" — declare it in the manifest's \\`groups\\``,\n );\n }\n }\n for (const target of declaration.writeTargets ?? []) {\n if (reservedTargets.has(target.name)) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" declares write target \"${target.name}\" — that name is written by the platform; choose another name`,\n );\n }\n }\n\n const valuesByName = new Map<string, D[\"values\"][number] & ResolvedValue>();\n const inheritedLists = new Map<string, Map<string, unknown>>();\n const coreLists: { field: string; identity(entry: unknown): string }[] = [\n { field: \"configNamespaces\", identity: (entry) => (entry as { namespace: string }).namespace },\n {\n field: \"evidenceSources\",\n identity: (entry) => `${(entry as { kind: string }).kind}:${(entry as { idValue: string }).idValue}`,\n },\n ];\n const lists = [...coreLists, ...extensionList.flatMap((extension) => extension.inheritedLists ?? [])];\n for (const { layer, from } of lineage) {\n for (const value of layer.values) {\n const provenance: ValueProvenance = from ? { kind: \"inherited\", from } : { kind: \"own\" };\n valuesByName.set(value.name, {\n ...value,\n provenance,\n groupKey: groupKeyFor(value, provenance),\n resolvedSensitivity: resolveSensitivity(value),\n });\n }\n for (const list of lists) {\n const entries = (layer as unknown as Record<string, unknown>)[list.field];\n if (!Array.isArray(entries)) continue;\n const byIdentity = inheritedLists.get(list.field) ?? new Map<string, unknown>();\n for (const entry of entries) byIdentity.set(list.identity(entry), entry);\n inheritedLists.set(list.field, byIdentity);\n }\n }\n\n if (!declaration.skipBaselineValues) {\n for (const baseline of baselineValues) {\n if (valuesByName.has(baseline.name)) continue;\n valuesByName.set(baseline.name, {\n ...baseline,\n provenance: { kind: \"baseline\" },\n groupKey: RESERVED_GROUP_KEYS.baseline,\n resolvedSensitivity: resolveSensitivity(baseline),\n } as D[\"values\"][number] & ResolvedValue);\n }\n }\n\n const usedGroupKeys = new Set(Array.from(valuesByName.values(), (value) => value.groupKey));\n const groups: ValueGroup[] = [...(declaration.groups ?? [])];\n if (usedGroupKeys.has(RESERVED_GROUP_KEYS.general)) {\n groups.push({ key: RESERVED_GROUP_KEYS.general, label: \"General\", sortOrder: GENERAL_GROUP_ORDER });\n }\n for (let i = chain.length - 1, distance = 0; i >= 0; i -= 1, distance += 1) {\n const parentName = chain[i]!;\n const key = `${RESERVED_GROUP_KEYS.inheritedPrefix}${parentName}`;\n if (!usedGroupKeys.has(key)) continue;\n const parentLabel = index.get(parentName)?.label ?? parentName;\n groups.push({\n key,\n label: `Inherited from ${parentLabel}`,\n sortOrder: INHERITED_GROUP_ORDER_BASE + distance * 10,\n });\n }\n if (usedGroupKeys.has(RESERVED_GROUP_KEYS.baseline)) {\n groups.push({ key: RESERVED_GROUP_KEYS.baseline, label: \"Generic baselines\", sortOrder: BASELINE_GROUP_ORDER });\n }\n groups.sort((a, b) => a.sortOrder - b.sortOrder);\n\n const groupOrder = new Map(groups.map((group) => [group.key, group.sortOrder] as const));\n const values = Array.from(valuesByName.values()).sort((a, b) => {\n const ga = groupOrder.get(a.groupKey) ?? GENERAL_GROUP_ORDER;\n const gb = groupOrder.get(b.groupKey) ?? GENERAL_GROUP_ORDER;\n if (ga !== gb) return ga - gb;\n return (a.sortOrder ?? 1000) - (b.sortOrder ?? 1000);\n });\n\n const merged: Record<string, unknown> = {};\n for (const [field, byIdentity] of inheritedLists) {\n if (byIdentity.size > 0) merged[field] = Array.from(byIdentity.values());\n }\n return {\n ...declaration,\n values,\n groups,\n ...merged,\n contentHash: declarationHash(declaration),\n } as Resolved<D>;\n }\n\n function resolvedAll(): Resolved<D>[] {\n if (!resolvedCache) {\n resolvedCache = declarations.map(resolve);\n resolvedIndex = new Map(resolvedCache.map((entry) => [entry.surfaceName, entry] as const));\n }\n return resolvedCache;\n }\n\n const registry: DeclarationRegistry<D> = {\n register(declaration) {\n if (index.has(declaration.surfaceName)) {\n throw new Error(`[surfaces] \"${declaration.surfaceName}\" is declared twice — one surface, one declaration`);\n }\n declarations.push(declaration);\n index.set(declaration.surfaceName, declaration);\n resolvedCache = null;\n },\n registerExtension(extension) {\n if (extensionList.some((existing) => existing.key === extension.key)) {\n throw new Error(`[surfaces] declaration extension \"${extension.key}\" is registered twice`);\n }\n extensionList.push(extension);\n resolvedCache = null;\n },\n extensions: () => extensionList,\n raw: () => declarations,\n getRaw: (surfaceName) => index.get(surfaceName),\n ancestry,\n children: (surfaceName) =>\n declarations.filter((d) => d.inheritsFrom === surfaceName).map((d) => d.surfaceName),\n all: () => resolvedAll(),\n get(surfaceName) {\n resolvedAll();\n return resolvedIndex.get(surfaceName);\n },\n validate: (validateOptions) =>\n validateDeclarations(resolvedAll() as unknown as readonly ResolvedSurfaceDeclaration[], {\n ...validateOptions,\n extensions: [...(validateOptions?.extensions ?? []), ...(extensionList as DeclarationExtension[])],\n baselineNames: validateOptions?.baselineNames ?? [...baselineNames],\n }),\n };\n return registry;\n}\n","/**\n * Every source of an Action projects onto ONE shape (Applets CONTRACTS §6):\n * a declared write target, a client tool row, a `ui.ui_surface_action` row.\n * Pure functions, zero loss (the census in `declarations.test.ts` proves every\n * source field lands). Then the chain: a child surface's Action wins by name.\n */\nimport { DEFAULT_MAX_INHERITANCE_DEPTH } from \"../declare/registry\";\nimport type { Json, WriteTarget } from \"../declare/types\";\nimport type {\n ActionCaller,\n ActionDeclaration,\n ActionDeclaredBy,\n ActionInfo,\n ActionInput,\n ActionOrigin,\n ActionPolicy,\n ActionRuns,\n ActionWriteMode,\n} from \"./applet-types\";\n\n/** Default `category` of an Action that names none. */\nexport const APPLET_CATEGORY = \"applet\";\n\n/** The DB default of `ui.ui_surface_action.triggered_by`, used where a source carries no list. */\nexport const DEFAULT_TRIGGERED_BY: readonly ActionCaller[] = [\"person\", \"agent\", \"applet\"];\n\nexport const ACTION_CALLERS: readonly ActionCaller[] = [\"person\", \"agent\", \"applet\", \"automation\"];\nexport const ACTION_RUNS: readonly ActionRuns[] = [\"page\", \"server\", \"mandate\", \"navigate\"];\nexport const ACTION_POLICIES: readonly ActionPolicy[] = [\"ask\", \"auto\", \"manual\"];\n\n/** A `ui.ui_surface_client_tool` row (live columns that carry meaning). */\nexport interface ClientToolRow {\n id?: string;\n surface_name: string;\n name: string;\n label: string;\n description: string;\n input_schema: Json;\n /** Live values: \"ui\" (applied directly) | \"draft\" (proposed for review). */\n mode: \"ui\" | \"draft\";\n declared_by?: ActionDeclaredBy;\n}\n\n/** A `ui.ui_surface_action` row. */\nexport interface SurfaceActionRow {\n id?: string;\n surface_id: string;\n surface_name: string;\n /** '' = the screen itself. */\n item_type: string;\n name: string;\n category: string;\n label: string;\n description: string;\n input: ActionInput | null;\n output: string | null;\n runs: ActionRuns;\n target: string | null;\n triggered_by: ActionCaller[];\n policy: ActionPolicy;\n updates_value: string | null;\n code_ref: string | null;\n declared_by: ActionDeclaredBy;\n sort_order: number;\n}\n\ntype Loose<T> = { [K in keyof T]: T[K] | undefined };\n\n/** Drop undefined keys (exactOptionalPropertyTypes: an absent field is absent, never `undefined`). */\nfunction compact<T extends object>(value: Loose<T>): T {\n return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined)) as T;\n}\n\nconst POLICY_OF_APPLY: Record<NonNullable<WriteTarget[\"applyPolicy\"]>, ActionPolicy> = {\n manual: \"manual\",\n ask: \"ask\",\n auto: \"auto\",\n // Filed for an organization's review: never applied without someone saying yes.\n queued: \"ask\",\n};\n\n/** A declared write target → an Action that runs on the page. */\nexport function writeTargetToAction(target: WriteTarget): ActionDeclaration {\n const applyPolicy = target.applyPolicy ?? \"manual\";\n return compact<ActionDeclaration>({\n name: target.name,\n label: target.label,\n description: target.description,\n input: target.valueKind ?? { jsonSchema: target.valueType === \"document\" ? {} : { type: target.valueType } },\n runs: \"page\",\n triggeredBy: [...DEFAULT_TRIGGERED_BY],\n policy: POLICY_OF_APPLY[applyPolicy],\n updatesValue: target.updatesValue,\n mode: target.mode as ActionWriteMode,\n patchable: target.patchable,\n approvalComparison: target.approvalComparison,\n streamOps: target.streamOps ? [...target.streamOps] : undefined,\n destination: target.destination,\n groupKey: target.group,\n itemType: target.itemType,\n applyPolicy: target.applyPolicy,\n valueType: target.valueType,\n valueKind: target.valueKind,\n sortOrder: target.sortOrder,\n origin: { source: \"write-target\", declaredBy: \"code\" },\n });\n}\n\n/** A client tool row → an Action an agent runs on the page (\"draft\" tools are proposed first). */\nexport function clientToolToAction(row: ClientToolRow): ActionDeclaration {\n return compact<ActionDeclaration>({\n name: row.name,\n label: row.label,\n description: row.description,\n input: { jsonSchema: (row.input_schema ?? {}) as object },\n runs: \"page\",\n triggeredBy: [\"agent\"],\n policy: row.mode === \"draft\" ? \"ask\" : \"auto\",\n mode: row.mode,\n origin: compact<ActionOrigin>({ source: \"client-tool\", surfaceName: row.surface_name, id: row.id, declaredBy: row.declared_by }),\n });\n}\n\n/** A `ui.ui_surface_action` row → its Action. */\nexport function surfaceActionRowToAction(row: SurfaceActionRow): ActionDeclaration {\n return compact<ActionDeclaration>({\n name: row.name,\n category: row.category,\n label: row.label,\n description: row.description,\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n runs: row.runs,\n target: row.target ?? undefined,\n triggeredBy: [...row.triggered_by],\n policy: row.policy,\n updatesValue: row.updates_value ?? undefined,\n itemType: row.item_type || undefined,\n sortOrder: row.sort_order,\n origin: compact<ActionOrigin>({\n source: \"surface-action\",\n surfaceName: row.surface_name,\n surfaceId: row.surface_id,\n id: row.id,\n declaredBy: row.declared_by,\n codeRef: row.code_ref ?? undefined,\n }),\n });\n}\n\n/** JSON-only view of an Action as declared on `declaredOn`. */\nexport function toActionInfo(declaration: ActionDeclaration, declaredOn: string): ActionInfo {\n return compact<ActionInfo>({\n name: declaration.name,\n category: declaration.category ?? APPLET_CATEGORY,\n label: declaration.label,\n description: declaration.description,\n runs: declaration.runs,\n policy: declaration.policy,\n triggeredBy: [...declaration.triggeredBy],\n input: declaration.input,\n output: declaration.output,\n declaredOn,\n target: declaration.target,\n updatesValue: declaration.updatesValue,\n itemType: declaration.itemType,\n source: declaration.origin?.source,\n });\n}\n\nexport interface ActionChainLink {\n surfaceName: string;\n actions: readonly ActionDeclaration[];\n}\n\n/**\n * The Actions a mount sees: its own plus every ancestor's, a child winning by\n * name. `chain` runs MOST GENERAL FIRST (root parent … the mounted surface),\n * as `DeclarationRegistry` resolves inheritance. Guards are loud, like the\n * declaration registry's: a surface twice in the chain is a cycle, more\n * ancestors than `maxDepth` throws, and one surface naming an Action twice throws.\n */\nexport function resolveActionChain(\n chain: readonly ActionChainLink[],\n options: { maxDepth?: number } = {},\n): ActionInfo[] {\n const maxDepth = options.maxDepth ?? DEFAULT_MAX_INHERITANCE_DEPTH;\n const names = chain.map((link) => link.surfaceName);\n const seen = new Set<string>();\n for (const name of names) {\n if (seen.has(name)) {\n throw new Error(`[actions] inheritance CYCLE detected at \"${name}\". Fix the surface chain: ${names.join(\" → \")}`);\n }\n seen.add(name);\n }\n if (chain.length - 1 > maxDepth) {\n throw new Error(\n `[actions] inheritance chain for \"${names[names.length - 1]}\" exceeds depth ${maxDepth}: ${names.join(\" → \")}`,\n );\n }\n const byName = new Map<string, ActionInfo>();\n for (const link of chain) {\n const own = new Set<string>();\n for (const action of link.actions) {\n if (own.has(action.name)) {\n throw new Error(\n `[actions] surface \"${link.surfaceName}\" declares Action \"${action.name}\" twice. Names are unique; nothing was overwritten.`,\n );\n }\n own.add(action.name);\n byName.set(action.name, toActionInfo(action, link.surfaceName));\n }\n }\n return [...byName.values()];\n}\n","/**\n * THE ONE RUNNER for surface Actions (Applets CONTRACTS §6). Every caller — a\n * person's click, an agent, an applet, an automation — runs an Action through\n * here, so policy and caller rules live once.\n *\n * Policy \"ask\": a person's own click is the approval. Started by an agent, applet or automation,\n * a \"server\" run carries the policy to aidream (which answers with a proposal); every other run\n * asks the person through `ports.approvals` first, and is refused by name without that port.\n *\n * Dispatch by `runs`:\n * \"server\" → `ports.serverActions.run({ name: target, input, by, surface_name, policy })`\n * \"mandate\" → `ports.mandates.run({ alias: target, variables, by, policy })`\n * \"navigate\" → `ports.overlay.navigate(target)` with `{param}` filled from the input\n * \"page\" → `ports.pageActions.dispatch(name, input, context)`\n * A port the host did not bind means that capability is ABSENT: the run is\n * refused with a sentence, never stubbed (ports rule).\n *\n * Write targets (ALC-17): an Action projected from a declared write target (`source: \"write-target\"`)\n * goes through `ports.door.write` when a door is bound — the door applies the target's own policy\n * (manual / ask / queued / auto) and its receipt becomes the result (`applied` / `queued` → ok with\n * the receipt; refused → an error whose code is the refusal reason and whose `remedy` is the door's).\n * Without a door it dispatches to `pageActions` as before.\n *\n * Never throws: every outcome is a `Result` whose error message is the\n * system's own sentence.\n */\nimport type { AlchemyHostPorts, Json } from \"../ports\";\nimport type { WriteOp } from \"../operate/door\";\nimport type { ActionCaller, ActionContext, ActionError, ActionInfo, ActionResult } from \"./applet-types\";\n\nexport type SurfaceActionPorts = Pick<\n AlchemyHostPorts,\n \"diagnostics\" | \"serverActions\" | \"mandates\" | \"pageActions\" | \"overlay\" | \"approvals\" | \"door\"\n>;\n\nexport interface RunSurfaceActionOptions {\n runId?: string;\n viewerId?: string | null;\n signal?: AbortSignal;\n /** Which item a write-target Action writes into (by its declared identity values). */\n itemIdentity?: Record<string, string>;\n /** Text edits for a stream or patchable write target, instead of the input as the whole value. */\n ops?: readonly WriteOp[];\n}\n\nfunction fail(code: string, message: string, retryable = false, diagnostic?: string): { ok: false; error: ActionError } {\n return { ok: false, error: diagnostic ? { code, message, retryable, diagnostic } : { code, message, retryable } };\n}\n\nfunction messageOf(error: unknown): string {\n if (error instanceof Error && error.message.trim()) return error.message;\n if (typeof error === \"string\" && error.trim()) return error;\n return \"The run failed without saying why.\";\n}\n\nfunction newRunId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n return `run-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Fill `{param}` placeholders from the input object. Returns the names it could not fill. */\nexport function fillActionTarget(template: string, input: unknown): { value: string; missing: string[] } {\n const source = input && typeof input === \"object\" && !Array.isArray(input) ? (input as Record<string, unknown>) : {};\n const missing: string[] = [];\n const value = template.replace(/\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g, (_, key: string) => {\n const v = source[key];\n if (v === undefined || v === null || v === \"\" || typeof v === \"object\") {\n missing.push(key);\n return \"\";\n }\n return encodeURIComponent(String(v));\n });\n return { value, missing };\n}\n\n/** Same as fillActionTarget, without URL-encoding (a mandate alias or server action name). */\nfunction fillName(template: string, input: unknown): { value: string; missing: string[] } {\n const filled = fillActionTarget(template, input);\n return { value: decodeURIComponent(filled.value), missing: filled.missing };\n}\n\nfunction toJson(value: unknown): Json {\n if (value === undefined) return null;\n return JSON.parse(JSON.stringify(value)) as Json;\n}\n\n/**\n * Who may run this Action, under its policy. Returns the refusal, or null.\n * \"manual\" = a person only. `triggeredBy` lists every caller allowed at all.\n */\nexport function refuseCaller(info: Pick<ActionInfo, \"name\" | \"label\" | \"policy\" | \"triggeredBy\">, by: ActionCaller): ActionError | null {\n if (!info.triggeredBy.includes(by)) {\n return {\n code: \"caller_not_allowed\",\n message: `\"${info.label}\" (${info.name}) can't be started by ${CALLER_WORDS[by]}; it allows ${info.triggeredBy.join(\", \") || \"no one\"}.`,\n retryable: false,\n };\n }\n if (info.policy === \"manual\" && by !== \"person\") {\n return {\n code: \"manual_only\",\n message: `\"${info.label}\" (${info.name}) runs only when a person starts it.`,\n retryable: false,\n };\n }\n return null;\n}\n\nconst CALLER_WORDS: Record<ActionCaller, string> = {\n person: \"a person\",\n agent: \"an agent\",\n applet: \"an applet\",\n automation: \"an automation\",\n};\n\nfunction absent(info: ActionInfo, capability: string): { ok: false; error: ActionError } {\n return fail(\"capability_absent\", `\"${info.label}\" can't run here: ${capability} isn't available on this page.`);\n}\n\nexport async function runSurfaceAction(\n info: ActionInfo,\n input: unknown,\n by: ActionCaller,\n ports: SurfaceActionPorts,\n options: RunSurfaceActionOptions = {},\n): Promise<ActionResult<unknown>> {\n const refusal = refuseCaller(info, by);\n if (refusal) return { ok: false, error: refusal };\n const context: ActionContext = {\n runId: options.runId ?? newRunId(),\n by,\n viewerId: options.viewerId ?? null,\n surfaceName: info.declaredOn,\n policy: info.policy,\n };\n const capture = (error: unknown, stage: string) => {\n try {\n ports.diagnostics.capture(error, { area: \"actions\", detail: { action: info.name, runs: info.runs, stage, runId: context.runId } });\n } catch {\n // A broken diagnostics port never turns a refusal into a throw.\n }\n };\n\n try {\n if (info.source === \"write-target\" && ports.door) {\n const receipt = await ports.door.write(\n {\n surfaceName: info.declaredOn,\n target: info.name,\n ...(info.itemType ? { itemType: info.itemType } : {}),\n ...(options.itemIdentity ? { itemIdentity: options.itemIdentity } : {}),\n ...(options.ops ? { ops: options.ops } : { value: input }),\n by,\n runId: context.runId,\n },\n options.signal,\n );\n if (receipt.status === \"refused\") {\n return { ok: false, error: { code: receipt.reason, message: receipt.sentence, retryable: receipt.reason === \"failed\", remedy: receipt.remedy } };\n }\n return { ok: true, data: receipt };\n }\n if (info.policy === \"ask\" && by !== \"person\" && info.runs !== \"server\") {\n if (!ports.approvals) {\n return fail(\"needs_approval\", `\"${info.label}\" needs a person's approval, and there is no one to ask here.`);\n }\n const approved = await ports.approvals.ask({\n action: info.name,\n label: info.label,\n description: info.description,\n input: toJson(input),\n by,\n surfaceName: info.declaredOn,\n });\n if (!approved) return fail(\"declined\", `\"${info.label}\" was not approved, so it did not run.`);\n }\n switch (info.runs) {\n case \"server\": {\n if (!ports.serverActions) return absent(info, \"server actions\");\n const filled = fillName(info.target ?? info.name, input);\n if (filled.missing.length) return fail(\"input_missing\", `\"${info.label}\" needs ${filled.missing.join(\", \")}.`);\n const response = await ports.serverActions.run({\n name: filled.value,\n input: toJson(input),\n by,\n surface_name: info.declaredOn,\n policy: info.policy,\n });\n if (response.status === \"refused\") return fail(\"refused\", response.message);\n return { ok: true, data: response };\n }\n case \"mandate\": {\n if (!ports.mandates) return absent(info, \"running a job\");\n if (!info.target) return fail(\"target_missing\", `\"${info.label}\" names no job to run.`);\n const filled = fillName(info.target, input);\n if (filled.missing.length) return fail(\"input_missing\", `\"${info.label}\" needs ${filled.missing.join(\", \")}.`);\n const record = input && typeof input === \"object\" && !Array.isArray(input) ? (input as Record<string, unknown>) : {};\n // A generic \"run a job\" Action carries { alias, variables, userInput }; a dedicated one's input IS the variables.\n const generic = /\\{[A-Za-z_]/.test(info.target);\n const variables = generic\n ? ((record.variables && typeof record.variables === \"object\" ? toJson(record.variables) : {}) as Record<string, Json>)\n : (toJson(record) as Record<string, Json>);\n const userInput = typeof record.userInput === \"string\" ? record.userInput : undefined;\n const data = await ports.mandates.run({\n alias: filled.value,\n variables,\n ...(userInput !== undefined ? { userInput } : {}),\n by,\n policy: info.policy,\n });\n return { ok: true, data };\n }\n case \"navigate\": {\n if (!ports.overlay) return absent(info, \"navigation\");\n const filled = fillActionTarget(info.target ?? \"\", input);\n if (filled.missing.length) return fail(\"input_missing\", `\"${info.label}\" needs ${filled.missing.join(\", \")}.`);\n // `{to}` is a whole route: keep its slashes.\n const to = info.target && /^\\{[A-Za-z_][A-Za-z0-9_]*\\}$/.test(info.target) ? decodeURIComponent(filled.value) : filled.value;\n if (!to) return fail(\"target_missing\", `\"${info.label}\" names no page to open.`);\n ports.overlay.navigate(to);\n return { ok: true, data: { to } };\n }\n case \"page\": {\n if (!ports.pageActions) return absent(info, \"this page's actions\");\n return await ports.pageActions.dispatch(info.name, input, context);\n }\n default: {\n const runs: never = info.runs;\n return fail(\"runs_unknown\", `\"${info.label}\" runs as \"${String(runs)}\", which nothing here knows how to run.`);\n }\n }\n } catch (error) {\n capture(error, \"run\");\n return fail(\"run_failed\", messageOf(error), true);\n }\n}\n"],"mappings":"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","names":["toJson","capture"]}
|
package/dist/checks.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var checks_exports={};__export(checks_exports,{GOVERNANCE_COLUMNS:()=>GOVERNANCE_COLUMNS,conflictUpdateColumns:()=>conflictUpdateColumns,findDeadUrlPatterns:()=>findDeadUrlPatterns,findStaleRows:()=>findStaleRows,mirrorRowKey:()=>mirrorRowKey,planColumns:()=>planColumns,planSurfaceSync:()=>planSurfaceSync,renderSurfaceSyncSql:()=>renderSurfaceSyncSql,renderSurfaceSyncStatements:()=>renderSurfaceSyncStatements,routeSegments:()=>routeSegments,sqlLiteral:()=>sqlLiteral,urlPatternMatchesRoute:()=>urlPatternMatchesRoute});module.exports=__toCommonJS(checks_exports);function surfaceClientOf(surfaceName){return surfaceName.split("/")[0]??""}var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}var GOVERNANCE_COLUMNS=["organization_id","published_to_web"];function childKey(schema){return schema?.itemType?["surface_name","item_type","name"]:["surface_name","name"]}function planSurfaceSync(declarations,options){let{organizationId,syncedFrom,schema}=options,provenance={synced_by:options.syncedBy??null,synced_from:syncedFrom},governance={organization_id:organizationId,published_to_web:!0},surfaces=[],values=[],targets=[],itemTypes=[],extensionTables=new Map;for(let d of declarations){let urlPattern=d.urlPattern?.trim()||options.resolveUrlPattern?.(d)||null,intro=d.intro?.trim()||null,parent=d.inheritsFrom??null,owned={client_name:surfaceClientOf(d.surfaceName),execution_mode:d.executionMode,description:d.description,label:d.label,value_groups:d.groups??[],readiness:d.readiness,readiness_note:d.readinessNote?.trim()||null,...schema?.contentHash?{content_hash:d.contentHash}:{}},claimed={...d.overlayId?{overlay_id:d.overlayId}:{},...urlPattern?{url_pattern:urlPattern}:{},...intro?{intro}:{},...parent?{parent_surface_name:parent}:{}};surfaces.push({name:d.surfaceName,insert:{name:d.surfaceName,...owned,overlay_id:d.overlayId??null,url_pattern:urlPattern,intro,parent_surface_name:parent},update:{...owned,...claimed}});for(let v of d.values)values.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:""}:{},name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.groupKey??v.group??"general",...schema?.valueContract?{exportable:resolveSensitivity(v).exportable,classification:resolveSensitivity(v).classification,included_by_default:resolveSensitivity(v).includedByDefault,kind_key:v.valueKind??null,live_slot:v.liveSlot??null,role:v.role??"data"}:{},...provenance});for(let t of d.writeTargets??[])targets.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:t.itemType??""}:{},name:t.name,label:t.label,description:t.description,value_type:t.valueType,mode:t.mode,updates_value:t.updatesValue??null,group_key:t.group??"general",sort_order:t.sortOrder??1e3,apply_policy:t.applyPolicy??"manual",kind_key:t.valueKind??null,...schema?.valueContract?{patchable:t.patchable??!1,approval_comparison:t.approvalComparison??null,stream_ops:t.streamOps?[...t.streamOps]:null,destination:t.destination??!1}:{},...provenance});if(schema?.itemType)for(let[position,item]of(d.itemTypes??[]).entries()){itemTypes.push({...governance,surface_name:d.surfaceName,name:item.name,label:item.label,description:item.description,identity:[...item.identity],levels:item.levels?[...item.levels]:null,entity_type:item.entityType??null,sort_order:position,...provenance});for(let v of item.values)values.push({...governance,surface_name:d.surfaceName,item_type:item.name,name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.group??"general",...provenance})}for(let extension of options.extensions??[])for(let entry of extension.toRows?.(d)??[]){let plan=extensionTables.get(entry.table)??{table:entry.table,conflict:entry.conflict,insertOnly:
|
|
1
|
+
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var checks_exports={};__export(checks_exports,{DECLARED_BY:()=>DECLARED_BY,GOVERNANCE_COLUMNS:()=>GOVERNANCE_COLUMNS,INSERT_ONLY_COLUMNS:()=>INSERT_ONLY_COLUMNS,SURFACE_ACTION_KEY:()=>SURFACE_ACTION_KEY,SURFACE_ACTION_TABLE:()=>SURFACE_ACTION_TABLE,conflictUpdateColumns:()=>conflictUpdateColumns,findDeadUrlPatterns:()=>findDeadUrlPatterns,findStaleRows:()=>findStaleRows,isDatabaseDeclared:()=>isDatabaseDeclared,mirrorRowKey:()=>mirrorRowKey,planColumns:()=>planColumns,planSurfaceSync:()=>planSurfaceSync,renderSurfaceSyncSql:()=>renderSurfaceSyncSql,renderSurfaceSyncStatements:()=>renderSurfaceSyncStatements,routeSegments:()=>routeSegments,sqlLiteral:()=>sqlLiteral,urlPatternMatchesRoute:()=>urlPatternMatchesRoute});module.exports=__toCommonJS(checks_exports);function surfaceClientOf(surfaceName){return surfaceName.split("/")[0]??""}var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}var GOVERNANCE_COLUMNS=["organization_id","published_to_web"],DECLARED_BY={code:"code",database:"database"},INSERT_ONLY_COLUMNS=[...GOVERNANCE_COLUMNS,"declared_by"],SURFACE_ACTION_TABLE="ui.ui_surface_action",SURFACE_ACTION_KEY=["surface_name","item_type","name"];function isDatabaseDeclared(row){return row.declared_by===DECLARED_BY.database}function childKey(schema){return schema?.itemType?["surface_name","item_type","name"]:["surface_name","name"]}function planSurfaceSync(declarations,options){let{organizationId,syncedFrom,schema}=options,provenance={synced_by:options.syncedBy??null,synced_from:syncedFrom},governance={organization_id:organizationId,published_to_web:!0,declared_by:DECLARED_BY.code},surfaces=[],values=[],targets=[],itemTypes=[],extensionTables=new Map;for(let d of declarations){let urlPattern=d.urlPattern?.trim()||options.resolveUrlPattern?.(d)||null,intro=d.intro?.trim()||null,parent=d.inheritsFrom??null,owned={client_name:surfaceClientOf(d.surfaceName),execution_mode:d.executionMode,description:d.description,label:d.label,value_groups:d.groups??[],readiness:d.readiness,readiness_note:d.readinessNote?.trim()||null,...schema?.contentHash?{content_hash:d.contentHash}:{}},claimed={...d.overlayId?{overlay_id:d.overlayId}:{},...urlPattern?{url_pattern:urlPattern}:{},...intro?{intro}:{},...parent?{parent_surface_name:parent}:{}};surfaces.push({name:d.surfaceName,insert:{name:d.surfaceName,declared_by:DECLARED_BY.code,...owned,overlay_id:d.overlayId??null,url_pattern:urlPattern,intro,parent_surface_name:parent},update:{...owned,...claimed}});for(let v of d.values)values.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:""}:{},name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.groupKey??v.group??"general",...schema?.valueContract?{exportable:resolveSensitivity(v).exportable,classification:resolveSensitivity(v).classification,included_by_default:resolveSensitivity(v).includedByDefault,kind_key:v.valueKind??null,live_slot:v.liveSlot??null,role:v.role??"data"}:{},...provenance});for(let t of d.writeTargets??[])targets.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:t.itemType??""}:{},name:t.name,label:t.label,description:t.description,value_type:t.valueType,mode:t.mode,updates_value:t.updatesValue??null,group_key:t.group??"general",sort_order:t.sortOrder??1e3,apply_policy:t.applyPolicy??"manual",kind_key:t.valueKind??null,...schema?.valueContract?{patchable:t.patchable??!1,approval_comparison:t.approvalComparison??null,stream_ops:t.streamOps?[...t.streamOps]:null,destination:t.destination??!1}:{},...provenance});if(schema?.itemType)for(let[position,item]of(d.itemTypes??[]).entries()){itemTypes.push({...governance,surface_name:d.surfaceName,name:item.name,label:item.label,description:item.description,identity:[...item.identity],levels:item.levels?[...item.levels]:null,entity_type:item.entityType??null,sort_order:position,...provenance});for(let v of item.values)values.push({...governance,surface_name:d.surfaceName,item_type:item.name,name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.group??"general",...provenance})}for(let extension of options.extensions??[])for(let entry of extension.toRows?.(d)??[]){let plan=extensionTables.get(entry.table)??{table:entry.table,conflict:entry.conflict,insertOnly:INSERT_ONLY_COLUMNS,rows:[]};plan.rows.push({...governance,...entry.row,...provenance}),extensionTables.set(entry.table,plan)}}let keys={"ui.ui_surface_value":childKey(schema),"ui.ui_surface_write_target":childKey(schema),...schema?.itemType?{"ui.ui_surface_item_type":["surface_name","name"]}:{},...extensionTables.has(SURFACE_ACTION_TABLE)?{[SURFACE_ACTION_TABLE]:SURFACE_ACTION_KEY}:{}};for(let extension of options.extensions??[])extension.mirror&&(keys[extension.mirror.table]=extension.mirror.conflict);for(let plan of extensionTables.values())keys[plan.table]??=plan.conflict;let tables=[{table:"ui.ui_surface_value",conflict:childKey(schema),insertOnly:INSERT_ONLY_COLUMNS,rows:values},{table:"ui.ui_surface_write_target",conflict:childKey(schema),insertOnly:INSERT_ONLY_COLUMNS,rows:targets},...schema?.itemType?[{table:"ui.ui_surface_item_type",conflict:["surface_name","name"],insertOnly:INSERT_ONLY_COLUMNS,rows:itemTypes}]:[],...extensionTables.values()];return{surfaces,tables:tables.filter(table=>table.rows.length>0),keys}}function mirrorRowKey(row,columns){return columns.map(column=>String(row[column]??"")).join("\0")}function findStaleRows(plan,table,existing){let key=plan.keys[table];if(!key)throw new Error(`Sync plan declares no key for "${table}"; give the extension that owns it a \`mirror\` entry.`);let managed=new Set(plan.surfaces.map(surface=>surface.name)),declared=new Set((plan.tables.find(entry=>entry.table===table)?.rows??[]).map(row=>mirrorRowKey(row,key)));return existing.filter(row=>!isDatabaseDeclared(row)&&managed.has(String(row.surface_name))&&!declared.has(mirrorRowKey(row,key)))}function planColumns(table){let columns=[];for(let row of table.rows)for(let key of Object.keys(row))columns.includes(key)||columns.push(key);return columns}function conflictUpdateColumns(table){return planColumns(table).filter(c=>!table.conflict.includes(c)&&!table.insertOnly.includes(c))}function sqlLiteral(value){return value==null?"NULL":typeof value=="boolean"||typeof value=="number"?String(value):typeof value=="string"?`'${value.replace(/'/g,"''")}'`:Array.isArray(value)&&value.every(entry=>typeof entry=="string")?`ARRAY[${value.map(entry=>sqlLiteral(entry)).join(", ")}]::text[]`:`'${JSON.stringify(value).replace(/'/g,"''")}'::jsonb`}function renderSurfaceSyncStatements(plan){let statements=[];if(plan.surfaces.length>0){let insertColumns=Object.keys(plan.surfaces[0].insert);statements.push(`INSERT INTO ui.ui_surface (${insertColumns.join(", ")}) VALUES
|
|
2
2
|
${plan.surfaces.map(s=>`(${insertColumns.map(c=>sqlLiteral(s.insert[c])).join(", ")})`).join(`,
|
|
3
3
|
`)}
|
|
4
4
|
ON CONFLICT (name) DO NOTHING`);for(let s of plan.surfaces)statements.push(`UPDATE ui.ui_surface SET ${Object.entries(s.update).map(([c,v])=>`${c} = ${sqlLiteral(v)}`).join(", ")}, updated_at = now() WHERE name = ${sqlLiteral(s.name)}`)}for(let table of plan.tables){let columns=planColumns(table),sets=conflictUpdateColumns(table).map(c=>`${c} = EXCLUDED.${c}`);statements.push(`INSERT INTO ${table.table} (${columns.join(", ")}) VALUES
|
package/dist/checks.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/checks.ts","../src/declare/keys.ts","../src/declare/sensitivity.ts","../src/checks/sync.ts","../src/checks/routes.ts"],"sourcesContent":["/**\n * `@ai-matrx/alchemy/checks` — the ONE surface sync (CONTRACT §2.7): the row plan\n * every sync path executes, and its SQL rendering. Pure; no database client.\n */\nexport {\n GOVERNANCE_COLUMNS,\n conflictUpdateColumns,\n findStaleRows,\n mirrorRowKey,\n planColumns,\n planSurfaceSync,\n renderSurfaceSyncSql,\n renderSurfaceSyncStatements,\n sqlLiteral,\n type SurfaceRowPlan,\n type SurfaceSyncPlan,\n type SurfaceSyncPlanOptions,\n type SyncSchema,\n type SyncTablePlan,\n} from \"./checks/sync\";\nexport { findDeadUrlPatterns, routeSegments, urlPatternMatchesRoute } from \"./checks/routes\";\n","import type { QualifiedValueKey } from \"./types\";\n\n/** Every value, write-target, item-type and group name (the DB CHECK rule). */\nexport const DECLARATION_NAME_RE = /^[a-z][a-z0-9_]*$/;\n\n/** \"<client>/<local>\" — the surface naming convention. */\nexport const SURFACE_NAME_RE = /^[a-z][a-z0-9-]*\\/[a-z0-9-/]+$/;\n\n/** A bare screen value (`status`) or an item value (`table_row.status`). */\nexport const QUALIFIED_VALUE_KEY_RE = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)?$/;\n\nexport interface ParsedValueKey {\n /** \"\" for a screen-level value. */\n itemType: string;\n name: string;\n}\n\n/** Split a qualified key; null when it is not a valid bare or qualified key. */\nexport function parseQualifiedValueKey(key: string): ParsedValueKey | null {\n if (!QUALIFIED_VALUE_KEY_RE.test(key)) return null;\n const dot = key.indexOf(\".\");\n if (dot === -1) return { itemType: \"\", name: key };\n return { itemType: key.slice(0, dot), name: key.slice(dot + 1) };\n}\n\nexport function qualifyValueKey(itemType: string, name: string): QualifiedValueKey {\n return itemType ? `${itemType}.${name}` : name;\n}\n\n/** The client that owns a surface: its name prefix. */\nexport function surfaceClientOf(surfaceName: string): string {\n return surfaceName.split(\"/\")[0] ?? \"\";\n}\n","/**\n * Sensitivity defaults and resolution (CONTRACT §2.1). Its own module so the\n * lightweight entries (`/actions`, the T0 React host) can project without\n * pulling the declaration registry.\n */\nimport type { DeclaredValue, Sensitivity } from \"./types\";\n\nexport const DEFAULT_SENSITIVITY: Sensitivity = Object.freeze({\n exportable: true,\n classification: \"ordinary\",\n includedByDefault: true,\n});\n\nexport function resolveSensitivity(value: Pick<DeclaredValue, \"sensitivity\">): Sensitivity {\n return {\n exportable: value.sensitivity?.exportable ?? DEFAULT_SENSITIVITY.exportable,\n classification: value.sensitivity?.classification ?? DEFAULT_SENSITIVITY.classification,\n includedByDefault: value.sensitivity?.includedByDefault ?? DEFAULT_SENSITIVITY.includedByDefault,\n };\n}\n","/**\n * THE ONE SYNC (CONTRACT §2.7 \"One sync path\", chair ruling B1).\n *\n * `planSurfaceSync` maps resolved declarations onto the `ui` mirror rows; every\n * sync path (the SQL emitter and the admin sync service) executes this plan and\n * builds no rows of its own. Governance columns (`organization_id`,\n * `published_to_web`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\n * Mirror rows are published to the web on insert, written explicitly (access ladder\n * T-13: never left to a column default); the database stamps when and by whom.\n *\n * Schema generations: the columns added by the ALC-14 migration (item_type,\n * sensitivity, live slots, content_hash) are emitted only when the caller says\n * that migration is live (`schema`), so no emitter ever writes a column — or\n * upserts against a key — the database does not have yet.\n */\nimport { resolveSensitivity, type Resolved } from \"../declare/registry\";\nimport { surfaceClientOf } from \"../declare/keys\";\nimport type { DeclarationExtension, Json, SurfaceDeclaration } from \"../declare/types\";\n\nexport const GOVERNANCE_COLUMNS = [\"organization_id\", \"published_to_web\"] as const;\n\nexport interface SyncSchema {\n /** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */\n itemType?: boolean;\n /** Sensitivity, kind, live slot and role columns exist on `ui_surface_value`. */\n valueContract?: boolean;\n /** `ui_surface.content_hash` exists. */\n contentHash?: boolean;\n}\n\nexport interface SurfaceSyncPlanOptions<D extends SurfaceDeclaration> {\n organizationId: string;\n syncedFrom: string;\n syncedBy?: string | null;\n /** The address the host derives for a declaration without `urlPattern`. */\n resolveUrlPattern?: (declaration: Resolved<D>) => string | undefined;\n extensions?: readonly DeclarationExtension<D>[];\n schema?: SyncSchema;\n}\n\nexport interface SurfaceRowPlan {\n name: string;\n /** Written only when the row does not exist yet. */\n insert: Record<string, Json>;\n /** Written on every sync (code owns these columns). */\n update: Record<string, Json>;\n}\n\nexport interface SyncTablePlan {\n table: string;\n /** The ON CONFLICT target (a unique index or primary key on exactly these columns). */\n conflict: readonly string[];\n /** Columns set on insert and never on conflict. */\n insertOnly: readonly string[];\n rows: Record<string, Json>[];\n}\n\nexport interface SurfaceSyncPlan {\n surfaces: SurfaceRowPlan[];\n tables: SyncTablePlan[];\n /**\n * The key (ON CONFLICT target) of every mirror table this plan owns,\n * including tables it emits no rows for. Stale detection and deletes use\n * exactly these columns (`findStaleRows`).\n */\n keys: Record<string, readonly string[]>;\n}\n\nfunction childKey(schema: SyncSchema | undefined): readonly string[] {\n return schema?.itemType ? [\"surface_name\", \"item_type\", \"name\"] : [\"surface_name\", \"name\"];\n}\n\nexport function planSurfaceSync<D extends SurfaceDeclaration>(\n declarations: readonly Resolved<D>[],\n options: SurfaceSyncPlanOptions<D>,\n): SurfaceSyncPlan {\n const { organizationId, syncedFrom, schema } = options;\n const syncedBy = options.syncedBy ?? null;\n const provenance = { synced_by: syncedBy, synced_from: syncedFrom };\n const governance = { organization_id: organizationId, published_to_web: true };\n const surfaces: SurfaceRowPlan[] = [];\n const values: Record<string, Json>[] = [];\n const targets: Record<string, Json>[] = [];\n const itemTypes: Record<string, Json>[] = [];\n const extensionTables = new Map<string, SyncTablePlan>();\n\n for (const d of declarations) {\n const urlPattern = d.urlPattern?.trim() || options.resolveUrlPattern?.(d) || null;\n const intro = d.intro?.trim() || null;\n const parent = d.inheritsFrom ?? null;\n const client = surfaceClientOf(d.surfaceName);\n const owned: Record<string, Json> = {\n client_name: client,\n execution_mode: d.executionMode,\n description: d.description,\n label: d.label,\n value_groups: (d.groups ?? []) as unknown as Json,\n readiness: d.readiness,\n readiness_note: d.readinessNote?.trim() || null,\n ...(schema?.contentHash ? { content_hash: d.contentHash } : {}),\n };\n // A declaration that does not claim these never clears a DB-authored value.\n const claimed: Record<string, Json> = {\n ...(d.overlayId ? { overlay_id: d.overlayId } : {}),\n ...(urlPattern ? { url_pattern: urlPattern } : {}),\n ...(intro ? { intro } : {}),\n ...(parent ? { parent_surface_name: parent } : {}),\n };\n surfaces.push({\n name: d.surfaceName,\n insert: {\n name: d.surfaceName,\n ...owned,\n overlay_id: d.overlayId ?? null,\n url_pattern: urlPattern,\n intro,\n parent_surface_name: parent,\n },\n update: { ...owned, ...claimed },\n });\n\n for (const v of d.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: \"\" } : {}),\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.groupKey ?? v.group ?? \"general\",\n ...(schema?.valueContract\n ? {\n exportable: resolveSensitivity(v).exportable,\n classification: resolveSensitivity(v).classification,\n included_by_default: resolveSensitivity(v).includedByDefault,\n kind_key: v.valueKind ?? null,\n live_slot: v.liveSlot ?? null,\n role: v.role ?? \"data\",\n }\n : {}),\n ...provenance,\n });\n }\n\n for (const t of d.writeTargets ?? []) {\n targets.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: t.itemType ?? \"\" } : {}),\n name: t.name,\n label: t.label,\n description: t.description,\n value_type: t.valueType,\n mode: t.mode,\n updates_value: t.updatesValue ?? null,\n group_key: t.group ?? \"general\",\n sort_order: t.sortOrder ?? 1000,\n apply_policy: t.applyPolicy ?? \"manual\",\n kind_key: t.valueKind ?? null,\n ...(schema?.valueContract\n ? {\n patchable: t.patchable ?? false,\n approval_comparison: t.approvalComparison ?? null,\n stream_ops: t.streamOps ? [...t.streamOps] : null,\n destination: t.destination ?? false,\n }\n : {}),\n ...provenance,\n });\n }\n\n if (schema?.itemType) {\n for (const [position, item] of (d.itemTypes ?? []).entries()) {\n itemTypes.push({\n ...governance,\n surface_name: d.surfaceName,\n name: item.name,\n label: item.label,\n description: item.description,\n identity: [...item.identity],\n levels: item.levels ? [...item.levels] : null,\n entity_type: item.entityType ?? null,\n sort_order: position,\n ...provenance,\n });\n for (const v of item.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n item_type: item.name,\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.group ?? \"general\",\n ...provenance,\n });\n }\n }\n }\n\n for (const extension of options.extensions ?? []) {\n for (const entry of extension.toRows?.(d as unknown as D) ?? []) {\n const plan = extensionTables.get(entry.table) ?? {\n table: entry.table,\n conflict: entry.conflict,\n insertOnly: GOVERNANCE_COLUMNS,\n rows: [],\n };\n plan.rows.push({ ...governance, ...entry.row, ...provenance });\n extensionTables.set(entry.table, plan);\n }\n }\n }\n\n const keys: Record<string, readonly string[]> = {\n \"ui.ui_surface_value\": childKey(schema),\n \"ui.ui_surface_write_target\": childKey(schema),\n ...(schema?.itemType ? { \"ui.ui_surface_item_type\": [\"surface_name\", \"name\"] } : {}),\n };\n for (const extension of options.extensions ?? []) {\n if (extension.mirror) keys[extension.mirror.table] = extension.mirror.conflict;\n }\n for (const plan of extensionTables.values()) keys[plan.table] ??= plan.conflict;\n\n const tables: SyncTablePlan[] = [\n { table: \"ui.ui_surface_value\", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: values },\n { table: \"ui.ui_surface_write_target\", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: targets },\n ...(schema?.itemType\n ? [{ table: \"ui.ui_surface_item_type\", conflict: [\"surface_name\", \"name\"], insertOnly: GOVERNANCE_COLUMNS, rows: itemTypes }]\n : []),\n ...extensionTables.values(),\n ];\n return { surfaces, tables: tables.filter((table) => table.rows.length > 0), keys };\n}\n\n/** One row's key under `columns` (a missing column reads as ''). */\nexport function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: readonly string[]): string {\n return columns.map((column) => String(row[column] ?? \"\")).join(\"\\u0000\");\n}\n\n/**\n * Rows of `table` that belong to a surface this plan manages but that the\n * plan no longer declares, judged by the table's full key (`plan.keys`) — so\n * a screen value and an item value that share a name are distinct rows. The\n * caller deletes each returned row filtered by every column of that key.\n */\nexport function findStaleRows<R extends Readonly<Record<string, unknown>>>(\n plan: SurfaceSyncPlan,\n table: string,\n existing: readonly R[],\n): R[] {\n const key = plan.keys[table];\n if (!key) {\n throw new Error(\n `Sync plan declares no key for \"${table}\"; give the extension that owns it a \\`mirror\\` entry.`,\n );\n }\n const managed = new Set(plan.surfaces.map((surface) => surface.name));\n const declared = new Set(\n (plan.tables.find((entry) => entry.table === table)?.rows ?? []).map((row) => mirrorRowKey(row, key)),\n );\n return existing.filter(\n (row) => managed.has(String(row.surface_name)) && !declared.has(mirrorRowKey(row, key)),\n );\n}\n\n/** Every column a table's rows carry, in first-seen order. */\nexport function planColumns(table: SyncTablePlan): string[] {\n const columns: string[] = [];\n for (const row of table.rows) for (const key of Object.keys(row)) if (!columns.includes(key)) columns.push(key);\n return columns;\n}\n\n/** Columns a conflict rewrites: everything except the key and the insert-only set. */\nexport function conflictUpdateColumns(table: SyncTablePlan): string[] {\n return planColumns(table).filter((c) => !table.conflict.includes(c) && !table.insertOnly.includes(c));\n}\n\nexport function sqlLiteral(value: Json | undefined): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"boolean\" || typeof value === \"number\") return String(value);\n if (typeof value === \"string\") return `'${value.replace(/'/g, \"''\")}'`;\n if (Array.isArray(value) && value.every((entry) => typeof entry === \"string\")) {\n return `ARRAY[${value.map((entry) => sqlLiteral(entry)).join(\", \")}]::text[]`;\n }\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'::jsonb`;\n}\n\n/**\n * The plan as SQL statements, one per entry: surface insert, one UPDATE per\n * surface, one upsert per table. Callers may run them, or EXPLAIN each one in a\n * read-only transaction to prove the plan against a live schema with no write.\n */\nexport function renderSurfaceSyncStatements(plan: SurfaceSyncPlan): string[] {\n const statements: string[] = [];\n if (plan.surfaces.length > 0) {\n const insertColumns = Object.keys(plan.surfaces[0]!.insert);\n statements.push(\n `INSERT INTO ui.ui_surface (${insertColumns.join(\", \")}) VALUES\\n${plan.surfaces\n .map((s) => `(${insertColumns.map((c) => sqlLiteral(s.insert[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (name) DO NOTHING`,\n );\n for (const s of plan.surfaces) {\n statements.push(\n `UPDATE ui.ui_surface SET ${Object.entries(s.update)\n .map(([c, v]) => `${c} = ${sqlLiteral(v)}`)\n .join(\", \")}, updated_at = now() WHERE name = ${sqlLiteral(s.name)}`,\n );\n }\n }\n for (const table of plan.tables) {\n const columns = planColumns(table);\n const sets = conflictUpdateColumns(table).map((c) => `${c} = EXCLUDED.${c}`);\n statements.push(\n `INSERT INTO ${table.table} (${columns.join(\", \")}) VALUES\\n${table.rows\n .map((row) => `(${columns.map((c) => sqlLiteral(row[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (${table.conflict.join(\", \")}) DO UPDATE SET ${[...sets, \"updated_at = now()\"].join(\", \")}`,\n );\n }\n return statements;\n}\n\n/** The plan as one SQL script (governance columns insert-only). */\nexport function renderSurfaceSyncSql(plan: SurfaceSyncPlan): string {\n return renderSurfaceSyncStatements(plan)\n .map((statement) => `${statement};`)\n .join(\"\\n\\n\");\n}\n","/**\n * The declaration half of the route check (CONTRACT §2.6 `/checks`): does each\n * declared `urlPattern` address a live route? The host supplies its route list\n * (it owns the filesystem); the matching rule lives here, once. Ported from\n * matrx-frontend `scripts/check-surface-routes.ts` (ALC-14).\n */\n\n/** Route or pattern → segments; `[x]` / `:x` → \"*\", `[...x]` / `[[...x]]` → \"**\". */\nexport function routeSegments(path: string): string[] {\n return (path.split(\"?\")[0] ?? \"\")\n .split(\"#\")[0]!\n .split(\"/\")\n .filter(Boolean)\n .map((segment) => {\n if (/^\\[\\[?\\.\\.\\..+\\]\\]?$/.test(segment)) return \"**\";\n if (segment.startsWith(\"[\") || segment.startsWith(\":\")) return \"*\";\n return segment;\n });\n}\n\n/**\n * Does a declared `urlPattern` address a live route? A literal pattern segment\n * must be a literal route segment — a dynamic route segment does NOT satisfy it,\n * or `/marketing/[brandId]/…` would \"cover\" a retired `/marketing/brands/…`.\n * A trailing `*` makes the pattern a prefix.\n */\nexport function urlPatternMatchesRoute(pattern: string, route: readonly string[]): boolean {\n const isPrefix = pattern.trimEnd().endsWith(\"*\") && !pattern.endsWith(\"]*\");\n const segments = routeSegments(pattern.replace(/\\*+\\s*$/, \"\"));\n for (let i = 0; i < segments.length; i += 1) {\n const routeSegment = route[i];\n if (routeSegment === \"**\") return true;\n if (routeSegment === undefined) return false;\n const declared = segments[i];\n if (declared === \"**\") return true;\n if (declared === \"*\" ? routeSegment !== \"*\" : routeSegment !== declared) return false;\n }\n return isPrefix || route.length === segments.length;\n}\n\n/** Every declaration whose `urlPattern` no live route can produce. */\nexport function findDeadUrlPatterns(\n declarations: readonly { surfaceName: string; urlPattern?: string | undefined }[],\n liveRoutes: readonly string[],\n): { surfaceName: string; urlPattern: string }[] {\n const routes = liveRoutes.map(routeSegments);\n const dead: { surfaceName: string; urlPattern: string }[] = [];\n for (const declaration of declarations) {\n const pattern = declaration.urlPattern;\n if (!pattern) continue;\n if (!routes.some((route) => urlPatternMatchesRoute(pattern, route))) {\n dead.push({ surfaceName: declaration.surfaceName, urlPattern: pattern });\n }\n }\n return dead;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/checks.ts","../src/declare/keys.ts","../src/declare/sensitivity.ts","../src/checks/sync.ts","../src/checks/routes.ts"],"sourcesContent":["/**\n * `@ai-matrx/alchemy/checks` — the ONE surface sync (CONTRACT §2.7): the row plan\n * every sync path executes, and its SQL rendering. Pure; no database client.\n */\nexport {\n DECLARED_BY,\n GOVERNANCE_COLUMNS,\n INSERT_ONLY_COLUMNS,\n SURFACE_ACTION_KEY,\n SURFACE_ACTION_TABLE,\n isDatabaseDeclared,\n type DeclaredBy,\n conflictUpdateColumns,\n findStaleRows,\n mirrorRowKey,\n planColumns,\n planSurfaceSync,\n renderSurfaceSyncSql,\n renderSurfaceSyncStatements,\n sqlLiteral,\n type SurfaceRowPlan,\n type SurfaceSyncPlan,\n type SurfaceSyncPlanOptions,\n type SyncSchema,\n type SyncTablePlan,\n} from \"./checks/sync\";\nexport { findDeadUrlPatterns, routeSegments, urlPatternMatchesRoute } from \"./checks/routes\";\n","import type { QualifiedValueKey } from \"./types\";\n\n/** Every value, write-target, item-type and group name (the DB CHECK rule). */\nexport const DECLARATION_NAME_RE = /^[a-z][a-z0-9_]*$/;\n\n/** \"<client>/<local>\" — the surface naming convention. */\nexport const SURFACE_NAME_RE = /^[a-z][a-z0-9-]*\\/[a-z0-9-/]+$/;\n\n/** A bare screen value (`status`) or an item value (`table_row.status`). */\nexport const QUALIFIED_VALUE_KEY_RE = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)?$/;\n\nexport interface ParsedValueKey {\n /** \"\" for a screen-level value. */\n itemType: string;\n name: string;\n}\n\n/** Split a qualified key; null when it is not a valid bare or qualified key. */\nexport function parseQualifiedValueKey(key: string): ParsedValueKey | null {\n if (!QUALIFIED_VALUE_KEY_RE.test(key)) return null;\n const dot = key.indexOf(\".\");\n if (dot === -1) return { itemType: \"\", name: key };\n return { itemType: key.slice(0, dot), name: key.slice(dot + 1) };\n}\n\nexport function qualifyValueKey(itemType: string, name: string): QualifiedValueKey {\n return itemType ? `${itemType}.${name}` : name;\n}\n\n/** The client that owns a surface: its name prefix. */\nexport function surfaceClientOf(surfaceName: string): string {\n return surfaceName.split(\"/\")[0] ?? \"\";\n}\n","/**\n * Sensitivity defaults and resolution (CONTRACT §2.1). Its own module so the\n * lightweight entries (`/actions`, the T0 React host) can project without\n * pulling the declaration registry.\n */\nimport type { DeclaredValue, Sensitivity } from \"./types\";\n\nexport const DEFAULT_SENSITIVITY: Sensitivity = Object.freeze({\n exportable: true,\n classification: \"ordinary\",\n includedByDefault: true,\n});\n\nexport function resolveSensitivity(value: Pick<DeclaredValue, \"sensitivity\">): Sensitivity {\n return {\n exportable: value.sensitivity?.exportable ?? DEFAULT_SENSITIVITY.exportable,\n classification: value.sensitivity?.classification ?? DEFAULT_SENSITIVITY.classification,\n includedByDefault: value.sensitivity?.includedByDefault ?? DEFAULT_SENSITIVITY.includedByDefault,\n };\n}\n","/**\n * THE ONE SYNC (CONTRACT §2.7 \"One sync path\", chair ruling B1).\n *\n * `planSurfaceSync` maps resolved declarations onto the `ui` mirror rows; every\n * sync path (the SQL emitter and the admin sync service) executes this plan and\n * builds no rows of its own. Governance columns (`organization_id`,\n * `published_to_web`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\n * Mirror rows are published to the web on insert, written explicitly (access ladder\n * T-13: never left to a column default); the database stamps when and by whom.\n *\n * Schema generations: the columns added by the ALC-14 migration (item_type,\n * sensitivity, live slots, content_hash) are emitted only when the caller says\n * that migration is live (`schema`), so no emitter ever writes a column — or\n * upserts against a key — the database does not have yet.\n */\nimport { resolveSensitivity, type Resolved } from \"../declare/registry\";\nimport { surfaceClientOf } from \"../declare/keys\";\nimport type { DeclarationExtension, Json, SurfaceDeclaration } from \"../declare/types\";\n\nexport const GOVERNANCE_COLUMNS = [\"organization_id\", \"published_to_web\"] as const;\n\n/**\n * WHO DECLARED A ROW (Applets CONTRACTS §6, PLAN ruling 7). Every `ui.ui_surface*`\n * row is `declared_by` \"code\" or \"database\". This sync writes only code rows: it\n * stamps \"code\" on insert and never rewrites the column on conflict (a database\n * trigger refuses a code takeover of a database row anyway); stale and orphan\n * checks never return a database row.\n */\nexport const DECLARED_BY = { code: \"code\", database: \"database\" } as const;\nexport type DeclaredBy = (typeof DECLARED_BY)[keyof typeof DECLARED_BY];\n\n/** Set on insert, never on conflict: governance plus `declared_by`. */\nexport const INSERT_ONLY_COLUMNS = [...GOVERNANCE_COLUMNS, \"declared_by\"] as const;\n\n/** The Actions mirror. Always keyed with item_type (the table was born re-keyed). */\nexport const SURFACE_ACTION_TABLE = \"ui.ui_surface_action\";\nexport const SURFACE_ACTION_KEY = [\"surface_name\", \"item_type\", \"name\"] as const;\n\n/** True for a row an organization authored in the database — code sync never touches it. */\nexport function isDatabaseDeclared(row: Readonly<Record<string, unknown>>): boolean {\n return row.declared_by === DECLARED_BY.database;\n}\n\nexport interface SyncSchema {\n /** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */\n itemType?: boolean;\n /** Sensitivity, kind, live slot and role columns exist on `ui_surface_value`. */\n valueContract?: boolean;\n /** `ui_surface.content_hash` exists. */\n contentHash?: boolean;\n}\n\nexport interface SurfaceSyncPlanOptions<D extends SurfaceDeclaration> {\n organizationId: string;\n syncedFrom: string;\n syncedBy?: string | null;\n /** The address the host derives for a declaration without `urlPattern`. */\n resolveUrlPattern?: (declaration: Resolved<D>) => string | undefined;\n extensions?: readonly DeclarationExtension<D>[];\n schema?: SyncSchema;\n}\n\nexport interface SurfaceRowPlan {\n name: string;\n /** Written only when the row does not exist yet. */\n insert: Record<string, Json>;\n /** Written on every sync (code owns these columns). */\n update: Record<string, Json>;\n}\n\nexport interface SyncTablePlan {\n table: string;\n /** The ON CONFLICT target (a unique index or primary key on exactly these columns). */\n conflict: readonly string[];\n /** Columns set on insert and never on conflict. */\n insertOnly: readonly string[];\n rows: Record<string, Json>[];\n}\n\nexport interface SurfaceSyncPlan {\n surfaces: SurfaceRowPlan[];\n tables: SyncTablePlan[];\n /**\n * The key (ON CONFLICT target) of every mirror table this plan owns,\n * including tables it emits no rows for. Stale detection and deletes use\n * exactly these columns (`findStaleRows`).\n */\n keys: Record<string, readonly string[]>;\n}\n\nfunction childKey(schema: SyncSchema | undefined): readonly string[] {\n return schema?.itemType ? [\"surface_name\", \"item_type\", \"name\"] : [\"surface_name\", \"name\"];\n}\n\nexport function planSurfaceSync<D extends SurfaceDeclaration>(\n declarations: readonly Resolved<D>[],\n options: SurfaceSyncPlanOptions<D>,\n): SurfaceSyncPlan {\n const { organizationId, syncedFrom, schema } = options;\n const syncedBy = options.syncedBy ?? null;\n const provenance = { synced_by: syncedBy, synced_from: syncedFrom };\n const governance = { organization_id: organizationId, published_to_web: true, declared_by: DECLARED_BY.code };\n const surfaces: SurfaceRowPlan[] = [];\n const values: Record<string, Json>[] = [];\n const targets: Record<string, Json>[] = [];\n const itemTypes: Record<string, Json>[] = [];\n const extensionTables = new Map<string, SyncTablePlan>();\n\n for (const d of declarations) {\n const urlPattern = d.urlPattern?.trim() || options.resolveUrlPattern?.(d) || null;\n const intro = d.intro?.trim() || null;\n const parent = d.inheritsFrom ?? null;\n const client = surfaceClientOf(d.surfaceName);\n const owned: Record<string, Json> = {\n client_name: client,\n execution_mode: d.executionMode,\n description: d.description,\n label: d.label,\n value_groups: (d.groups ?? []) as unknown as Json,\n readiness: d.readiness,\n readiness_note: d.readinessNote?.trim() || null,\n ...(schema?.contentHash ? { content_hash: d.contentHash } : {}),\n };\n // A declaration that does not claim these never clears a DB-authored value.\n const claimed: Record<string, Json> = {\n ...(d.overlayId ? { overlay_id: d.overlayId } : {}),\n ...(urlPattern ? { url_pattern: urlPattern } : {}),\n ...(intro ? { intro } : {}),\n ...(parent ? { parent_surface_name: parent } : {}),\n };\n surfaces.push({\n name: d.surfaceName,\n insert: {\n name: d.surfaceName,\n declared_by: DECLARED_BY.code,\n ...owned,\n overlay_id: d.overlayId ?? null,\n url_pattern: urlPattern,\n intro,\n parent_surface_name: parent,\n },\n update: { ...owned, ...claimed },\n });\n\n for (const v of d.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: \"\" } : {}),\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.groupKey ?? v.group ?? \"general\",\n ...(schema?.valueContract\n ? {\n exportable: resolveSensitivity(v).exportable,\n classification: resolveSensitivity(v).classification,\n included_by_default: resolveSensitivity(v).includedByDefault,\n kind_key: v.valueKind ?? null,\n live_slot: v.liveSlot ?? null,\n role: v.role ?? \"data\",\n }\n : {}),\n ...provenance,\n });\n }\n\n for (const t of d.writeTargets ?? []) {\n targets.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: t.itemType ?? \"\" } : {}),\n name: t.name,\n label: t.label,\n description: t.description,\n value_type: t.valueType,\n mode: t.mode,\n updates_value: t.updatesValue ?? null,\n group_key: t.group ?? \"general\",\n sort_order: t.sortOrder ?? 1000,\n apply_policy: t.applyPolicy ?? \"manual\",\n kind_key: t.valueKind ?? null,\n ...(schema?.valueContract\n ? {\n patchable: t.patchable ?? false,\n approval_comparison: t.approvalComparison ?? null,\n stream_ops: t.streamOps ? [...t.streamOps] : null,\n destination: t.destination ?? false,\n }\n : {}),\n ...provenance,\n });\n }\n\n if (schema?.itemType) {\n for (const [position, item] of (d.itemTypes ?? []).entries()) {\n itemTypes.push({\n ...governance,\n surface_name: d.surfaceName,\n name: item.name,\n label: item.label,\n description: item.description,\n identity: [...item.identity],\n levels: item.levels ? [...item.levels] : null,\n entity_type: item.entityType ?? null,\n sort_order: position,\n ...provenance,\n });\n for (const v of item.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n item_type: item.name,\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.group ?? \"general\",\n ...provenance,\n });\n }\n }\n }\n\n for (const extension of options.extensions ?? []) {\n for (const entry of extension.toRows?.(d as unknown as D) ?? []) {\n const plan = extensionTables.get(entry.table) ?? {\n table: entry.table,\n conflict: entry.conflict,\n insertOnly: INSERT_ONLY_COLUMNS,\n rows: [],\n };\n plan.rows.push({ ...governance, ...entry.row, ...provenance });\n extensionTables.set(entry.table, plan);\n }\n }\n }\n\n const keys: Record<string, readonly string[]> = {\n \"ui.ui_surface_value\": childKey(schema),\n \"ui.ui_surface_write_target\": childKey(schema),\n ...(schema?.itemType ? { \"ui.ui_surface_item_type\": [\"surface_name\", \"name\"] } : {}),\n // ui.ui_surface_action is claimed ONLY when a code declaration emits Action rows: until code\n // declares Actions, every live Action row is database-owned, and claiming the table would read\n // a future code Action as stale. Unclaimed, a stale check on it throws by name instead.\n ...(extensionTables.has(SURFACE_ACTION_TABLE) ? { [SURFACE_ACTION_TABLE]: SURFACE_ACTION_KEY } : {}),\n };\n for (const extension of options.extensions ?? []) {\n if (extension.mirror) keys[extension.mirror.table] = extension.mirror.conflict;\n }\n for (const plan of extensionTables.values()) keys[plan.table] ??= plan.conflict;\n\n const tables: SyncTablePlan[] = [\n { table: \"ui.ui_surface_value\", conflict: childKey(schema), insertOnly: INSERT_ONLY_COLUMNS, rows: values },\n { table: \"ui.ui_surface_write_target\", conflict: childKey(schema), insertOnly: INSERT_ONLY_COLUMNS, rows: targets },\n ...(schema?.itemType\n ? [{ table: \"ui.ui_surface_item_type\", conflict: [\"surface_name\", \"name\"], insertOnly: INSERT_ONLY_COLUMNS, rows: itemTypes }]\n : []),\n ...extensionTables.values(),\n ];\n return { surfaces, tables: tables.filter((table) => table.rows.length > 0), keys };\n}\n\n/** One row's key under `columns` (a missing column reads as ''). */\nexport function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: readonly string[]): string {\n return columns.map((column) => String(row[column] ?? \"\")).join(\"\\u0000\");\n}\n\n/**\n * Rows of `table` that belong to a surface this plan manages but that the\n * plan no longer declares, judged by the table's full key (`plan.keys`) — so\n * a screen value and an item value that share a name are distinct rows. The\n * caller deletes each returned row filtered by every column of that key.\n * A row whose `declared_by` is \"database\" is never returned (pass the column\n * in `existing`, and delete with `declared_by = 'code'` as well).\n */\nexport function findStaleRows<R extends Readonly<Record<string, unknown>>>(\n plan: SurfaceSyncPlan,\n table: string,\n existing: readonly R[],\n): R[] {\n const key = plan.keys[table];\n if (!key) {\n throw new Error(\n `Sync plan declares no key for \"${table}\"; give the extension that owns it a \\`mirror\\` entry.`,\n );\n }\n const managed = new Set(plan.surfaces.map((surface) => surface.name));\n const declared = new Set(\n (plan.tables.find((entry) => entry.table === table)?.rows ?? []).map((row) => mirrorRowKey(row, key)),\n );\n return existing.filter(\n (row) => !isDatabaseDeclared(row) && managed.has(String(row.surface_name)) && !declared.has(mirrorRowKey(row, key)),\n );\n}\n\n/** Every column a table's rows carry, in first-seen order. */\nexport function planColumns(table: SyncTablePlan): string[] {\n const columns: string[] = [];\n for (const row of table.rows) for (const key of Object.keys(row)) if (!columns.includes(key)) columns.push(key);\n return columns;\n}\n\n/** Columns a conflict rewrites: everything except the key and the insert-only set. */\nexport function conflictUpdateColumns(table: SyncTablePlan): string[] {\n return planColumns(table).filter((c) => !table.conflict.includes(c) && !table.insertOnly.includes(c));\n}\n\nexport function sqlLiteral(value: Json | undefined): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"boolean\" || typeof value === \"number\") return String(value);\n if (typeof value === \"string\") return `'${value.replace(/'/g, \"''\")}'`;\n if (Array.isArray(value) && value.every((entry) => typeof entry === \"string\")) {\n return `ARRAY[${value.map((entry) => sqlLiteral(entry)).join(\", \")}]::text[]`;\n }\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'::jsonb`;\n}\n\n/**\n * The plan as SQL statements, one per entry: surface insert, one UPDATE per\n * surface, one upsert per table. Callers may run them, or EXPLAIN each one in a\n * read-only transaction to prove the plan against a live schema with no write.\n */\nexport function renderSurfaceSyncStatements(plan: SurfaceSyncPlan): string[] {\n const statements: string[] = [];\n if (plan.surfaces.length > 0) {\n const insertColumns = Object.keys(plan.surfaces[0]!.insert);\n statements.push(\n `INSERT INTO ui.ui_surface (${insertColumns.join(\", \")}) VALUES\\n${plan.surfaces\n .map((s) => `(${insertColumns.map((c) => sqlLiteral(s.insert[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (name) DO NOTHING`,\n );\n for (const s of plan.surfaces) {\n statements.push(\n `UPDATE ui.ui_surface SET ${Object.entries(s.update)\n .map(([c, v]) => `${c} = ${sqlLiteral(v)}`)\n .join(\", \")}, updated_at = now() WHERE name = ${sqlLiteral(s.name)}`,\n );\n }\n }\n for (const table of plan.tables) {\n const columns = planColumns(table);\n const sets = conflictUpdateColumns(table).map((c) => `${c} = EXCLUDED.${c}`);\n statements.push(\n `INSERT INTO ${table.table} (${columns.join(\", \")}) VALUES\\n${table.rows\n .map((row) => `(${columns.map((c) => sqlLiteral(row[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (${table.conflict.join(\", \")}) DO UPDATE SET ${[...sets, \"updated_at = now()\"].join(\", \")}`,\n );\n }\n return statements;\n}\n\n/** The plan as one SQL script (governance columns insert-only). */\nexport function renderSurfaceSyncSql(plan: SurfaceSyncPlan): string {\n return renderSurfaceSyncStatements(plan)\n .map((statement) => `${statement};`)\n .join(\"\\n\\n\");\n}\n","/**\n * The declaration half of the route check (CONTRACT §2.6 `/checks`): does each\n * declared `urlPattern` address a live route? The host supplies its route list\n * (it owns the filesystem); the matching rule lives here, once. Ported from\n * matrx-frontend `scripts/check-surface-routes.ts` (ALC-14).\n */\n\n/** Route or pattern → segments; `[x]` / `:x` → \"*\", `[...x]` / `[[...x]]` → \"**\". */\nexport function routeSegments(path: string): string[] {\n return (path.split(\"?\")[0] ?? \"\")\n .split(\"#\")[0]!\n .split(\"/\")\n .filter(Boolean)\n .map((segment) => {\n if (/^\\[\\[?\\.\\.\\..+\\]\\]?$/.test(segment)) return \"**\";\n if (segment.startsWith(\"[\") || segment.startsWith(\":\")) return \"*\";\n return segment;\n });\n}\n\n/**\n * Does a declared `urlPattern` address a live route? A literal pattern segment\n * must be a literal route segment — a dynamic route segment does NOT satisfy it,\n * or `/marketing/[brandId]/…` would \"cover\" a retired `/marketing/brands/…`.\n * A trailing `*` makes the pattern a prefix.\n */\nexport function urlPatternMatchesRoute(pattern: string, route: readonly string[]): boolean {\n const isPrefix = pattern.trimEnd().endsWith(\"*\") && !pattern.endsWith(\"]*\");\n const segments = routeSegments(pattern.replace(/\\*+\\s*$/, \"\"));\n for (let i = 0; i < segments.length; i += 1) {\n const routeSegment = route[i];\n if (routeSegment === \"**\") return true;\n if (routeSegment === undefined) return false;\n const declared = segments[i];\n if (declared === \"**\") return true;\n if (declared === \"*\" ? routeSegment !== \"*\" : routeSegment !== declared) return false;\n }\n return isPrefix || route.length === segments.length;\n}\n\n/** Every declaration whose `urlPattern` no live route can produce. */\nexport function findDeadUrlPatterns(\n declarations: readonly { surfaceName: string; urlPattern?: string | undefined }[],\n liveRoutes: readonly string[],\n): { surfaceName: string; urlPattern: string }[] {\n const routes = liveRoutes.map(routeSegments);\n const dead: { surfaceName: string; urlPattern: string }[] = [];\n for (const declaration of declarations) {\n const pattern = declaration.urlPattern;\n if (!pattern) continue;\n if (!routes.some((route) => urlPatternMatchesRoute(pattern, route))) {\n dead.push({ surfaceName: declaration.surfaceName, urlPattern: pattern });\n }\n }\n return dead;\n}\n"],"mappings":"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","names":[]}
|
package/dist/checks.d.cts
CHANGED
|
@@ -215,6 +215,25 @@ type Resolved<D extends SurfaceDeclaration> = Omit<D, "values" | "groups"> & {
|
|
|
215
215
|
*/
|
|
216
216
|
|
|
217
217
|
declare const GOVERNANCE_COLUMNS: readonly ["organization_id", "published_to_web"];
|
|
218
|
+
/**
|
|
219
|
+
* WHO DECLARED A ROW (Applets CONTRACTS §6, PLAN ruling 7). Every `ui.ui_surface*`
|
|
220
|
+
* row is `declared_by` "code" or "database". This sync writes only code rows: it
|
|
221
|
+
* stamps "code" on insert and never rewrites the column on conflict (a database
|
|
222
|
+
* trigger refuses a code takeover of a database row anyway); stale and orphan
|
|
223
|
+
* checks never return a database row.
|
|
224
|
+
*/
|
|
225
|
+
declare const DECLARED_BY: {
|
|
226
|
+
readonly code: "code";
|
|
227
|
+
readonly database: "database";
|
|
228
|
+
};
|
|
229
|
+
type DeclaredBy = (typeof DECLARED_BY)[keyof typeof DECLARED_BY];
|
|
230
|
+
/** Set on insert, never on conflict: governance plus `declared_by`. */
|
|
231
|
+
declare const INSERT_ONLY_COLUMNS: readonly ["organization_id", "published_to_web", "declared_by"];
|
|
232
|
+
/** The Actions mirror. Always keyed with item_type (the table was born re-keyed). */
|
|
233
|
+
declare const SURFACE_ACTION_TABLE = "ui.ui_surface_action";
|
|
234
|
+
declare const SURFACE_ACTION_KEY: readonly ["surface_name", "item_type", "name"];
|
|
235
|
+
/** True for a row an organization authored in the database — code sync never touches it. */
|
|
236
|
+
declare function isDatabaseDeclared(row: Readonly<Record<string, unknown>>): boolean;
|
|
218
237
|
interface SyncSchema {
|
|
219
238
|
/** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */
|
|
220
239
|
itemType?: boolean;
|
|
@@ -265,6 +284,8 @@ declare function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: r
|
|
|
265
284
|
* plan no longer declares, judged by the table's full key (`plan.keys`) — so
|
|
266
285
|
* a screen value and an item value that share a name are distinct rows. The
|
|
267
286
|
* caller deletes each returned row filtered by every column of that key.
|
|
287
|
+
* A row whose `declared_by` is "database" is never returned (pass the column
|
|
288
|
+
* in `existing`, and delete with `declared_by = 'code'` as well).
|
|
268
289
|
*/
|
|
269
290
|
declare function findStaleRows<R extends Readonly<Record<string, unknown>>>(plan: SurfaceSyncPlan, table: string, existing: readonly R[]): R[];
|
|
270
291
|
/** Every column a table's rows carry, in first-seen order. */
|
|
@@ -305,4 +326,4 @@ declare function findDeadUrlPatterns(declarations: readonly {
|
|
|
305
326
|
urlPattern: string;
|
|
306
327
|
}[];
|
|
307
328
|
|
|
308
|
-
export { GOVERNANCE_COLUMNS, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, findStaleRows, mirrorRowKey, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
|
|
329
|
+
export { DECLARED_BY, type DeclaredBy, GOVERNANCE_COLUMNS, INSERT_ONLY_COLUMNS, SURFACE_ACTION_KEY, SURFACE_ACTION_TABLE, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, findStaleRows, isDatabaseDeclared, mirrorRowKey, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
|
package/dist/checks.d.ts
CHANGED
|
@@ -215,6 +215,25 @@ type Resolved<D extends SurfaceDeclaration> = Omit<D, "values" | "groups"> & {
|
|
|
215
215
|
*/
|
|
216
216
|
|
|
217
217
|
declare const GOVERNANCE_COLUMNS: readonly ["organization_id", "published_to_web"];
|
|
218
|
+
/**
|
|
219
|
+
* WHO DECLARED A ROW (Applets CONTRACTS §6, PLAN ruling 7). Every `ui.ui_surface*`
|
|
220
|
+
* row is `declared_by` "code" or "database". This sync writes only code rows: it
|
|
221
|
+
* stamps "code" on insert and never rewrites the column on conflict (a database
|
|
222
|
+
* trigger refuses a code takeover of a database row anyway); stale and orphan
|
|
223
|
+
* checks never return a database row.
|
|
224
|
+
*/
|
|
225
|
+
declare const DECLARED_BY: {
|
|
226
|
+
readonly code: "code";
|
|
227
|
+
readonly database: "database";
|
|
228
|
+
};
|
|
229
|
+
type DeclaredBy = (typeof DECLARED_BY)[keyof typeof DECLARED_BY];
|
|
230
|
+
/** Set on insert, never on conflict: governance plus `declared_by`. */
|
|
231
|
+
declare const INSERT_ONLY_COLUMNS: readonly ["organization_id", "published_to_web", "declared_by"];
|
|
232
|
+
/** The Actions mirror. Always keyed with item_type (the table was born re-keyed). */
|
|
233
|
+
declare const SURFACE_ACTION_TABLE = "ui.ui_surface_action";
|
|
234
|
+
declare const SURFACE_ACTION_KEY: readonly ["surface_name", "item_type", "name"];
|
|
235
|
+
/** True for a row an organization authored in the database — code sync never touches it. */
|
|
236
|
+
declare function isDatabaseDeclared(row: Readonly<Record<string, unknown>>): boolean;
|
|
218
237
|
interface SyncSchema {
|
|
219
238
|
/** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */
|
|
220
239
|
itemType?: boolean;
|
|
@@ -265,6 +284,8 @@ declare function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: r
|
|
|
265
284
|
* plan no longer declares, judged by the table's full key (`plan.keys`) — so
|
|
266
285
|
* a screen value and an item value that share a name are distinct rows. The
|
|
267
286
|
* caller deletes each returned row filtered by every column of that key.
|
|
287
|
+
* A row whose `declared_by` is "database" is never returned (pass the column
|
|
288
|
+
* in `existing`, and delete with `declared_by = 'code'` as well).
|
|
268
289
|
*/
|
|
269
290
|
declare function findStaleRows<R extends Readonly<Record<string, unknown>>>(plan: SurfaceSyncPlan, table: string, existing: readonly R[]): R[];
|
|
270
291
|
/** Every column a table's rows carry, in first-seen order. */
|
|
@@ -305,4 +326,4 @@ declare function findDeadUrlPatterns(declarations: readonly {
|
|
|
305
326
|
urlPattern: string;
|
|
306
327
|
}[];
|
|
307
328
|
|
|
308
|
-
export { GOVERNANCE_COLUMNS, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, findStaleRows, mirrorRowKey, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
|
|
329
|
+
export { DECLARED_BY, type DeclaredBy, GOVERNANCE_COLUMNS, INSERT_ONLY_COLUMNS, SURFACE_ACTION_KEY, SURFACE_ACTION_TABLE, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, findStaleRows, isDatabaseDeclared, mirrorRowKey, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
|