@ai-matrx/alchemy 0.6.2 → 0.8.2

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.
Files changed (113) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/actions.cjs +374 -0
  3. package/dist/actions.cjs.map +1 -0
  4. package/dist/actions.d.cts +773 -0
  5. package/dist/actions.d.ts +773 -0
  6. package/dist/actions.js +351 -0
  7. package/dist/actions.js.map +1 -0
  8. package/dist/checks.cjs +31 -2
  9. package/dist/checks.cjs.map +1 -1
  10. package/dist/checks.d.cts +24 -1
  11. package/dist/checks.d.ts +24 -1
  12. package/dist/checks.js +31 -2
  13. package/dist/checks.js.map +1 -1
  14. package/dist/core.cjs +1757 -2
  15. package/dist/core.cjs.map +1 -1
  16. package/dist/core.d.cts +595 -1
  17. package/dist/core.d.ts +595 -1
  18. package/dist/core.js +1749 -2
  19. package/dist/core.js.map +1 -1
  20. package/dist/declare.cjs +12 -10
  21. package/dist/declare.cjs.map +1 -1
  22. package/dist/declare.d.cts +18 -2
  23. package/dist/declare.d.ts +18 -2
  24. package/dist/declare.js +12 -10
  25. package/dist/declare.js.map +1 -1
  26. package/dist/index.cjs +1757 -2
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +595 -1
  29. package/dist/index.d.ts +595 -1
  30. package/dist/index.js +1749 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/menu.cjs +436 -0
  33. package/dist/menu.cjs.map +1 -0
  34. package/dist/menu.d.cts +834 -0
  35. package/dist/menu.d.ts +834 -0
  36. package/dist/menu.js +413 -0
  37. package/dist/menu.js.map +1 -0
  38. package/dist/operate-document.cjs +163 -0
  39. package/dist/operate-document.cjs.map +1 -0
  40. package/dist/operate-document.d.cts +132 -0
  41. package/dist/operate-document.d.ts +132 -0
  42. package/dist/operate-document.js +130 -0
  43. package/dist/operate-document.js.map +1 -0
  44. package/dist/operate-rich-html.cjs +129 -0
  45. package/dist/operate-rich-html.cjs.map +1 -0
  46. package/dist/operate-rich-html.d.cts +136 -0
  47. package/dist/operate-rich-html.d.ts +136 -0
  48. package/dist/operate-rich-html.js +96 -0
  49. package/dist/operate-rich-html.js.map +1 -0
  50. package/dist/operate-server.cjs +157 -0
  51. package/dist/operate-server.cjs.map +1 -0
  52. package/dist/operate-server.d.cts +183 -0
  53. package/dist/operate-server.d.ts +183 -0
  54. package/dist/operate-server.js +134 -0
  55. package/dist/operate-server.js.map +1 -0
  56. package/dist/operate-xlsx.cjs +248 -0
  57. package/dist/operate-xlsx.cjs.map +1 -0
  58. package/dist/operate-xlsx.d.cts +129 -0
  59. package/dist/operate-xlsx.d.ts +129 -0
  60. package/dist/operate-xlsx.js +215 -0
  61. package/dist/operate-xlsx.js.map +1 -0
  62. package/dist/operate.cjs +1774 -0
  63. package/dist/operate.cjs.map +1 -0
  64. package/dist/operate.d.cts +595 -0
  65. package/dist/operate.d.ts +595 -0
  66. package/dist/operate.js +1750 -0
  67. package/dist/operate.js.map +1 -0
  68. package/dist/ports.cjs.map +1 -1
  69. package/dist/ports.d.cts +361 -3
  70. package/dist/ports.d.ts +361 -3
  71. package/dist/react-bar.cjs +686 -0
  72. package/dist/react-bar.cjs.map +1 -0
  73. package/dist/react-bar.d.cts +379 -0
  74. package/dist/react-bar.d.ts +379 -0
  75. package/dist/react-bar.js +665 -0
  76. package/dist/react-bar.js.map +1 -0
  77. package/dist/react-host.cjs +301 -0
  78. package/dist/react-host.cjs.map +1 -0
  79. package/dist/react-host.d.cts +820 -0
  80. package/dist/react-host.d.ts +820 -0
  81. package/dist/react-host.js +269 -0
  82. package/dist/react-host.js.map +1 -0
  83. package/dist/react-menu.cjs +735 -0
  84. package/dist/react-menu.cjs.map +1 -0
  85. package/dist/react-menu.d.cts +370 -0
  86. package/dist/react-menu.d.ts +370 -0
  87. package/dist/react-menu.js +722 -0
  88. package/dist/react-menu.js.map +1 -0
  89. package/dist/react-overflow.cjs +592 -0
  90. package/dist/react-overflow.cjs.map +1 -0
  91. package/dist/react-overflow.d.cts +817 -0
  92. package/dist/react-overflow.d.ts +817 -0
  93. package/dist/react-overflow.js +571 -0
  94. package/dist/react-overflow.js.map +1 -0
  95. package/dist/react-palette.cjs +489 -0
  96. package/dist/react-palette.cjs.map +1 -0
  97. package/dist/react-palette.d.cts +359 -0
  98. package/dist/react-palette.d.ts +359 -0
  99. package/dist/react-palette.js +457 -0
  100. package/dist/react-palette.js.map +1 -0
  101. package/dist/react-selection.cjs +617 -0
  102. package/dist/react-selection.cjs.map +1 -0
  103. package/dist/react-selection.d.cts +357 -0
  104. package/dist/react-selection.d.ts +357 -0
  105. package/dist/react-selection.js +596 -0
  106. package/dist/react-selection.js.map +1 -0
  107. package/dist/react-sheet.cjs +616 -0
  108. package/dist/react-sheet.cjs.map +1 -0
  109. package/dist/react-sheet.d.cts +361 -0
  110. package/dist/react-sheet.d.ts +361 -0
  111. package/dist/react-sheet.js +595 -0
  112. package/dist/react-sheet.js.map +1 -0
  113. package/package.json +148 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/checks.ts","../src/declare/keys.ts","../src/declare/registry.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 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 * 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\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\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 * 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 * `visibility`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\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\", \"visibility\"] 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\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, visibility: \"public\" };\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 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) };\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 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 * `visibility`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\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\", \"visibility\"] 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, visibility: \"public\" };\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":[]}
package/dist/checks.d.cts CHANGED
@@ -159,6 +159,14 @@ interface DeclarationExtension<D extends SurfaceDeclaration = SurfaceDeclaration
159
159
  }[];
160
160
  validate?(declaration: D, context: ValidationContext): readonly DeclarationIssue[];
161
161
  toRows?(declaration: D): readonly ExtensionRow[];
162
+ /**
163
+ * The mirror table this slot's rows live in and its key, so the sync can
164
+ * judge stale rows even when no declaration contributes a row.
165
+ */
166
+ mirror?: {
167
+ table: string;
168
+ conflict: readonly string[];
169
+ };
162
170
  }
163
171
  interface ValidationContext {
164
172
  /** Every registered declaration, resolved. */
@@ -240,8 +248,23 @@ interface SyncTablePlan {
240
248
  interface SurfaceSyncPlan {
241
249
  surfaces: SurfaceRowPlan[];
242
250
  tables: SyncTablePlan[];
251
+ /**
252
+ * The key (ON CONFLICT target) of every mirror table this plan owns,
253
+ * including tables it emits no rows for. Stale detection and deletes use
254
+ * exactly these columns (`findStaleRows`).
255
+ */
256
+ keys: Record<string, readonly string[]>;
243
257
  }
244
258
  declare function planSurfaceSync<D extends SurfaceDeclaration>(declarations: readonly Resolved<D>[], options: SurfaceSyncPlanOptions<D>): SurfaceSyncPlan;
259
+ /** One row's key under `columns` (a missing column reads as ''). */
260
+ declare function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: readonly string[]): string;
261
+ /**
262
+ * Rows of `table` that belong to a surface this plan manages but that the
263
+ * plan no longer declares, judged by the table's full key (`plan.keys`) — so
264
+ * a screen value and an item value that share a name are distinct rows. The
265
+ * caller deletes each returned row filtered by every column of that key.
266
+ */
267
+ declare function findStaleRows<R extends Readonly<Record<string, unknown>>>(plan: SurfaceSyncPlan, table: string, existing: readonly R[]): R[];
245
268
  /** Every column a table's rows carry, in first-seen order. */
246
269
  declare function planColumns(table: SyncTablePlan): string[];
247
270
  /** Columns a conflict rewrites: everything except the key and the insert-only set. */
@@ -280,4 +303,4 @@ declare function findDeadUrlPatterns(declarations: readonly {
280
303
  urlPattern: string;
281
304
  }[];
282
305
 
283
- export { GOVERNANCE_COLUMNS, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
306
+ export { GOVERNANCE_COLUMNS, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, findStaleRows, mirrorRowKey, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
package/dist/checks.d.ts CHANGED
@@ -159,6 +159,14 @@ interface DeclarationExtension<D extends SurfaceDeclaration = SurfaceDeclaration
159
159
  }[];
160
160
  validate?(declaration: D, context: ValidationContext): readonly DeclarationIssue[];
161
161
  toRows?(declaration: D): readonly ExtensionRow[];
162
+ /**
163
+ * The mirror table this slot's rows live in and its key, so the sync can
164
+ * judge stale rows even when no declaration contributes a row.
165
+ */
166
+ mirror?: {
167
+ table: string;
168
+ conflict: readonly string[];
169
+ };
162
170
  }
163
171
  interface ValidationContext {
164
172
  /** Every registered declaration, resolved. */
@@ -240,8 +248,23 @@ interface SyncTablePlan {
240
248
  interface SurfaceSyncPlan {
241
249
  surfaces: SurfaceRowPlan[];
242
250
  tables: SyncTablePlan[];
251
+ /**
252
+ * The key (ON CONFLICT target) of every mirror table this plan owns,
253
+ * including tables it emits no rows for. Stale detection and deletes use
254
+ * exactly these columns (`findStaleRows`).
255
+ */
256
+ keys: Record<string, readonly string[]>;
243
257
  }
244
258
  declare function planSurfaceSync<D extends SurfaceDeclaration>(declarations: readonly Resolved<D>[], options: SurfaceSyncPlanOptions<D>): SurfaceSyncPlan;
259
+ /** One row's key under `columns` (a missing column reads as ''). */
260
+ declare function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: readonly string[]): string;
261
+ /**
262
+ * Rows of `table` that belong to a surface this plan manages but that the
263
+ * plan no longer declares, judged by the table's full key (`plan.keys`) — so
264
+ * a screen value and an item value that share a name are distinct rows. The
265
+ * caller deletes each returned row filtered by every column of that key.
266
+ */
267
+ declare function findStaleRows<R extends Readonly<Record<string, unknown>>>(plan: SurfaceSyncPlan, table: string, existing: readonly R[]): R[];
245
268
  /** Every column a table's rows carry, in first-seen order. */
246
269
  declare function planColumns(table: SyncTablePlan): string[];
247
270
  /** Columns a conflict rewrites: everything except the key and the insert-only set. */
@@ -280,4 +303,4 @@ declare function findDeadUrlPatterns(declarations: readonly {
280
303
  urlPattern: string;
281
304
  }[];
282
305
 
283
- export { GOVERNANCE_COLUMNS, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
306
+ export { GOVERNANCE_COLUMNS, type SurfaceRowPlan, type SurfaceSyncPlan, type SurfaceSyncPlanOptions, type SyncSchema, type SyncTablePlan, conflictUpdateColumns, findDeadUrlPatterns, findStaleRows, mirrorRowKey, planColumns, planSurfaceSync, renderSurfaceSyncSql, renderSurfaceSyncStatements, routeSegments, sqlLiteral, urlPatternMatchesRoute };
package/dist/checks.js CHANGED
@@ -3,7 +3,7 @@ function surfaceClientOf(surfaceName) {
3
3
  return surfaceName.split("/")[0] ?? "";
4
4
  }
5
5
 
6
- // src/declare/registry.ts
6
+ // src/declare/sensitivity.ts
7
7
  var DEFAULT_SENSITIVITY = Object.freeze({
8
8
  exportable: true,
9
9
  classification: "ordinary",
@@ -160,13 +160,40 @@ function planSurfaceSync(declarations, options) {
160
160
  }
161
161
  }
162
162
  }
163
+ const keys = {
164
+ "ui.ui_surface_value": childKey(schema),
165
+ "ui.ui_surface_write_target": childKey(schema),
166
+ ...schema?.itemType ? { "ui.ui_surface_item_type": ["surface_name", "name"] } : {}
167
+ };
168
+ for (const extension of options.extensions ?? []) {
169
+ if (extension.mirror) keys[extension.mirror.table] = extension.mirror.conflict;
170
+ }
171
+ for (const plan of extensionTables.values()) keys[plan.table] ??= plan.conflict;
163
172
  const tables = [
164
173
  { table: "ui.ui_surface_value", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: values },
165
174
  { table: "ui.ui_surface_write_target", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: targets },
166
175
  ...schema?.itemType ? [{ table: "ui.ui_surface_item_type", conflict: ["surface_name", "name"], insertOnly: GOVERNANCE_COLUMNS, rows: itemTypes }] : [],
167
176
  ...extensionTables.values()
168
177
  ];
169
- return { surfaces, tables: tables.filter((table) => table.rows.length > 0) };
178
+ return { surfaces, tables: tables.filter((table) => table.rows.length > 0), keys };
179
+ }
180
+ function mirrorRowKey(row, columns) {
181
+ return columns.map((column) => String(row[column] ?? "")).join("\0");
182
+ }
183
+ function findStaleRows(plan, table, existing) {
184
+ const key = plan.keys[table];
185
+ if (!key) {
186
+ throw new Error(
187
+ `Sync plan declares no key for "${table}"; give the extension that owns it a \`mirror\` entry.`
188
+ );
189
+ }
190
+ const managed = new Set(plan.surfaces.map((surface) => surface.name));
191
+ const declared = new Set(
192
+ (plan.tables.find((entry) => entry.table === table)?.rows ?? []).map((row) => mirrorRowKey(row, key))
193
+ );
194
+ return existing.filter(
195
+ (row) => managed.has(String(row.surface_name)) && !declared.has(mirrorRowKey(row, key))
196
+ );
170
197
  }
171
198
  function planColumns(table) {
172
199
  const columns = [];
@@ -252,6 +279,8 @@ export {
252
279
  GOVERNANCE_COLUMNS,
253
280
  conflictUpdateColumns,
254
281
  findDeadUrlPatterns,
282
+ findStaleRows,
283
+ mirrorRowKey,
255
284
  planColumns,
256
285
  planSurfaceSync,
257
286
  renderSurfaceSyncSql,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/declare/keys.ts","../src/declare/registry.ts","../src/checks/sync.ts","../src/checks/routes.ts"],"sourcesContent":["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 * 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\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\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 * 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 * `visibility`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\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\", \"visibility\"] 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\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, visibility: \"public\" };\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 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) };\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":";AA8BO,SAAS,gBAAgB,aAA6B;AAC3D,SAAO,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK;AACtC;;;ACKO,IAAM,sBAAmC,OAAO,OAAO;AAAA,EAC5D,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,mBAAmB;AACrB,CAAC;AAEM,SAAS,mBAAmB,OAAwD;AACzF,SAAO;AAAA,IACL,YAAY,MAAM,aAAa,cAAc,oBAAoB;AAAA,IACjE,gBAAgB,MAAM,aAAa,kBAAkB,oBAAoB;AAAA,IACzE,mBAAmB,MAAM,aAAa,qBAAqB,oBAAoB;AAAA,EACjF;AACF;;;AChCO,IAAM,qBAAqB,CAAC,mBAAmB,YAAY;AA2ClE,SAAS,SAAS,QAAmD;AACnE,SAAO,QAAQ,WAAW,CAAC,gBAAgB,aAAa,MAAM,IAAI,CAAC,gBAAgB,MAAM;AAC3F;AAEO,SAAS,gBACd,cACA,SACiB;AACjB,QAAM,EAAE,gBAAgB,YAAY,OAAO,IAAI;AAC/C,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,aAAa,EAAE,WAAW,UAAU,aAAa,WAAW;AAClE,QAAM,aAAa,EAAE,iBAAiB,gBAAgB,YAAY,SAAS;AAC3E,QAAM,WAA6B,CAAC;AACpC,QAAM,SAAiC,CAAC;AACxC,QAAM,UAAkC,CAAC;AACzC,QAAM,YAAoC,CAAC;AAC3C,QAAM,kBAAkB,oBAAI,IAA2B;AAEvD,aAAW,KAAK,cAAc;AAC5B,UAAM,aAAa,EAAE,YAAY,KAAK,KAAK,QAAQ,oBAAoB,CAAC,KAAK;AAC7E,UAAM,QAAQ,EAAE,OAAO,KAAK,KAAK;AACjC,UAAM,SAAS,EAAE,gBAAgB;AACjC,UAAM,SAAS,gBAAgB,EAAE,WAAW;AAC5C,UAAM,QAA8B;AAAA,MAClC,aAAa;AAAA,MACb,gBAAgB,EAAE;AAAA,MAClB,aAAa,EAAE;AAAA,MACf,OAAO,EAAE;AAAA,MACT,cAAe,EAAE,UAAU,CAAC;AAAA,MAC5B,WAAW,EAAE;AAAA,MACb,gBAAgB,EAAE,eAAe,KAAK,KAAK;AAAA,MAC3C,GAAI,QAAQ,cAAc,EAAE,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,IAC/D;AAEA,UAAM,UAAgC;AAAA,MACpC,GAAI,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjD,GAAI,aAAa,EAAE,aAAa,WAAW,IAAI,CAAC;AAAA,MAChD,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,MACzB,GAAI,SAAS,EAAE,qBAAqB,OAAO,IAAI,CAAC;AAAA,IAClD;AACA,aAAS,KAAK;AAAA,MACZ,MAAM,EAAE;AAAA,MACR,QAAQ;AAAA,QACN,MAAM,EAAE;AAAA,QACR,GAAG;AAAA,QACH,YAAY,EAAE,aAAa;AAAA,QAC3B,aAAa;AAAA,QACb;AAAA,QACA,qBAAqB;AAAA,MACvB;AAAA,MACA,QAAQ,EAAE,GAAG,OAAO,GAAG,QAAQ;AAAA,IACjC,CAAC;AAED,eAAW,KAAK,EAAE,QAAQ;AACxB,aAAO,KAAK;AAAA,QACV,GAAG;AAAA,QACH,cAAc,EAAE;AAAA,QAChB,GAAI,QAAQ,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;AAAA,QAC5C,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,aAAa,EAAE;AAAA,QACf,YAAY,EAAE;AAAA,QACd,kBAAkB,EAAE;AAAA,QACpB,oBAAoB,EAAE;AAAA,QACtB,YAAY,EAAE,aAAa;AAAA,QAC3B,cAAc,EAAE,eAAe;AAAA,QAC/B,WAAW,EAAE,YAAY,EAAE,SAAS;AAAA,QACpC,GAAI,QAAQ,gBACR;AAAA,UACE,YAAY,mBAAmB,CAAC,EAAE;AAAA,UAClC,gBAAgB,mBAAmB,CAAC,EAAE;AAAA,UACtC,qBAAqB,mBAAmB,CAAC,EAAE;AAAA,UAC3C,UAAU,EAAE,aAAa;AAAA,UACzB,WAAW,EAAE,YAAY;AAAA,UACzB,MAAM,EAAE,QAAQ;AAAA,QAClB,IACA,CAAC;AAAA,QACL,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAEA,eAAW,KAAK,EAAE,gBAAgB,CAAC,GAAG;AACpC,cAAQ,KAAK;AAAA,QACX,GAAG;AAAA,QACH,cAAc,EAAE;AAAA,QAChB,GAAI,QAAQ,WAAW,EAAE,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;AAAA,QAC1D,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,aAAa,EAAE;AAAA,QACf,YAAY,EAAE;AAAA,QACd,MAAM,EAAE;AAAA,QACR,eAAe,EAAE,gBAAgB;AAAA,QACjC,WAAW,EAAE,SAAS;AAAA,QACtB,YAAY,EAAE,aAAa;AAAA,QAC3B,cAAc,EAAE,eAAe;AAAA,QAC/B,UAAU,EAAE,aAAa;AAAA,QACzB,GAAI,QAAQ,gBACR;AAAA,UACE,WAAW,EAAE,aAAa;AAAA,UAC1B,qBAAqB,EAAE,sBAAsB;AAAA,UAC7C,YAAY,EAAE,YAAY,CAAC,GAAG,EAAE,SAAS,IAAI;AAAA,UAC7C,aAAa,EAAE,eAAe;AAAA,QAChC,IACA,CAAC;AAAA,QACL,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAEA,QAAI,QAAQ,UAAU;AACpB,iBAAW,CAAC,UAAU,IAAI,MAAM,EAAE,aAAa,CAAC,GAAG,QAAQ,GAAG;AAC5D,kBAAU,KAAK;AAAA,UACb,GAAG;AAAA,UACH,cAAc,EAAE;AAAA,UAChB,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,aAAa,KAAK;AAAA,UAClB,UAAU,CAAC,GAAG,KAAK,QAAQ;AAAA,UAC3B,QAAQ,KAAK,SAAS,CAAC,GAAG,KAAK,MAAM,IAAI;AAAA,UACzC,aAAa,KAAK,cAAc;AAAA,UAChC,YAAY;AAAA,UACZ,GAAG;AAAA,QACL,CAAC;AACD,mBAAW,KAAK,KAAK,QAAQ;AAC3B,iBAAO,KAAK;AAAA,YACV,GAAG;AAAA,YACH,cAAc,EAAE;AAAA,YAChB,WAAW,KAAK;AAAA,YAChB,MAAM,EAAE;AAAA,YACR,OAAO,EAAE;AAAA,YACT,aAAa,EAAE;AAAA,YACf,YAAY,EAAE;AAAA,YACd,kBAAkB,EAAE;AAAA,YACpB,oBAAoB,EAAE;AAAA,YACtB,YAAY,EAAE,aAAa;AAAA,YAC3B,cAAc,EAAE,eAAe;AAAA,YAC/B,WAAW,EAAE,SAAS;AAAA,YACtB,GAAG;AAAA,UACL,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,eAAW,aAAa,QAAQ,cAAc,CAAC,GAAG;AAChD,iBAAW,SAAS,UAAU,SAAS,CAAiB,KAAK,CAAC,GAAG;AAC/D,cAAM,OAAO,gBAAgB,IAAI,MAAM,KAAK,KAAK;AAAA,UAC/C,OAAO,MAAM;AAAA,UACb,UAAU,MAAM;AAAA,UAChB,YAAY;AAAA,UACZ,MAAM,CAAC;AAAA,QACT;AACA,aAAK,KAAK,KAAK,EAAE,GAAG,YAAY,GAAG,MAAM,KAAK,GAAG,WAAW,CAAC;AAC7D,wBAAgB,IAAI,MAAM,OAAO,IAAI;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAA0B;AAAA,IAC9B,EAAE,OAAO,uBAAuB,UAAU,SAAS,MAAM,GAAG,YAAY,oBAAoB,MAAM,OAAO;AAAA,IACzG,EAAE,OAAO,8BAA8B,UAAU,SAAS,MAAM,GAAG,YAAY,oBAAoB,MAAM,QAAQ;AAAA,IACjH,GAAI,QAAQ,WACR,CAAC,EAAE,OAAO,2BAA2B,UAAU,CAAC,gBAAgB,MAAM,GAAG,YAAY,oBAAoB,MAAM,UAAU,CAAC,IAC1H,CAAC;AAAA,IACL,GAAG,gBAAgB,OAAO;AAAA,EAC5B;AACA,SAAO,EAAE,UAAU,QAAQ,OAAO,OAAO,CAAC,UAAU,MAAM,KAAK,SAAS,CAAC,EAAE;AAC7E;AAGO,SAAS,YAAY,OAAgC;AAC1D,QAAM,UAAoB,CAAC;AAC3B,aAAW,OAAO,MAAM,KAAM,YAAW,OAAO,OAAO,KAAK,GAAG,EAAG,KAAI,CAAC,QAAQ,SAAS,GAAG,EAAG,SAAQ,KAAK,GAAG;AAC9G,SAAO;AACT;AAGO,SAAS,sBAAsB,OAAgC;AACpE,SAAO,YAAY,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,SAAS,SAAS,CAAC,KAAK,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC;AACtG;AAEO,SAAS,WAAW,OAAiC;AAC1D,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,OAAO,UAAU,aAAa,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK;AAChF,MAAI,OAAO,UAAU,SAAU,QAAO,IAAI,MAAM,QAAQ,MAAM,IAAI,CAAC;AACnE,MAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,CAAC,UAAU,OAAO,UAAU,QAAQ,GAAG;AAC7E,WAAO,SAAS,MAAM,IAAI,CAAC,UAAU,WAAW,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACpE;AACA,SAAO,IAAI,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,IAAI,CAAC;AACtD;AAOO,SAAS,4BAA4B,MAAiC;AAC3E,QAAM,aAAuB,CAAC;AAC9B,MAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,UAAM,gBAAgB,OAAO,KAAK,KAAK,SAAS,CAAC,EAAG,MAAM;AAC1D,eAAW;AAAA,MACT,8BAA8B,cAAc,KAAK,IAAI,CAAC;AAAA,EAAa,KAAK,SACrE,IAAI,CAAC,MAAM,IAAI,cAAc,IAAI,CAAC,MAAM,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,EAC9E,KAAK,KAAK,CAAC;AAAA;AAAA,IAChB;AACA,eAAW,KAAK,KAAK,UAAU;AAC7B,iBAAW;AAAA,QACT,4BAA4B,OAAO,QAAQ,EAAE,MAAM,EAChD,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC,EAAE,EACzC,KAAK,IAAI,CAAC,qCAAqC,WAAW,EAAE,IAAI,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACA,aAAW,SAAS,KAAK,QAAQ;AAC/B,UAAM,UAAU,YAAY,KAAK;AACjC,UAAM,OAAO,sBAAsB,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,eAAe,CAAC,EAAE;AAC3E,eAAW;AAAA,MACT,eAAe,MAAM,KAAK,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,EAAa,MAAM,KACjE,IAAI,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC,MAAM,WAAW,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,EACrE,KAAK,KAAK,CAAC;AAAA,eAAkB,MAAM,SAAS,KAAK,IAAI,CAAC,mBAAmB,CAAC,GAAG,MAAM,oBAAoB,EAAE,KAAK,IAAI,CAAC;AAAA,IACxH;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,qBAAqB,MAA+B;AAClE,SAAO,4BAA4B,IAAI,EACpC,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,EAClC,KAAK,MAAM;AAChB;;;ACxRO,SAAS,cAAc,MAAwB;AACpD,UAAQ,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,IAC3B,MAAM,GAAG,EAAE,CAAC,EACZ,MAAM,GAAG,EACT,OAAO,OAAO,EACd,IAAI,CAAC,YAAY;AAChB,QAAI,uBAAuB,KAAK,OAAO,EAAG,QAAO;AACjD,QAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,GAAG,EAAG,QAAO;AAC/D,WAAO;AAAA,EACT,CAAC;AACL;AAQO,SAAS,uBAAuB,SAAiB,OAAmC;AACzF,QAAM,WAAW,QAAQ,QAAQ,EAAE,SAAS,GAAG,KAAK,CAAC,QAAQ,SAAS,IAAI;AAC1E,QAAM,WAAW,cAAc,QAAQ,QAAQ,WAAW,EAAE,CAAC;AAC7D,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;AAC3C,UAAM,eAAe,MAAM,CAAC;AAC5B,QAAI,iBAAiB,KAAM,QAAO;AAClC,QAAI,iBAAiB,OAAW,QAAO;AACvC,UAAM,WAAW,SAAS,CAAC;AAC3B,QAAI,aAAa,KAAM,QAAO;AAC9B,QAAI,aAAa,MAAM,iBAAiB,MAAM,iBAAiB,SAAU,QAAO;AAAA,EAClF;AACA,SAAO,YAAY,MAAM,WAAW,SAAS;AAC/C;AAGO,SAAS,oBACd,cACA,YAC+C;AAC/C,QAAM,SAAS,WAAW,IAAI,aAAa;AAC3C,QAAM,OAAsD,CAAC;AAC7D,aAAW,eAAe,cAAc;AACtC,UAAM,UAAU,YAAY;AAC5B,QAAI,CAAC,QAAS;AACd,QAAI,CAAC,OAAO,KAAK,CAAC,UAAU,uBAAuB,SAAS,KAAK,CAAC,GAAG;AACnE,WAAK,KAAK,EAAE,aAAa,YAAY,aAAa,YAAY,QAAQ,CAAC;AAAA,IACzE;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/declare/keys.ts","../src/declare/sensitivity.ts","../src/checks/sync.ts","../src/checks/routes.ts"],"sourcesContent":["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 * `visibility`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\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\", \"visibility\"] 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, visibility: \"public\" };\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":[]}