@ai-matrx/alchemy 0.8.32 → 0.8.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/checks.cjs +1 -1
- package/dist/checks.cjs.map +1 -1
- package/dist/checks.d.cts +4 -2
- package/dist/checks.d.ts +4 -2
- package/dist/checks.js +1 -1
- package/dist/checks.js.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.js.map +1 -1
- package/dist/operate.cjs +1 -1
- package/dist/operate.cjs.map +1 -1
- package/dist/operate.js +1 -1
- package/dist/operate.js.map +1 -1
- package/dist/react-bar.cjs.map +1 -1
- package/dist/react-bar.js.map +1 -1
- package/dist/react-menu.cjs +2 -2
- package/dist/react-menu.cjs.map +1 -1
- package/dist/react-menu.js +2 -2
- package/dist/react-menu.js.map +1 -1
- package/dist/react-overflow.cjs.map +1 -1
- package/dist/react-overflow.js.map +1 -1
- package/dist/react-palette.cjs +2 -2
- package/dist/react-palette.cjs.map +1 -1
- package/dist/react-palette.js +2 -2
- package/dist/react-palette.js.map +1 -1
- package/dist/react-selection.cjs.map +1 -1
- package/dist/react-selection.js.map +1 -1
- package/dist/react-sheet.cjs.map +1 -1
- package/dist/react-sheet.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.35
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/alchemy/v0.8.33..npm/alchemy/v0.8.35 -- apps/shared/alchemy`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.8.34
|
|
10
|
+
### Unreleased
|
|
11
|
+
|
|
12
|
+
- **Type-to-filter reaches every row** (clone 2026-10-01): the right-click `command` filter and `ActionPalette` open each lazy submenu while searching, so a library row ("Patient reminder card" under AI Actions ▸ My Personal) is found by typing, not only after drilling in. While rows are still opening the empty state reads "Searching…", never "No action matches". Guard: `src/react/filter-reaches-library-rows.test.tsx`. Consumer action: none.
|
|
13
|
+
- **The `[stubbed — N chars]` / `[truncated — N chars]` markers group through kit's `formatCount` pinned to en-US** (package-twins drain, 2026-09-30): same bytes as before (`12,345`), now from the one count formatter. Consumer action: none.
|
|
14
|
+
|
|
15
|
+
## 0.8.33
|
|
16
|
+
|
|
17
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
18
|
+
`git diff npm/alchemy/v0.8.32..npm/alchemy/v0.8.33 -- apps/shared/alchemy`).
|
|
19
|
+
No source changes intended and no consumer action required.
|
|
20
|
+
|
|
3
21
|
## 0.8.32
|
|
4
22
|
|
|
5
23
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/checks.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var checks_exports={};__export(checks_exports,{GOVERNANCE_COLUMNS:()=>GOVERNANCE_COLUMNS,conflictUpdateColumns:()=>conflictUpdateColumns,findDeadUrlPatterns:()=>findDeadUrlPatterns,findStaleRows:()=>findStaleRows,mirrorRowKey:()=>mirrorRowKey,planColumns:()=>planColumns,planSurfaceSync:()=>planSurfaceSync,renderSurfaceSyncSql:()=>renderSurfaceSyncSql,renderSurfaceSyncStatements:()=>renderSurfaceSyncStatements,routeSegments:()=>routeSegments,sqlLiteral:()=>sqlLiteral,urlPatternMatchesRoute:()=>urlPatternMatchesRoute});module.exports=__toCommonJS(checks_exports);function surfaceClientOf(surfaceName){return surfaceName.split("/")[0]??""}var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}var GOVERNANCE_COLUMNS=["organization_id","
|
|
1
|
+
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var checks_exports={};__export(checks_exports,{GOVERNANCE_COLUMNS:()=>GOVERNANCE_COLUMNS,conflictUpdateColumns:()=>conflictUpdateColumns,findDeadUrlPatterns:()=>findDeadUrlPatterns,findStaleRows:()=>findStaleRows,mirrorRowKey:()=>mirrorRowKey,planColumns:()=>planColumns,planSurfaceSync:()=>planSurfaceSync,renderSurfaceSyncSql:()=>renderSurfaceSyncSql,renderSurfaceSyncStatements:()=>renderSurfaceSyncStatements,routeSegments:()=>routeSegments,sqlLiteral:()=>sqlLiteral,urlPatternMatchesRoute:()=>urlPatternMatchesRoute});module.exports=__toCommonJS(checks_exports);function surfaceClientOf(surfaceName){return surfaceName.split("/")[0]??""}var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}var GOVERNANCE_COLUMNS=["organization_id","published_to_web"];function childKey(schema){return schema?.itemType?["surface_name","item_type","name"]:["surface_name","name"]}function planSurfaceSync(declarations,options){let{organizationId,syncedFrom,schema}=options,provenance={synced_by:options.syncedBy??null,synced_from:syncedFrom},governance={organization_id:organizationId,published_to_web:!0},surfaces=[],values=[],targets=[],itemTypes=[],extensionTables=new Map;for(let d of declarations){let urlPattern=d.urlPattern?.trim()||options.resolveUrlPattern?.(d)||null,intro=d.intro?.trim()||null,parent=d.inheritsFrom??null,owned={client_name:surfaceClientOf(d.surfaceName),execution_mode:d.executionMode,description:d.description,label:d.label,value_groups:d.groups??[],readiness:d.readiness,readiness_note:d.readinessNote?.trim()||null,...schema?.contentHash?{content_hash:d.contentHash}:{}},claimed={...d.overlayId?{overlay_id:d.overlayId}:{},...urlPattern?{url_pattern:urlPattern}:{},...intro?{intro}:{},...parent?{parent_surface_name:parent}:{}};surfaces.push({name:d.surfaceName,insert:{name:d.surfaceName,...owned,overlay_id:d.overlayId??null,url_pattern:urlPattern,intro,parent_surface_name:parent},update:{...owned,...claimed}});for(let v of d.values)values.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:""}:{},name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.groupKey??v.group??"general",...schema?.valueContract?{exportable:resolveSensitivity(v).exportable,classification:resolveSensitivity(v).classification,included_by_default:resolveSensitivity(v).includedByDefault,kind_key:v.valueKind??null,live_slot:v.liveSlot??null,role:v.role??"data"}:{},...provenance});for(let t of d.writeTargets??[])targets.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:t.itemType??""}:{},name:t.name,label:t.label,description:t.description,value_type:t.valueType,mode:t.mode,updates_value:t.updatesValue??null,group_key:t.group??"general",sort_order:t.sortOrder??1e3,apply_policy:t.applyPolicy??"manual",kind_key:t.valueKind??null,...schema?.valueContract?{patchable:t.patchable??!1,approval_comparison:t.approvalComparison??null,stream_ops:t.streamOps?[...t.streamOps]:null,destination:t.destination??!1}:{},...provenance});if(schema?.itemType)for(let[position,item]of(d.itemTypes??[]).entries()){itemTypes.push({...governance,surface_name:d.surfaceName,name:item.name,label:item.label,description:item.description,identity:[...item.identity],levels:item.levels?[...item.levels]:null,entity_type:item.entityType??null,sort_order:position,...provenance});for(let v of item.values)values.push({...governance,surface_name:d.surfaceName,item_type:item.name,name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.group??"general",...provenance})}for(let extension of options.extensions??[])for(let entry of extension.toRows?.(d)??[]){let plan=extensionTables.get(entry.table)??{table:entry.table,conflict:entry.conflict,insertOnly:GOVERNANCE_COLUMNS,rows:[]};plan.rows.push({...governance,...entry.row,...provenance}),extensionTables.set(entry.table,plan)}}let keys={"ui.ui_surface_value":childKey(schema),"ui.ui_surface_write_target":childKey(schema),...schema?.itemType?{"ui.ui_surface_item_type":["surface_name","name"]}:{}};for(let extension of options.extensions??[])extension.mirror&&(keys[extension.mirror.table]=extension.mirror.conflict);for(let plan of extensionTables.values())keys[plan.table]??=plan.conflict;let tables=[{table:"ui.ui_surface_value",conflict:childKey(schema),insertOnly:GOVERNANCE_COLUMNS,rows:values},{table:"ui.ui_surface_write_target",conflict:childKey(schema),insertOnly:GOVERNANCE_COLUMNS,rows:targets},...schema?.itemType?[{table:"ui.ui_surface_item_type",conflict:["surface_name","name"],insertOnly:GOVERNANCE_COLUMNS,rows:itemTypes}]:[],...extensionTables.values()];return{surfaces,tables:tables.filter(table=>table.rows.length>0),keys}}function mirrorRowKey(row,columns){return columns.map(column=>String(row[column]??"")).join("\0")}function findStaleRows(plan,table,existing){let key=plan.keys[table];if(!key)throw new Error(`Sync plan declares no key for "${table}"; give the extension that owns it a \`mirror\` entry.`);let managed=new Set(plan.surfaces.map(surface=>surface.name)),declared=new Set((plan.tables.find(entry=>entry.table===table)?.rows??[]).map(row=>mirrorRowKey(row,key)));return existing.filter(row=>managed.has(String(row.surface_name))&&!declared.has(mirrorRowKey(row,key)))}function planColumns(table){let columns=[];for(let row of table.rows)for(let key of Object.keys(row))columns.includes(key)||columns.push(key);return columns}function conflictUpdateColumns(table){return planColumns(table).filter(c=>!table.conflict.includes(c)&&!table.insertOnly.includes(c))}function sqlLiteral(value){return value==null?"NULL":typeof value=="boolean"||typeof value=="number"?String(value):typeof value=="string"?`'${value.replace(/'/g,"''")}'`:Array.isArray(value)&&value.every(entry=>typeof entry=="string")?`ARRAY[${value.map(entry=>sqlLiteral(entry)).join(", ")}]::text[]`:`'${JSON.stringify(value).replace(/'/g,"''")}'::jsonb`}function renderSurfaceSyncStatements(plan){let statements=[];if(plan.surfaces.length>0){let insertColumns=Object.keys(plan.surfaces[0].insert);statements.push(`INSERT INTO ui.ui_surface (${insertColumns.join(", ")}) VALUES
|
|
2
2
|
${plan.surfaces.map(s=>`(${insertColumns.map(c=>sqlLiteral(s.insert[c])).join(", ")})`).join(`,
|
|
3
3
|
`)}
|
|
4
4
|
ON CONFLICT (name) DO NOTHING`);for(let s of plan.surfaces)statements.push(`UPDATE ui.ui_surface SET ${Object.entries(s.update).map(([c,v])=>`${c} = ${sqlLiteral(v)}`).join(", ")}, updated_at = now() WHERE name = ${sqlLiteral(s.name)}`)}for(let table of plan.tables){let columns=planColumns(table),sets=conflictUpdateColumns(table).map(c=>`${c} = EXCLUDED.${c}`);statements.push(`INSERT INTO ${table.table} (${columns.join(", ")}) VALUES
|
package/dist/checks.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/checks.ts","../src/declare/keys.ts","../src/declare/sensitivity.ts","../src/checks/sync.ts","../src/checks/routes.ts"],"sourcesContent":["/**\n * `@ai-matrx/alchemy/checks` — the ONE surface sync (CONTRACT §2.7): the row plan\n * every sync path executes, and its SQL rendering. Pure; no database client.\n */\nexport {\n GOVERNANCE_COLUMNS,\n conflictUpdateColumns,\n findStaleRows,\n mirrorRowKey,\n planColumns,\n planSurfaceSync,\n renderSurfaceSyncSql,\n renderSurfaceSyncStatements,\n sqlLiteral,\n type SurfaceRowPlan,\n type SurfaceSyncPlan,\n type SurfaceSyncPlanOptions,\n type SyncSchema,\n type SyncTablePlan,\n} from \"./checks/sync\";\nexport { findDeadUrlPatterns, routeSegments, urlPatternMatchesRoute } from \"./checks/routes\";\n","import type { QualifiedValueKey } from \"./types\";\n\n/** Every value, write-target, item-type and group name (the DB CHECK rule). */\nexport const DECLARATION_NAME_RE = /^[a-z][a-z0-9_]*$/;\n\n/** \"<client>/<local>\" — the surface naming convention. */\nexport const SURFACE_NAME_RE = /^[a-z][a-z0-9-]*\\/[a-z0-9-/]+$/;\n\n/** A bare screen value (`status`) or an item value (`table_row.status`). */\nexport const QUALIFIED_VALUE_KEY_RE = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)?$/;\n\nexport interface ParsedValueKey {\n /** \"\" for a screen-level value. */\n itemType: string;\n name: string;\n}\n\n/** Split a qualified key; null when it is not a valid bare or qualified key. */\nexport function parseQualifiedValueKey(key: string): ParsedValueKey | null {\n if (!QUALIFIED_VALUE_KEY_RE.test(key)) return null;\n const dot = key.indexOf(\".\");\n if (dot === -1) return { itemType: \"\", name: key };\n return { itemType: key.slice(0, dot), name: key.slice(dot + 1) };\n}\n\nexport function qualifyValueKey(itemType: string, name: string): QualifiedValueKey {\n return itemType ? `${itemType}.${name}` : name;\n}\n\n/** The client that owns a surface: its name prefix. */\nexport function surfaceClientOf(surfaceName: string): string {\n return surfaceName.split(\"/\")[0] ?? \"\";\n}\n","/**\n * Sensitivity defaults and resolution (CONTRACT §2.1). Its own module so the\n * lightweight entries (`/actions`, the T0 React host) can project without\n * pulling the declaration registry.\n */\nimport type { DeclaredValue, Sensitivity } from \"./types\";\n\nexport const DEFAULT_SENSITIVITY: Sensitivity = Object.freeze({\n exportable: true,\n classification: \"ordinary\",\n includedByDefault: true,\n});\n\nexport function resolveSensitivity(value: Pick<DeclaredValue, \"sensitivity\">): Sensitivity {\n return {\n exportable: value.sensitivity?.exportable ?? DEFAULT_SENSITIVITY.exportable,\n classification: value.sensitivity?.classification ?? DEFAULT_SENSITIVITY.classification,\n includedByDefault: value.sensitivity?.includedByDefault ?? DEFAULT_SENSITIVITY.includedByDefault,\n };\n}\n","/**\n * THE ONE SYNC (CONTRACT §2.7 \"One sync path\", chair ruling B1).\n *\n * `planSurfaceSync` maps resolved declarations onto the `ui` mirror rows; every\n * sync path (the SQL emitter and the admin sync service) executes this plan and\n * builds no rows of its own. Governance columns (`organization_id`,\n * `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":"wpBAAA,ujBC8BO,SAAS,gBAAgB,YAA6B,CAC3D,OAAO,YAAY,MAAM,GAAG,EAAE,CAAC,GAAK,EACtC,CCzBO,IAAM,oBAAmC,OAAO,OAAO,CAC5D,WAAY,GACZ,eAAgB,WAChB,kBAAmB,EACrB,CAAC,EAEM,SAAS,mBAAmB,MAAwD,CACzF,MAAO,CACL,WAAY,MAAM,aAAa,YAAc,oBAAoB,WACjE,eAAgB,MAAM,aAAa,gBAAkB,oBAAoB,eACzE,kBAAmB,MAAM,aAAa,mBAAqB,oBAAoB,iBACjF,CACF,CCFO,IAAM,mBAAqB,CAAC,kBAAmB,YAAY,EAiDlE,SAAS,SAAS,OAAmD,CACnE,OAAO,QAAQ,SAAW,CAAC,eAAgB,YAAa,MAAM,EAAI,CAAC,eAAgB,MAAM,CAC3F,CAEO,SAAS,gBACd,aACA,QACiB,CACjB,GAAM,CAAE,eAAgB,WAAY,MAAO,EAAI,QAEzC,WAAa,CAAE,UADJ,QAAQ,UAAY,KACK,YAAa,UAAW,EAC5D,WAAa,CAAE,gBAAiB,eAAgB,WAAY,QAAS,EACrE,SAA6B,CAAC,EAC9B,OAAiC,CAAC,EAClC,QAAkC,CAAC,EACnC,UAAoC,CAAC,EACrC,gBAAkB,IAAI,IAE5B,QAAW,KAAK,aAAc,CAC5B,IAAM,WAAa,EAAE,YAAY,KAAK,GAAK,QAAQ,oBAAoB,CAAC,GAAK,KACvE,MAAQ,EAAE,OAAO,KAAK,GAAK,KAC3B,OAAS,EAAE,cAAgB,KAE3B,MAA8B,CAClC,YAFa,gBAAgB,EAAE,WAAW,EAG1C,eAAgB,EAAE,cAClB,YAAa,EAAE,YACf,MAAO,EAAE,MACT,aAAe,EAAE,QAAU,CAAC,EAC5B,UAAW,EAAE,UACb,eAAgB,EAAE,eAAe,KAAK,GAAK,KAC3C,GAAI,QAAQ,YAAc,CAAE,aAAc,EAAE,WAAY,EAAI,CAAC,CAC/D,EAEM,QAAgC,CACpC,GAAI,EAAE,UAAY,CAAE,WAAY,EAAE,SAAU,EAAI,CAAC,EACjD,GAAI,WAAa,CAAE,YAAa,UAAW,EAAI,CAAC,EAChD,GAAI,MAAQ,CAAE,KAAM,EAAI,CAAC,EACzB,GAAI,OAAS,CAAE,oBAAqB,MAAO,EAAI,CAAC,CAClD,EACA,SAAS,KAAK,CACZ,KAAM,EAAE,YACR,OAAQ,CACN,KAAM,EAAE,YACR,GAAG,MACH,WAAY,EAAE,WAAa,KAC3B,YAAa,WACb,MACA,oBAAqB,MACvB,EACA,OAAQ,CAAE,GAAG,MAAO,GAAG,OAAQ,CACjC,CAAC,EAED,QAAW,KAAK,EAAE,OAChB,OAAO,KAAK,CACV,GAAG,WACH,aAAc,EAAE,YAChB,GAAI,QAAQ,SAAW,CAAE,UAAW,EAAG,EAAI,CAAC,EAC5C,KAAM,EAAE,KACR,MAAO,EAAE,MACT,YAAa,EAAE,YACf,WAAY,EAAE,UACd,iBAAkB,EAAE,gBACpB,mBAAoB,EAAE,iBACtB,WAAY,EAAE,WAAa,IAC3B,aAAc,EAAE,aAAe,GAC/B,UAAW,EAAE,UAAY,EAAE,OAAS,UACpC,GAAI,QAAQ,cACR,CACE,WAAY,mBAAmB,CAAC,EAAE,WAClC,eAAgB,mBAAmB,CAAC,EAAE,eACtC,oBAAqB,mBAAmB,CAAC,EAAE,kBAC3C,SAAU,EAAE,WAAa,KACzB,UAAW,EAAE,UAAY,KACzB,KAAM,EAAE,MAAQ,MAClB,EACA,CAAC,EACL,GAAG,UACL,CAAC,EAGH,QAAW,KAAK,EAAE,cAAgB,CAAC,EACjC,QAAQ,KAAK,CACX,GAAG,WACH,aAAc,EAAE,YAChB,GAAI,QAAQ,SAAW,CAAE,UAAW,EAAE,UAAY,EAAG,EAAI,CAAC,EAC1D,KAAM,EAAE,KACR,MAAO,EAAE,MACT,YAAa,EAAE,YACf,WAAY,EAAE,UACd,KAAM,EAAE,KACR,cAAe,EAAE,cAAgB,KACjC,UAAW,EAAE,OAAS,UACtB,WAAY,EAAE,WAAa,IAC3B,aAAc,EAAE,aAAe,SAC/B,SAAU,EAAE,WAAa,KACzB,GAAI,QAAQ,cACR,CACE,UAAW,EAAE,WAAa,GAC1B,oBAAqB,EAAE,oBAAsB,KAC7C,WAAY,EAAE,UAAY,CAAC,GAAG,EAAE,SAAS,EAAI,KAC7C,YAAa,EAAE,aAAe,EAChC,EACA,CAAC,EACL,GAAG,UACL,CAAC,EAGH,GAAI,QAAQ,SACV,OAAW,CAAC,SAAU,IAAI,IAAM,EAAE,WAAa,CAAC,GAAG,QAAQ,EAAG,CAC5D,UAAU,KAAK,CACb,GAAG,WACH,aAAc,EAAE,YAChB,KAAM,KAAK,KACX,MAAO,KAAK,MACZ,YAAa,KAAK,YAClB,SAAU,CAAC,GAAG,KAAK,QAAQ,EAC3B,OAAQ,KAAK,OAAS,CAAC,GAAG,KAAK,MAAM,EAAI,KACzC,YAAa,KAAK,YAAc,KAChC,WAAY,SACZ,GAAG,UACL,CAAC,EACD,QAAW,KAAK,KAAK,OACnB,OAAO,KAAK,CACV,GAAG,WACH,aAAc,EAAE,YAChB,UAAW,KAAK,KAChB,KAAM,EAAE,KACR,MAAO,EAAE,MACT,YAAa,EAAE,YACf,WAAY,EAAE,UACd,iBAAkB,EAAE,gBACpB,mBAAoB,EAAE,iBACtB,WAAY,EAAE,WAAa,IAC3B,aAAc,EAAE,aAAe,GAC/B,UAAW,EAAE,OAAS,UACtB,GAAG,UACL,CAAC,CAEL,CAGF,QAAW,aAAa,QAAQ,YAAc,CAAC,EAC7C,QAAW,SAAS,UAAU,SAAS,CAAiB,GAAK,CAAC,EAAG,CAC/D,IAAM,KAAO,gBAAgB,IAAI,MAAM,KAAK,GAAK,CAC/C,MAAO,MAAM,MACb,SAAU,MAAM,SAChB,WAAY,mBACZ,KAAM,CAAC,CACT,EACA,KAAK,KAAK,KAAK,CAAE,GAAG,WAAY,GAAG,MAAM,IAAK,GAAG,UAAW,CAAC,EAC7D,gBAAgB,IAAI,MAAM,MAAO,IAAI,CACvC,CAEJ,CAEA,IAAM,KAA0C,CAC9C,sBAAuB,SAAS,MAAM,EACtC,6BAA8B,SAAS,MAAM,EAC7C,GAAI,QAAQ,SAAW,CAAE,0BAA2B,CAAC,eAAgB,MAAM,CAAE,EAAI,CAAC,CACpF,EACA,QAAW,aAAa,QAAQ,YAAc,CAAC,EACzC,UAAU,SAAQ,KAAK,UAAU,OAAO,KAAK,EAAI,UAAU,OAAO,UAExE,QAAW,QAAQ,gBAAgB,OAAO,EAAG,KAAK,KAAK,KAAK,IAAM,KAAK,SAEvE,IAAM,OAA0B,CAC9B,CAAE,MAAO,sBAAuB,SAAU,SAAS,MAAM,EAAG,WAAY,mBAAoB,KAAM,MAAO,EACzG,CAAE,MAAO,6BAA8B,SAAU,SAAS,MAAM,EAAG,WAAY,mBAAoB,KAAM,OAAQ,EACjH,GAAI,QAAQ,SACR,CAAC,CAAE,MAAO,0BAA2B,SAAU,CAAC,eAAgB,MAAM,EAAG,WAAY,mBAAoB,KAAM,SAAU,CAAC,EAC1H,CAAC,EACL,GAAG,gBAAgB,OAAO,CAC5B,EACA,MAAO,CAAE,SAAU,OAAQ,OAAO,OAAQ,OAAU,MAAM,KAAK,OAAS,CAAC,EAAG,IAAK,CACnF,CAGO,SAAS,aAAa,IAAwC,QAAoC,CACvG,OAAO,QAAQ,IAAK,QAAW,OAAO,IAAI,MAAM,GAAK,EAAE,CAAC,EAAE,KAAK,IAAQ,CACzE,CAQO,SAAS,cACd,KACA,MACA,SACK,CACL,IAAM,IAAM,KAAK,KAAK,KAAK,EAC3B,GAAI,CAAC,IACH,MAAM,IAAI,MACR,kCAAkC,KAAK,wDACzC,EAEF,IAAM,QAAU,IAAI,IAAI,KAAK,SAAS,IAAK,SAAY,QAAQ,IAAI,CAAC,EAC9D,SAAW,IAAI,KAClB,KAAK,OAAO,KAAM,OAAU,MAAM,QAAU,KAAK,GAAG,MAAQ,CAAC,GAAG,IAAK,KAAQ,aAAa,IAAK,GAAG,CAAC,CACtG,EACA,OAAO,SAAS,OACb,KAAQ,QAAQ,IAAI,OAAO,IAAI,YAAY,CAAC,GAAK,CAAC,SAAS,IAAI,aAAa,IAAK,GAAG,CAAC,CACxF,CACF,CAGO,SAAS,YAAY,MAAgC,CAC1D,IAAM,QAAoB,CAAC,EAC3B,QAAW,OAAO,MAAM,KAAM,QAAW,OAAO,OAAO,KAAK,GAAG,EAAQ,QAAQ,SAAS,GAAG,GAAG,QAAQ,KAAK,GAAG,EAC9G,OAAO,OACT,CAGO,SAAS,sBAAsB,MAAgC,CACpE,OAAO,YAAY,KAAK,EAAE,OAAQ,GAAM,CAAC,MAAM,SAAS,SAAS,CAAC,GAAK,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC,CACtG,CAEO,SAAS,WAAW,MAAiC,CAC1D,OAAI,OAAU,KAAoC,OAC9C,OAAO,OAAU,WAAa,OAAO,OAAU,SAAiB,OAAO,KAAK,EAC5E,OAAO,OAAU,SAAiB,IAAI,MAAM,QAAQ,KAAM,IAAI,CAAC,IAC/D,MAAM,QAAQ,KAAK,GAAK,MAAM,MAAO,OAAU,OAAO,OAAU,QAAQ,EACnE,SAAS,MAAM,IAAK,OAAU,WAAW,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,YAE7D,IAAI,KAAK,UAAU,KAAK,EAAE,QAAQ,KAAM,IAAI,CAAC,UACtD,CAOO,SAAS,4BAA4B,KAAiC,CAC3E,IAAM,WAAuB,CAAC,EAC9B,GAAI,KAAK,SAAS,OAAS,EAAG,CAC5B,IAAM,cAAgB,OAAO,KAAK,KAAK,SAAS,CAAC,EAAG,MAAM,EAC1D,WAAW,KACT,8BAA8B,cAAc,KAAK,IAAI,CAAC;AAAA,EAAa,KAAK,SACrE,IAAK,GAAM,IAAI,cAAc,IAAK,GAAM,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,EAC9E,KAAK;AAAA,CAAK,CAAC;AAAA,8BAChB,EACA,QAAW,KAAK,KAAK,SACnB,WAAW,KACT,4BAA4B,OAAO,QAAQ,EAAE,MAAM,EAChD,IAAI,CAAC,CAAC,EAAG,CAAC,IAAM,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC,EAAE,EACzC,KAAK,IAAI,CAAC,qCAAqC,WAAW,EAAE,IAAI,CAAC,EACtE,CAEJ,CACA,QAAW,SAAS,KAAK,OAAQ,CAC/B,IAAM,QAAU,YAAY,KAAK,EAC3B,KAAO,sBAAsB,KAAK,EAAE,IAAK,GAAM,GAAG,CAAC,eAAe,CAAC,EAAE,EAC3E,WAAW,KACT,eAAe,MAAM,KAAK,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,EAAa,MAAM,KACjE,IAAK,KAAQ,IAAI,QAAQ,IAAK,GAAM,WAAW,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,EACrE,KAAK;AAAA,CAAK,CAAC;AAAA,eAAkB,MAAM,SAAS,KAAK,IAAI,CAAC,mBAAmB,CAAC,GAAG,KAAM,oBAAoB,EAAE,KAAK,IAAI,CAAC,EACxH,CACF,CACA,OAAO,UACT,CAGO,SAAS,qBAAqB,KAA+B,CAClE,OAAO,4BAA4B,IAAI,EACpC,IAAK,WAAc,GAAG,SAAS,GAAG,EAClC,KAAK;AAAA;AAAA,CAAM,CAChB,CCvUO,SAAS,cAAc,KAAwB,CACpD,OAAQ,KAAK,MAAM,GAAG,EAAE,CAAC,GAAK,IAC3B,MAAM,GAAG,EAAE,CAAC,EACZ,MAAM,GAAG,EACT,OAAO,OAAO,EACd,IAAK,SACA,uBAAuB,KAAK,OAAO,EAAU,KAC7C,QAAQ,WAAW,GAAG,GAAK,QAAQ,WAAW,GAAG,EAAU,IACxD,OACR,CACL,CAQO,SAAS,uBAAuB,QAAiB,MAAmC,CACzF,IAAM,SAAW,QAAQ,QAAQ,EAAE,SAAS,GAAG,GAAK,CAAC,QAAQ,SAAS,IAAI,EACpE,SAAW,cAAc,QAAQ,QAAQ,UAAW,EAAE,CAAC,EAC7D,QAAS,EAAI,EAAG,EAAI,SAAS,OAAQ,GAAK,EAAG,CAC3C,IAAM,aAAe,MAAM,CAAC,EAC5B,GAAI,eAAiB,KAAM,MAAO,GAClC,GAAI,eAAiB,OAAW,MAAO,GACvC,IAAM,SAAW,SAAS,CAAC,EAC3B,GAAI,WAAa,KAAM,MAAO,GAC9B,GAAI,WAAa,IAAM,eAAiB,IAAM,eAAiB,SAAU,MAAO,EAClF,CACA,OAAO,UAAY,MAAM,SAAW,SAAS,MAC/C,CAGO,SAAS,oBACd,aACA,WAC+C,CAC/C,IAAM,OAAS,WAAW,IAAI,aAAa,EACrC,KAAsD,CAAC,EAC7D,QAAW,eAAe,aAAc,CACtC,IAAM,QAAU,YAAY,WACvB,UACA,OAAO,KAAM,OAAU,uBAAuB,QAAS,KAAK,CAAC,GAChE,KAAK,KAAK,CAAE,YAAa,YAAY,YAAa,WAAY,OAAQ,CAAC,EAE3E,CACA,OAAO,IACT","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 * `published_to_web`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\n * Mirror rows are published to the web on insert, written explicitly (access ladder\n * T-13: never left to a column default); the database stamps when and by whom.\n *\n * Schema generations: the columns added by the ALC-14 migration (item_type,\n * sensitivity, live slots, content_hash) are emitted only when the caller says\n * that migration is live (`schema`), so no emitter ever writes a column — or\n * upserts against a key — the database does not have yet.\n */\nimport { resolveSensitivity, type Resolved } from \"../declare/registry\";\nimport { surfaceClientOf } from \"../declare/keys\";\nimport type { DeclarationExtension, Json, SurfaceDeclaration } from \"../declare/types\";\n\nexport const GOVERNANCE_COLUMNS = [\"organization_id\", \"published_to_web\"] as const;\n\nexport interface SyncSchema {\n /** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */\n itemType?: boolean;\n /** Sensitivity, kind, live slot and role columns exist on `ui_surface_value`. */\n valueContract?: boolean;\n /** `ui_surface.content_hash` exists. */\n contentHash?: boolean;\n}\n\nexport interface SurfaceSyncPlanOptions<D extends SurfaceDeclaration> {\n organizationId: string;\n syncedFrom: string;\n syncedBy?: string | null;\n /** The address the host derives for a declaration without `urlPattern`. */\n resolveUrlPattern?: (declaration: Resolved<D>) => string | undefined;\n extensions?: readonly DeclarationExtension<D>[];\n schema?: SyncSchema;\n}\n\nexport interface SurfaceRowPlan {\n name: string;\n /** Written only when the row does not exist yet. */\n insert: Record<string, Json>;\n /** Written on every sync (code owns these columns). */\n update: Record<string, Json>;\n}\n\nexport interface SyncTablePlan {\n table: string;\n /** The ON CONFLICT target (a unique index or primary key on exactly these columns). */\n conflict: readonly string[];\n /** Columns set on insert and never on conflict. */\n insertOnly: readonly string[];\n rows: Record<string, Json>[];\n}\n\nexport interface SurfaceSyncPlan {\n surfaces: SurfaceRowPlan[];\n tables: SyncTablePlan[];\n /**\n * The key (ON CONFLICT target) of every mirror table this plan owns,\n * including tables it emits no rows for. Stale detection and deletes use\n * exactly these columns (`findStaleRows`).\n */\n keys: Record<string, readonly string[]>;\n}\n\nfunction childKey(schema: SyncSchema | undefined): readonly string[] {\n return schema?.itemType ? [\"surface_name\", \"item_type\", \"name\"] : [\"surface_name\", \"name\"];\n}\n\nexport function planSurfaceSync<D extends SurfaceDeclaration>(\n declarations: readonly Resolved<D>[],\n options: SurfaceSyncPlanOptions<D>,\n): SurfaceSyncPlan {\n const { organizationId, syncedFrom, schema } = options;\n const syncedBy = options.syncedBy ?? null;\n const provenance = { synced_by: syncedBy, synced_from: syncedFrom };\n const governance = { organization_id: organizationId, published_to_web: true };\n const surfaces: SurfaceRowPlan[] = [];\n const values: Record<string, Json>[] = [];\n const targets: Record<string, Json>[] = [];\n const itemTypes: Record<string, Json>[] = [];\n const extensionTables = new Map<string, SyncTablePlan>();\n\n for (const d of declarations) {\n const urlPattern = d.urlPattern?.trim() || options.resolveUrlPattern?.(d) || null;\n const intro = d.intro?.trim() || null;\n const parent = d.inheritsFrom ?? null;\n const client = surfaceClientOf(d.surfaceName);\n const owned: Record<string, Json> = {\n client_name: client,\n execution_mode: d.executionMode,\n description: d.description,\n label: d.label,\n value_groups: (d.groups ?? []) as unknown as Json,\n readiness: d.readiness,\n readiness_note: d.readinessNote?.trim() || null,\n ...(schema?.contentHash ? { content_hash: d.contentHash } : {}),\n };\n // A declaration that does not claim these never clears a DB-authored value.\n const claimed: Record<string, Json> = {\n ...(d.overlayId ? { overlay_id: d.overlayId } : {}),\n ...(urlPattern ? { url_pattern: urlPattern } : {}),\n ...(intro ? { intro } : {}),\n ...(parent ? { parent_surface_name: parent } : {}),\n };\n surfaces.push({\n name: d.surfaceName,\n insert: {\n name: d.surfaceName,\n ...owned,\n overlay_id: d.overlayId ?? null,\n url_pattern: urlPattern,\n intro,\n parent_surface_name: parent,\n },\n update: { ...owned, ...claimed },\n });\n\n for (const v of d.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: \"\" } : {}),\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.groupKey ?? v.group ?? \"general\",\n ...(schema?.valueContract\n ? {\n exportable: resolveSensitivity(v).exportable,\n classification: resolveSensitivity(v).classification,\n included_by_default: resolveSensitivity(v).includedByDefault,\n kind_key: v.valueKind ?? null,\n live_slot: v.liveSlot ?? null,\n role: v.role ?? \"data\",\n }\n : {}),\n ...provenance,\n });\n }\n\n for (const t of d.writeTargets ?? []) {\n targets.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: t.itemType ?? \"\" } : {}),\n name: t.name,\n label: t.label,\n description: t.description,\n value_type: t.valueType,\n mode: t.mode,\n updates_value: t.updatesValue ?? null,\n group_key: t.group ?? \"general\",\n sort_order: t.sortOrder ?? 1000,\n apply_policy: t.applyPolicy ?? \"manual\",\n kind_key: t.valueKind ?? null,\n ...(schema?.valueContract\n ? {\n patchable: t.patchable ?? false,\n approval_comparison: t.approvalComparison ?? null,\n stream_ops: t.streamOps ? [...t.streamOps] : null,\n destination: t.destination ?? false,\n }\n : {}),\n ...provenance,\n });\n }\n\n if (schema?.itemType) {\n for (const [position, item] of (d.itemTypes ?? []).entries()) {\n itemTypes.push({\n ...governance,\n surface_name: d.surfaceName,\n name: item.name,\n label: item.label,\n description: item.description,\n identity: [...item.identity],\n levels: item.levels ? [...item.levels] : null,\n entity_type: item.entityType ?? null,\n sort_order: position,\n ...provenance,\n });\n for (const v of item.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n item_type: item.name,\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.group ?? \"general\",\n ...provenance,\n });\n }\n }\n }\n\n for (const extension of options.extensions ?? []) {\n for (const entry of extension.toRows?.(d as unknown as D) ?? []) {\n const plan = extensionTables.get(entry.table) ?? {\n table: entry.table,\n conflict: entry.conflict,\n insertOnly: GOVERNANCE_COLUMNS,\n rows: [],\n };\n plan.rows.push({ ...governance, ...entry.row, ...provenance });\n extensionTables.set(entry.table, plan);\n }\n }\n }\n\n const keys: Record<string, readonly string[]> = {\n \"ui.ui_surface_value\": childKey(schema),\n \"ui.ui_surface_write_target\": childKey(schema),\n ...(schema?.itemType ? { \"ui.ui_surface_item_type\": [\"surface_name\", \"name\"] } : {}),\n };\n for (const extension of options.extensions ?? []) {\n if (extension.mirror) keys[extension.mirror.table] = extension.mirror.conflict;\n }\n for (const plan of extensionTables.values()) keys[plan.table] ??= plan.conflict;\n\n const tables: SyncTablePlan[] = [\n { table: \"ui.ui_surface_value\", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: values },\n { table: \"ui.ui_surface_write_target\", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: targets },\n ...(schema?.itemType\n ? [{ table: \"ui.ui_surface_item_type\", conflict: [\"surface_name\", \"name\"], insertOnly: GOVERNANCE_COLUMNS, rows: itemTypes }]\n : []),\n ...extensionTables.values(),\n ];\n return { surfaces, tables: tables.filter((table) => table.rows.length > 0), keys };\n}\n\n/** One row's key under `columns` (a missing column reads as ''). */\nexport function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: readonly string[]): string {\n return columns.map((column) => String(row[column] ?? \"\")).join(\"\\u0000\");\n}\n\n/**\n * Rows of `table` that belong to a surface this plan manages but that the\n * plan no longer declares, judged by the table's full key (`plan.keys`) — so\n * a screen value and an item value that share a name are distinct rows. The\n * caller deletes each returned row filtered by every column of that key.\n */\nexport function findStaleRows<R extends Readonly<Record<string, unknown>>>(\n plan: SurfaceSyncPlan,\n table: string,\n existing: readonly R[],\n): R[] {\n const key = plan.keys[table];\n if (!key) {\n throw new Error(\n `Sync plan declares no key for \"${table}\"; give the extension that owns it a \\`mirror\\` entry.`,\n );\n }\n const managed = new Set(plan.surfaces.map((surface) => surface.name));\n const declared = new Set(\n (plan.tables.find((entry) => entry.table === table)?.rows ?? []).map((row) => mirrorRowKey(row, key)),\n );\n return existing.filter(\n (row) => managed.has(String(row.surface_name)) && !declared.has(mirrorRowKey(row, key)),\n );\n}\n\n/** Every column a table's rows carry, in first-seen order. */\nexport function planColumns(table: SyncTablePlan): string[] {\n const columns: string[] = [];\n for (const row of table.rows) for (const key of Object.keys(row)) if (!columns.includes(key)) columns.push(key);\n return columns;\n}\n\n/** Columns a conflict rewrites: everything except the key and the insert-only set. */\nexport function conflictUpdateColumns(table: SyncTablePlan): string[] {\n return planColumns(table).filter((c) => !table.conflict.includes(c) && !table.insertOnly.includes(c));\n}\n\nexport function sqlLiteral(value: Json | undefined): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"boolean\" || typeof value === \"number\") return String(value);\n if (typeof value === \"string\") return `'${value.replace(/'/g, \"''\")}'`;\n if (Array.isArray(value) && value.every((entry) => typeof entry === \"string\")) {\n return `ARRAY[${value.map((entry) => sqlLiteral(entry)).join(\", \")}]::text[]`;\n }\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'::jsonb`;\n}\n\n/**\n * The plan as SQL statements, one per entry: surface insert, one UPDATE per\n * surface, one upsert per table. Callers may run them, or EXPLAIN each one in a\n * read-only transaction to prove the plan against a live schema with no write.\n */\nexport function renderSurfaceSyncStatements(plan: SurfaceSyncPlan): string[] {\n const statements: string[] = [];\n if (plan.surfaces.length > 0) {\n const insertColumns = Object.keys(plan.surfaces[0]!.insert);\n statements.push(\n `INSERT INTO ui.ui_surface (${insertColumns.join(\", \")}) VALUES\\n${plan.surfaces\n .map((s) => `(${insertColumns.map((c) => sqlLiteral(s.insert[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (name) DO NOTHING`,\n );\n for (const s of plan.surfaces) {\n statements.push(\n `UPDATE ui.ui_surface SET ${Object.entries(s.update)\n .map(([c, v]) => `${c} = ${sqlLiteral(v)}`)\n .join(\", \")}, updated_at = now() WHERE name = ${sqlLiteral(s.name)}`,\n );\n }\n }\n for (const table of plan.tables) {\n const columns = planColumns(table);\n const sets = conflictUpdateColumns(table).map((c) => `${c} = EXCLUDED.${c}`);\n statements.push(\n `INSERT INTO ${table.table} (${columns.join(\", \")}) VALUES\\n${table.rows\n .map((row) => `(${columns.map((c) => sqlLiteral(row[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (${table.conflict.join(\", \")}) DO UPDATE SET ${[...sets, \"updated_at = now()\"].join(\", \")}`,\n );\n }\n return statements;\n}\n\n/** The plan as one SQL script (governance columns insert-only). */\nexport function renderSurfaceSyncSql(plan: SurfaceSyncPlan): string {\n return renderSurfaceSyncStatements(plan)\n .map((statement) => `${statement};`)\n .join(\"\\n\\n\");\n}\n","/**\n * The declaration half of the route check (CONTRACT §2.6 `/checks`): does each\n * declared `urlPattern` address a live route? The host supplies its route list\n * (it owns the filesystem); the matching rule lives here, once. Ported from\n * matrx-frontend `scripts/check-surface-routes.ts` (ALC-14).\n */\n\n/** Route or pattern → segments; `[x]` / `:x` → \"*\", `[...x]` / `[[...x]]` → \"**\". */\nexport function routeSegments(path: string): string[] {\n return (path.split(\"?\")[0] ?? \"\")\n .split(\"#\")[0]!\n .split(\"/\")\n .filter(Boolean)\n .map((segment) => {\n if (/^\\[\\[?\\.\\.\\..+\\]\\]?$/.test(segment)) return \"**\";\n if (segment.startsWith(\"[\") || segment.startsWith(\":\")) return \"*\";\n return segment;\n });\n}\n\n/**\n * Does a declared `urlPattern` address a live route? A literal pattern segment\n * must be a literal route segment — a dynamic route segment does NOT satisfy it,\n * or `/marketing/[brandId]/…` would \"cover\" a retired `/marketing/brands/…`.\n * A trailing `*` makes the pattern a prefix.\n */\nexport function urlPatternMatchesRoute(pattern: string, route: readonly string[]): boolean {\n const isPrefix = pattern.trimEnd().endsWith(\"*\") && !pattern.endsWith(\"]*\");\n const segments = routeSegments(pattern.replace(/\\*+\\s*$/, \"\"));\n for (let i = 0; i < segments.length; i += 1) {\n const routeSegment = route[i];\n if (routeSegment === \"**\") return true;\n if (routeSegment === undefined) return false;\n const declared = segments[i];\n if (declared === \"**\") return true;\n if (declared === \"*\" ? routeSegment !== \"*\" : routeSegment !== declared) return false;\n }\n return isPrefix || route.length === segments.length;\n}\n\n/** Every declaration whose `urlPattern` no live route can produce. */\nexport function findDeadUrlPatterns(\n declarations: readonly { surfaceName: string; urlPattern?: string | undefined }[],\n liveRoutes: readonly string[],\n): { surfaceName: string; urlPattern: string }[] {\n const routes = liveRoutes.map(routeSegments);\n const dead: { surfaceName: string; urlPattern: string }[] = [];\n for (const declaration of declarations) {\n const pattern = declaration.urlPattern;\n if (!pattern) continue;\n if (!routes.some((route) => urlPatternMatchesRoute(pattern, route))) {\n dead.push({ surfaceName: declaration.surfaceName, urlPattern: pattern });\n }\n }\n return dead;\n}\n"],"mappings":"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","names":[]}
|
package/dist/checks.d.cts
CHANGED
|
@@ -204,7 +204,9 @@ type Resolved<D extends SurfaceDeclaration> = Omit<D, "values" | "groups"> & {
|
|
|
204
204
|
* `planSurfaceSync` maps resolved declarations onto the `ui` mirror rows; every
|
|
205
205
|
* sync path (the SQL emitter and the admin sync service) executes this plan and
|
|
206
206
|
* builds no rows of its own. Governance columns (`organization_id`,
|
|
207
|
-
* `
|
|
207
|
+
* `published_to_web`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.
|
|
208
|
+
* Mirror rows are published to the web on insert, written explicitly (access ladder
|
|
209
|
+
* T-13: never left to a column default); the database stamps when and by whom.
|
|
208
210
|
*
|
|
209
211
|
* Schema generations: the columns added by the ALC-14 migration (item_type,
|
|
210
212
|
* sensitivity, live slots, content_hash) are emitted only when the caller says
|
|
@@ -212,7 +214,7 @@ type Resolved<D extends SurfaceDeclaration> = Omit<D, "values" | "groups"> & {
|
|
|
212
214
|
* upserts against a key — the database does not have yet.
|
|
213
215
|
*/
|
|
214
216
|
|
|
215
|
-
declare const GOVERNANCE_COLUMNS: readonly ["organization_id", "
|
|
217
|
+
declare const GOVERNANCE_COLUMNS: readonly ["organization_id", "published_to_web"];
|
|
216
218
|
interface SyncSchema {
|
|
217
219
|
/** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */
|
|
218
220
|
itemType?: boolean;
|
package/dist/checks.d.ts
CHANGED
|
@@ -204,7 +204,9 @@ type Resolved<D extends SurfaceDeclaration> = Omit<D, "values" | "groups"> & {
|
|
|
204
204
|
* `planSurfaceSync` maps resolved declarations onto the `ui` mirror rows; every
|
|
205
205
|
* sync path (the SQL emitter and the admin sync service) executes this plan and
|
|
206
206
|
* builds no rows of its own. Governance columns (`organization_id`,
|
|
207
|
-
* `
|
|
207
|
+
* `published_to_web`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.
|
|
208
|
+
* Mirror rows are published to the web on insert, written explicitly (access ladder
|
|
209
|
+
* T-13: never left to a column default); the database stamps when and by whom.
|
|
208
210
|
*
|
|
209
211
|
* Schema generations: the columns added by the ALC-14 migration (item_type,
|
|
210
212
|
* sensitivity, live slots, content_hash) are emitted only when the caller says
|
|
@@ -212,7 +214,7 @@ type Resolved<D extends SurfaceDeclaration> = Omit<D, "values" | "groups"> & {
|
|
|
212
214
|
* upserts against a key — the database does not have yet.
|
|
213
215
|
*/
|
|
214
216
|
|
|
215
|
-
declare const GOVERNANCE_COLUMNS: readonly ["organization_id", "
|
|
217
|
+
declare const GOVERNANCE_COLUMNS: readonly ["organization_id", "published_to_web"];
|
|
216
218
|
interface SyncSchema {
|
|
217
219
|
/** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */
|
|
218
220
|
itemType?: boolean;
|
package/dist/checks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function surfaceClientOf(surfaceName){return surfaceName.split("/")[0]??""}var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}var GOVERNANCE_COLUMNS=["organization_id","
|
|
1
|
+
function surfaceClientOf(surfaceName){return surfaceName.split("/")[0]??""}var DEFAULT_SENSITIVITY=Object.freeze({exportable:!0,classification:"ordinary",includedByDefault:!0});function resolveSensitivity(value){return{exportable:value.sensitivity?.exportable??DEFAULT_SENSITIVITY.exportable,classification:value.sensitivity?.classification??DEFAULT_SENSITIVITY.classification,includedByDefault:value.sensitivity?.includedByDefault??DEFAULT_SENSITIVITY.includedByDefault}}var GOVERNANCE_COLUMNS=["organization_id","published_to_web"];function childKey(schema){return schema?.itemType?["surface_name","item_type","name"]:["surface_name","name"]}function planSurfaceSync(declarations,options){let{organizationId,syncedFrom,schema}=options,provenance={synced_by:options.syncedBy??null,synced_from:syncedFrom},governance={organization_id:organizationId,published_to_web:!0},surfaces=[],values=[],targets=[],itemTypes=[],extensionTables=new Map;for(let d of declarations){let urlPattern=d.urlPattern?.trim()||options.resolveUrlPattern?.(d)||null,intro=d.intro?.trim()||null,parent=d.inheritsFrom??null,owned={client_name:surfaceClientOf(d.surfaceName),execution_mode:d.executionMode,description:d.description,label:d.label,value_groups:d.groups??[],readiness:d.readiness,readiness_note:d.readinessNote?.trim()||null,...schema?.contentHash?{content_hash:d.contentHash}:{}},claimed={...d.overlayId?{overlay_id:d.overlayId}:{},...urlPattern?{url_pattern:urlPattern}:{},...intro?{intro}:{},...parent?{parent_surface_name:parent}:{}};surfaces.push({name:d.surfaceName,insert:{name:d.surfaceName,...owned,overlay_id:d.overlayId??null,url_pattern:urlPattern,intro,parent_surface_name:parent},update:{...owned,...claimed}});for(let v of d.values)values.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:""}:{},name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.groupKey??v.group??"general",...schema?.valueContract?{exportable:resolveSensitivity(v).exportable,classification:resolveSensitivity(v).classification,included_by_default:resolveSensitivity(v).includedByDefault,kind_key:v.valueKind??null,live_slot:v.liveSlot??null,role:v.role??"data"}:{},...provenance});for(let t of d.writeTargets??[])targets.push({...governance,surface_name:d.surfaceName,...schema?.itemType?{item_type:t.itemType??""}:{},name:t.name,label:t.label,description:t.description,value_type:t.valueType,mode:t.mode,updates_value:t.updatesValue??null,group_key:t.group??"general",sort_order:t.sortOrder??1e3,apply_policy:t.applyPolicy??"manual",kind_key:t.valueKind??null,...schema?.valueContract?{patchable:t.patchable??!1,approval_comparison:t.approvalComparison??null,stream_ops:t.streamOps?[...t.streamOps]:null,destination:t.destination??!1}:{},...provenance});if(schema?.itemType)for(let[position,item]of(d.itemTypes??[]).entries()){itemTypes.push({...governance,surface_name:d.surfaceName,name:item.name,label:item.label,description:item.description,identity:[...item.identity],levels:item.levels?[...item.levels]:null,entity_type:item.entityType??null,sort_order:position,...provenance});for(let v of item.values)values.push({...governance,surface_name:d.surfaceName,item_type:item.name,name:v.name,label:v.label,description:v.description,value_type:v.valueType,always_available:v.alwaysAvailable,typical_char_count:v.typicalCharCount,sort_order:v.sortOrder??1e3,auto_context:v.autoContext??!0,group_key:v.group??"general",...provenance})}for(let extension of options.extensions??[])for(let entry of extension.toRows?.(d)??[]){let plan=extensionTables.get(entry.table)??{table:entry.table,conflict:entry.conflict,insertOnly:GOVERNANCE_COLUMNS,rows:[]};plan.rows.push({...governance,...entry.row,...provenance}),extensionTables.set(entry.table,plan)}}let keys={"ui.ui_surface_value":childKey(schema),"ui.ui_surface_write_target":childKey(schema),...schema?.itemType?{"ui.ui_surface_item_type":["surface_name","name"]}:{}};for(let extension of options.extensions??[])extension.mirror&&(keys[extension.mirror.table]=extension.mirror.conflict);for(let plan of extensionTables.values())keys[plan.table]??=plan.conflict;let tables=[{table:"ui.ui_surface_value",conflict:childKey(schema),insertOnly:GOVERNANCE_COLUMNS,rows:values},{table:"ui.ui_surface_write_target",conflict:childKey(schema),insertOnly:GOVERNANCE_COLUMNS,rows:targets},...schema?.itemType?[{table:"ui.ui_surface_item_type",conflict:["surface_name","name"],insertOnly:GOVERNANCE_COLUMNS,rows:itemTypes}]:[],...extensionTables.values()];return{surfaces,tables:tables.filter(table=>table.rows.length>0),keys}}function mirrorRowKey(row,columns){return columns.map(column=>String(row[column]??"")).join("\0")}function findStaleRows(plan,table,existing){let key=plan.keys[table];if(!key)throw new Error(`Sync plan declares no key for "${table}"; give the extension that owns it a \`mirror\` entry.`);let managed=new Set(plan.surfaces.map(surface=>surface.name)),declared=new Set((plan.tables.find(entry=>entry.table===table)?.rows??[]).map(row=>mirrorRowKey(row,key)));return existing.filter(row=>managed.has(String(row.surface_name))&&!declared.has(mirrorRowKey(row,key)))}function planColumns(table){let columns=[];for(let row of table.rows)for(let key of Object.keys(row))columns.includes(key)||columns.push(key);return columns}function conflictUpdateColumns(table){return planColumns(table).filter(c=>!table.conflict.includes(c)&&!table.insertOnly.includes(c))}function sqlLiteral(value){return value==null?"NULL":typeof value=="boolean"||typeof value=="number"?String(value):typeof value=="string"?`'${value.replace(/'/g,"''")}'`:Array.isArray(value)&&value.every(entry=>typeof entry=="string")?`ARRAY[${value.map(entry=>sqlLiteral(entry)).join(", ")}]::text[]`:`'${JSON.stringify(value).replace(/'/g,"''")}'::jsonb`}function renderSurfaceSyncStatements(plan){let statements=[];if(plan.surfaces.length>0){let insertColumns=Object.keys(plan.surfaces[0].insert);statements.push(`INSERT INTO ui.ui_surface (${insertColumns.join(", ")}) VALUES
|
|
2
2
|
${plan.surfaces.map(s=>`(${insertColumns.map(c=>sqlLiteral(s.insert[c])).join(", ")})`).join(`,
|
|
3
3
|
`)}
|
|
4
4
|
ON CONFLICT (name) DO NOTHING`);for(let s of plan.surfaces)statements.push(`UPDATE ui.ui_surface SET ${Object.entries(s.update).map(([c,v])=>`${c} = ${sqlLiteral(v)}`).join(", ")}, updated_at = now() WHERE name = ${sqlLiteral(s.name)}`)}for(let table of plan.tables){let columns=planColumns(table),sets=conflictUpdateColumns(table).map(c=>`${c} = EXCLUDED.${c}`);statements.push(`INSERT INTO ${table.table} (${columns.join(", ")}) VALUES
|
package/dist/checks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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":[]}
|
|
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 * `published_to_web`) are INSERT-ONLY (chair ruling N5): a conflict never rewrites them.\n * Mirror rows are published to the web on insert, written explicitly (access ladder\n * T-13: never left to a column default); the database stamps when and by whom.\n *\n * Schema generations: the columns added by the ALC-14 migration (item_type,\n * sensitivity, live slots, content_hash) are emitted only when the caller says\n * that migration is live (`schema`), so no emitter ever writes a column — or\n * upserts against a key — the database does not have yet.\n */\nimport { resolveSensitivity, type Resolved } from \"../declare/registry\";\nimport { surfaceClientOf } from \"../declare/keys\";\nimport type { DeclarationExtension, Json, SurfaceDeclaration } from \"../declare/types\";\n\nexport const GOVERNANCE_COLUMNS = [\"organization_id\", \"published_to_web\"] as const;\n\nexport interface SyncSchema {\n /** `ui_surface_value/write_target.item_type` exists and the conflict key includes it (re-key step 1). */\n itemType?: boolean;\n /** Sensitivity, kind, live slot and role columns exist on `ui_surface_value`. */\n valueContract?: boolean;\n /** `ui_surface.content_hash` exists. */\n contentHash?: boolean;\n}\n\nexport interface SurfaceSyncPlanOptions<D extends SurfaceDeclaration> {\n organizationId: string;\n syncedFrom: string;\n syncedBy?: string | null;\n /** The address the host derives for a declaration without `urlPattern`. */\n resolveUrlPattern?: (declaration: Resolved<D>) => string | undefined;\n extensions?: readonly DeclarationExtension<D>[];\n schema?: SyncSchema;\n}\n\nexport interface SurfaceRowPlan {\n name: string;\n /** Written only when the row does not exist yet. */\n insert: Record<string, Json>;\n /** Written on every sync (code owns these columns). */\n update: Record<string, Json>;\n}\n\nexport interface SyncTablePlan {\n table: string;\n /** The ON CONFLICT target (a unique index or primary key on exactly these columns). */\n conflict: readonly string[];\n /** Columns set on insert and never on conflict. */\n insertOnly: readonly string[];\n rows: Record<string, Json>[];\n}\n\nexport interface SurfaceSyncPlan {\n surfaces: SurfaceRowPlan[];\n tables: SyncTablePlan[];\n /**\n * The key (ON CONFLICT target) of every mirror table this plan owns,\n * including tables it emits no rows for. Stale detection and deletes use\n * exactly these columns (`findStaleRows`).\n */\n keys: Record<string, readonly string[]>;\n}\n\nfunction childKey(schema: SyncSchema | undefined): readonly string[] {\n return schema?.itemType ? [\"surface_name\", \"item_type\", \"name\"] : [\"surface_name\", \"name\"];\n}\n\nexport function planSurfaceSync<D extends SurfaceDeclaration>(\n declarations: readonly Resolved<D>[],\n options: SurfaceSyncPlanOptions<D>,\n): SurfaceSyncPlan {\n const { organizationId, syncedFrom, schema } = options;\n const syncedBy = options.syncedBy ?? null;\n const provenance = { synced_by: syncedBy, synced_from: syncedFrom };\n const governance = { organization_id: organizationId, published_to_web: true };\n const surfaces: SurfaceRowPlan[] = [];\n const values: Record<string, Json>[] = [];\n const targets: Record<string, Json>[] = [];\n const itemTypes: Record<string, Json>[] = [];\n const extensionTables = new Map<string, SyncTablePlan>();\n\n for (const d of declarations) {\n const urlPattern = d.urlPattern?.trim() || options.resolveUrlPattern?.(d) || null;\n const intro = d.intro?.trim() || null;\n const parent = d.inheritsFrom ?? null;\n const client = surfaceClientOf(d.surfaceName);\n const owned: Record<string, Json> = {\n client_name: client,\n execution_mode: d.executionMode,\n description: d.description,\n label: d.label,\n value_groups: (d.groups ?? []) as unknown as Json,\n readiness: d.readiness,\n readiness_note: d.readinessNote?.trim() || null,\n ...(schema?.contentHash ? { content_hash: d.contentHash } : {}),\n };\n // A declaration that does not claim these never clears a DB-authored value.\n const claimed: Record<string, Json> = {\n ...(d.overlayId ? { overlay_id: d.overlayId } : {}),\n ...(urlPattern ? { url_pattern: urlPattern } : {}),\n ...(intro ? { intro } : {}),\n ...(parent ? { parent_surface_name: parent } : {}),\n };\n surfaces.push({\n name: d.surfaceName,\n insert: {\n name: d.surfaceName,\n ...owned,\n overlay_id: d.overlayId ?? null,\n url_pattern: urlPattern,\n intro,\n parent_surface_name: parent,\n },\n update: { ...owned, ...claimed },\n });\n\n for (const v of d.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: \"\" } : {}),\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.groupKey ?? v.group ?? \"general\",\n ...(schema?.valueContract\n ? {\n exportable: resolveSensitivity(v).exportable,\n classification: resolveSensitivity(v).classification,\n included_by_default: resolveSensitivity(v).includedByDefault,\n kind_key: v.valueKind ?? null,\n live_slot: v.liveSlot ?? null,\n role: v.role ?? \"data\",\n }\n : {}),\n ...provenance,\n });\n }\n\n for (const t of d.writeTargets ?? []) {\n targets.push({\n ...governance,\n surface_name: d.surfaceName,\n ...(schema?.itemType ? { item_type: t.itemType ?? \"\" } : {}),\n name: t.name,\n label: t.label,\n description: t.description,\n value_type: t.valueType,\n mode: t.mode,\n updates_value: t.updatesValue ?? null,\n group_key: t.group ?? \"general\",\n sort_order: t.sortOrder ?? 1000,\n apply_policy: t.applyPolicy ?? \"manual\",\n kind_key: t.valueKind ?? null,\n ...(schema?.valueContract\n ? {\n patchable: t.patchable ?? false,\n approval_comparison: t.approvalComparison ?? null,\n stream_ops: t.streamOps ? [...t.streamOps] : null,\n destination: t.destination ?? false,\n }\n : {}),\n ...provenance,\n });\n }\n\n if (schema?.itemType) {\n for (const [position, item] of (d.itemTypes ?? []).entries()) {\n itemTypes.push({\n ...governance,\n surface_name: d.surfaceName,\n name: item.name,\n label: item.label,\n description: item.description,\n identity: [...item.identity],\n levels: item.levels ? [...item.levels] : null,\n entity_type: item.entityType ?? null,\n sort_order: position,\n ...provenance,\n });\n for (const v of item.values) {\n values.push({\n ...governance,\n surface_name: d.surfaceName,\n item_type: item.name,\n name: v.name,\n label: v.label,\n description: v.description,\n value_type: v.valueType,\n always_available: v.alwaysAvailable,\n typical_char_count: v.typicalCharCount,\n sort_order: v.sortOrder ?? 1000,\n auto_context: v.autoContext ?? true,\n group_key: v.group ?? \"general\",\n ...provenance,\n });\n }\n }\n }\n\n for (const extension of options.extensions ?? []) {\n for (const entry of extension.toRows?.(d as unknown as D) ?? []) {\n const plan = extensionTables.get(entry.table) ?? {\n table: entry.table,\n conflict: entry.conflict,\n insertOnly: GOVERNANCE_COLUMNS,\n rows: [],\n };\n plan.rows.push({ ...governance, ...entry.row, ...provenance });\n extensionTables.set(entry.table, plan);\n }\n }\n }\n\n const keys: Record<string, readonly string[]> = {\n \"ui.ui_surface_value\": childKey(schema),\n \"ui.ui_surface_write_target\": childKey(schema),\n ...(schema?.itemType ? { \"ui.ui_surface_item_type\": [\"surface_name\", \"name\"] } : {}),\n };\n for (const extension of options.extensions ?? []) {\n if (extension.mirror) keys[extension.mirror.table] = extension.mirror.conflict;\n }\n for (const plan of extensionTables.values()) keys[plan.table] ??= plan.conflict;\n\n const tables: SyncTablePlan[] = [\n { table: \"ui.ui_surface_value\", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: values },\n { table: \"ui.ui_surface_write_target\", conflict: childKey(schema), insertOnly: GOVERNANCE_COLUMNS, rows: targets },\n ...(schema?.itemType\n ? [{ table: \"ui.ui_surface_item_type\", conflict: [\"surface_name\", \"name\"], insertOnly: GOVERNANCE_COLUMNS, rows: itemTypes }]\n : []),\n ...extensionTables.values(),\n ];\n return { surfaces, tables: tables.filter((table) => table.rows.length > 0), keys };\n}\n\n/** One row's key under `columns` (a missing column reads as ''). */\nexport function mirrorRowKey(row: Readonly<Record<string, unknown>>, columns: readonly string[]): string {\n return columns.map((column) => String(row[column] ?? \"\")).join(\"\\u0000\");\n}\n\n/**\n * Rows of `table` that belong to a surface this plan manages but that the\n * plan no longer declares, judged by the table's full key (`plan.keys`) — so\n * a screen value and an item value that share a name are distinct rows. The\n * caller deletes each returned row filtered by every column of that key.\n */\nexport function findStaleRows<R extends Readonly<Record<string, unknown>>>(\n plan: SurfaceSyncPlan,\n table: string,\n existing: readonly R[],\n): R[] {\n const key = plan.keys[table];\n if (!key) {\n throw new Error(\n `Sync plan declares no key for \"${table}\"; give the extension that owns it a \\`mirror\\` entry.`,\n );\n }\n const managed = new Set(plan.surfaces.map((surface) => surface.name));\n const declared = new Set(\n (plan.tables.find((entry) => entry.table === table)?.rows ?? []).map((row) => mirrorRowKey(row, key)),\n );\n return existing.filter(\n (row) => managed.has(String(row.surface_name)) && !declared.has(mirrorRowKey(row, key)),\n );\n}\n\n/** Every column a table's rows carry, in first-seen order. */\nexport function planColumns(table: SyncTablePlan): string[] {\n const columns: string[] = [];\n for (const row of table.rows) for (const key of Object.keys(row)) if (!columns.includes(key)) columns.push(key);\n return columns;\n}\n\n/** Columns a conflict rewrites: everything except the key and the insert-only set. */\nexport function conflictUpdateColumns(table: SyncTablePlan): string[] {\n return planColumns(table).filter((c) => !table.conflict.includes(c) && !table.insertOnly.includes(c));\n}\n\nexport function sqlLiteral(value: Json | undefined): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"boolean\" || typeof value === \"number\") return String(value);\n if (typeof value === \"string\") return `'${value.replace(/'/g, \"''\")}'`;\n if (Array.isArray(value) && value.every((entry) => typeof entry === \"string\")) {\n return `ARRAY[${value.map((entry) => sqlLiteral(entry)).join(\", \")}]::text[]`;\n }\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'::jsonb`;\n}\n\n/**\n * The plan as SQL statements, one per entry: surface insert, one UPDATE per\n * surface, one upsert per table. Callers may run them, or EXPLAIN each one in a\n * read-only transaction to prove the plan against a live schema with no write.\n */\nexport function renderSurfaceSyncStatements(plan: SurfaceSyncPlan): string[] {\n const statements: string[] = [];\n if (plan.surfaces.length > 0) {\n const insertColumns = Object.keys(plan.surfaces[0]!.insert);\n statements.push(\n `INSERT INTO ui.ui_surface (${insertColumns.join(\", \")}) VALUES\\n${plan.surfaces\n .map((s) => `(${insertColumns.map((c) => sqlLiteral(s.insert[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (name) DO NOTHING`,\n );\n for (const s of plan.surfaces) {\n statements.push(\n `UPDATE ui.ui_surface SET ${Object.entries(s.update)\n .map(([c, v]) => `${c} = ${sqlLiteral(v)}`)\n .join(\", \")}, updated_at = now() WHERE name = ${sqlLiteral(s.name)}`,\n );\n }\n }\n for (const table of plan.tables) {\n const columns = planColumns(table);\n const sets = conflictUpdateColumns(table).map((c) => `${c} = EXCLUDED.${c}`);\n statements.push(\n `INSERT INTO ${table.table} (${columns.join(\", \")}) VALUES\\n${table.rows\n .map((row) => `(${columns.map((c) => sqlLiteral(row[c])).join(\", \")})`)\n .join(\",\\n\")}\\nON CONFLICT (${table.conflict.join(\", \")}) DO UPDATE SET ${[...sets, \"updated_at = now()\"].join(\", \")}`,\n );\n }\n return statements;\n}\n\n/** The plan as one SQL script (governance columns insert-only). */\nexport function renderSurfaceSyncSql(plan: SurfaceSyncPlan): string {\n return renderSurfaceSyncStatements(plan)\n .map((statement) => `${statement};`)\n .join(\"\\n\\n\");\n}\n","/**\n * The declaration half of the route check (CONTRACT §2.6 `/checks`): does each\n * declared `urlPattern` address a live route? The host supplies its route list\n * (it owns the filesystem); the matching rule lives here, once. Ported from\n * matrx-frontend `scripts/check-surface-routes.ts` (ALC-14).\n */\n\n/** Route or pattern → segments; `[x]` / `:x` → \"*\", `[...x]` / `[[...x]]` → \"**\". */\nexport function routeSegments(path: string): string[] {\n return (path.split(\"?\")[0] ?? \"\")\n .split(\"#\")[0]!\n .split(\"/\")\n .filter(Boolean)\n .map((segment) => {\n if (/^\\[\\[?\\.\\.\\..+\\]\\]?$/.test(segment)) return \"**\";\n if (segment.startsWith(\"[\") || segment.startsWith(\":\")) return \"*\";\n return segment;\n });\n}\n\n/**\n * Does a declared `urlPattern` address a live route? A literal pattern segment\n * must be a literal route segment — a dynamic route segment does NOT satisfy it,\n * or `/marketing/[brandId]/…` would \"cover\" a retired `/marketing/brands/…`.\n * A trailing `*` makes the pattern a prefix.\n */\nexport function urlPatternMatchesRoute(pattern: string, route: readonly string[]): boolean {\n const isPrefix = pattern.trimEnd().endsWith(\"*\") && !pattern.endsWith(\"]*\");\n const segments = routeSegments(pattern.replace(/\\*+\\s*$/, \"\"));\n for (let i = 0; i < segments.length; i += 1) {\n const routeSegment = route[i];\n if (routeSegment === \"**\") return true;\n if (routeSegment === undefined) return false;\n const declared = segments[i];\n if (declared === \"**\") return true;\n if (declared === \"*\" ? routeSegment !== \"*\" : routeSegment !== declared) return false;\n }\n return isPrefix || route.length === segments.length;\n}\n\n/** Every declaration whose `urlPattern` no live route can produce. */\nexport function findDeadUrlPatterns(\n declarations: readonly { surfaceName: string; urlPattern?: string | undefined }[],\n liveRoutes: readonly string[],\n): { surfaceName: string; urlPattern: string }[] {\n const routes = liveRoutes.map(routeSegments);\n const dead: { surfaceName: string; urlPattern: string }[] = [];\n for (const declaration of declarations) {\n const pattern = declaration.urlPattern;\n if (!pattern) continue;\n if (!routes.some((route) => urlPatternMatchesRoute(pattern, route))) {\n dead.push({ surfaceName: declaration.surfaceName, urlPattern: pattern });\n }\n }\n return dead;\n}\n"],"mappings":"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","names":[]}
|
package/dist/core.cjs
CHANGED
|
@@ -24,7 +24,7 @@ ${summary}<data format="${dataFormat}">
|
|
|
24
24
|
`;)i++;spans.push({path,start,end:i});let last=index===paths.length-1,expected=last?`
|
|
25
25
|
`:delimiter;if(!(last&&i===text.length)){if(text[i]!==expected)throw spanError(`Expected ${last?"a line break":"a delimiter"} at character ${i}.`);last||i++}}),linePath!==null&&(spans[lineSlot].end=i),i<text.length&&i++};readLine(columns.map(c=>`/columns/${pointerSegment(c.id)}`),null);for(let row=0;row<rowCount;row++)readLine(columns.map(c=>`/rows/${row}${c.path}`),`/rows/${row}`);if(i<text.length)throw spanError(`Text continues after the last row at character ${i}.`);return spans}function markdownTableSpans(text,columns,rowCount){let spans=[],lines=[],at2=0;for(let line of text.split(`
|
|
26
26
|
`))lines.push({start:at2,end:at2+line.length}),at2+=line.length+1;if(lines.length!==rowCount+2)throw spanError(`A Markdown table of ${rowCount} rows has ${lines.length} lines.`);let cells=(line,paths)=>{let i=line.start;if(text.slice(i,i+2)!=="| ")throw spanError(`A table line must open with "| " at character ${i}.`);if(i+=2,paths.forEach(path=>{let start=i;for(;i<line.end&&text[i]!=="|";)i+=text[i]==="\\"?2:1;if(text[i]!=="|"||text[i-1]!==" ")throw spanError(`A table cell must close with " |" at character ${i}.`);spans.push({path,start,end:i-1}),i+=2}),i-1!==line.end)throw spanError(`A table line has more cells than columns at character ${i}.`)};cells(lines[0],columns.map(c=>`/columns/${pointerSegment(c.id)}`));for(let row=0;row<rowCount;row++){let line=lines[row+2];spans.push({path:`/rows/${row}`,start:line.start,end:line.end}),cells(line,columns.map(c=>`/rows/${row}${c.path}`))}return spans}function spanMap(draft,artifact){if(artifact.snapshotId!==draft.snapshotId||artifact.draftRevision!==draft.revision)throw spanError("This artifact was built from a different draft, so its spans cannot be read from this one. Seal the current draft again.");let text=artifact.plainText,payload=draft.payload,format=artifact.format;if(format==="json"||format==="compact-json")return jsonTextSpans(text,payload.kind==="rows"?"/rows":"");if(format==="csv"||format==="tsv"){if(payload.kind!=="rows")throw spanError(`${format.toUpperCase()} requires tabular data`);return delimitedSpans(text,format==="csv"?",":" ",exportedColumns(payload.columns),payload.rows.length)}if(format!=="plain"&&format!=="markdown"&&format!=="html")throw spanError(`The ${format} format has no text span map; spans cover plain, Markdown, JSON, CSV and TSV text.`);if(payload.kind==="rows"){let columns=exportedColumns(payload.columns);return format==="markdown"?markdownTableSpans(text,columns,payload.rows.length):delimitedSpans(text," ",columns,payload.rows.length)}if(payload.kind==="json"||payload.kind==="registered")return jsonTextSpans(text);if(payload.kind==="text"&&payload.language&&format==="markdown"){if(fencedCodeBlock(payload.text,payload.language)!==text)throw spanError("The Markdown code block does not hold this draft's text.");let start=text.indexOf(`
|
|
27
|
-
`)+1;return[{path:"",start,end:start+payload.text.length}]}return[{path:"",start:0,end:text.length}]}function offsetSpans(spans,offset){return spans.map(s=>({path:s.path,start:s.start+offset,end:s.end+offset}))}function agentPayloadWithSpans(input,environment={}){let{text,body,bodyOffset}=assembleAgentPayload(input,environment);return(input.dataFormat??"json")!=="json"?{text,spans:[{path:"",start:bodyOffset,end:bodyOffset+body.length}]}:{text,spans:jsonTextSpans(body,"",bodyOffset)}}init_core();var EMPTY_STRUCTURE=Object.freeze({exclude:Object.freeze([]),limits:Object.freeze({})}),encode=segment=>segment.replace(/~/g,"~0").replace(/\//g,"~1"),decode=segment=>segment.replace(/~1/g,"/").replace(/~0/g,"~");function pointerSegments(pointer){if(pointer==="")return[];if(!pointer.startsWith("/"))throw new ContentTransferError("invalid-pointer",`"${pointer}" is not a JSON Pointer (it must start with "/").`);return pointer.slice(1).split("/").map(decode)}function joinPointer(segments){return segments.map(segment=>`/${encode(segment)}`).join("")}function patternMatches(pattern,pointer){let p=pointerSegments(pattern),s=pointerSegments(pointer);return p.length===s.length&&p.every((segment,index)=>segment==="*"||segment===s[index])}function patternCovers(pattern,pointer){let p=pointerSegments(pattern),s=pointerSegments(pointer);return p.length<=s.length&&p.every((segment,index)=>segment==="*"||segment===s[index])}function patternBelow(pattern,pointer){let p=pointerSegments(pattern),s=pointerSegments(pointer);return p.length>s.length&&s.every((segment,index)=>p[index]==="*"||p[index]===segment)}function displayPath(pointer,root="data"){let out=root;for(let segment of pointerSegments(pointer))segment==="*"||/^(0|[1-9]\d*)$/.test(segment)?out+=`[${segment}]`:/^[A-Za-z_$][\w$]*$/.test(segment)?out+=`${out?".":""}${segment}`:out+=`[${JSON.stringify(segment)}]`;return out}var sizes=new WeakMap;function jsonSize(value){if(value===null)return 4;if(typeof value=="string")return JSON.stringify(value).length;if(typeof value=="number")return(JSON.stringify(value)??"null").length;if(typeof value=="boolean")return value?4:5;let cached=sizes.get(value);if(cached!==void 0)return cached;let total=2;if(Array.isArray(value))value.forEach((item,index)=>{total+=jsonSize(item)+(index?1:0)});else{let index=0;for(let[key,item]of Object.entries(value))total+=JSON.stringify(key).length+1+jsonSize(item)+(index++?1:0)}return sizes.set(value,total),total}function nodeChars(value){return typeof value=="string"?value.length:jsonSize(value)}var n=value=>
|
|
27
|
+
`)+1;return[{path:"",start,end:start+payload.text.length}]}return[{path:"",start:0,end:text.length}]}function offsetSpans(spans,offset){return spans.map(s=>({path:s.path,start:s.start+offset,end:s.end+offset}))}function agentPayloadWithSpans(input,environment={}){let{text,body,bodyOffset}=assembleAgentPayload(input,environment);return(input.dataFormat??"json")!=="json"?{text,spans:[{path:"",start:bodyOffset,end:bodyOffset+body.length}]}:{text,spans:jsonTextSpans(body,"",bodyOffset)}}var import_format=require("@ai-matrx/kit/format");init_core();var EMPTY_STRUCTURE=Object.freeze({exclude:Object.freeze([]),limits:Object.freeze({})}),encode=segment=>segment.replace(/~/g,"~0").replace(/\//g,"~1"),decode=segment=>segment.replace(/~1/g,"/").replace(/~0/g,"~");function pointerSegments(pointer){if(pointer==="")return[];if(!pointer.startsWith("/"))throw new ContentTransferError("invalid-pointer",`"${pointer}" is not a JSON Pointer (it must start with "/").`);return pointer.slice(1).split("/").map(decode)}function joinPointer(segments){return segments.map(segment=>`/${encode(segment)}`).join("")}function patternMatches(pattern,pointer){let p=pointerSegments(pattern),s=pointerSegments(pointer);return p.length===s.length&&p.every((segment,index)=>segment==="*"||segment===s[index])}function patternCovers(pattern,pointer){let p=pointerSegments(pattern),s=pointerSegments(pointer);return p.length<=s.length&&p.every((segment,index)=>segment==="*"||segment===s[index])}function patternBelow(pattern,pointer){let p=pointerSegments(pattern),s=pointerSegments(pointer);return p.length>s.length&&s.every((segment,index)=>p[index]==="*"||p[index]===segment)}function displayPath(pointer,root="data"){let out=root;for(let segment of pointerSegments(pointer))segment==="*"||/^(0|[1-9]\d*)$/.test(segment)?out+=`[${segment}]`:/^[A-Za-z_$][\w$]*$/.test(segment)?out+=`${out?".":""}${segment}`:out+=`[${JSON.stringify(segment)}]`;return out}var sizes=new WeakMap;function jsonSize(value){if(value===null)return 4;if(typeof value=="string")return JSON.stringify(value).length;if(typeof value=="number")return(JSON.stringify(value)??"null").length;if(typeof value=="boolean")return value?4:5;let cached=sizes.get(value);if(cached!==void 0)return cached;let total=2;if(Array.isArray(value))value.forEach((item,index)=>{total+=jsonSize(item)+(index?1:0)});else{let index=0;for(let[key,item]of Object.entries(value))total+=JSON.stringify(key).length+1+jsonSize(item)+(index++?1:0)}return sizes.set(value,total),total}function nodeChars(value){return typeof value=="string"?value.length:jsonSize(value)}var n=value=>(0,import_format.formatCount)(value,{locale:"en-US"});function stubText(value){let chars=n(nodeChars(value));if(typeof value=="string"){let first=(value.split(`
|
|
28
28
|
`,1)[0]??"").trim(),head=first.length>120?`${first.slice(0,120)}\u2026`:first;return`${head?`${head} `:""}[stubbed \u2014 ${chars} chars]`}if(Array.isArray(value))return`[stubbed \u2014 ${n(value.length)} items, ${chars} chars]`;if(value&&typeof value=="object"){let header=Object.entries(value).filter(([,item])=>typeof item=="string"&&item.length<=60&&!item.includes(`
|
|
29
29
|
`)||typeof item=="number"||typeof item=="boolean").slice(0,4).map(([key,item])=>`${key}: ${String(item)}`);return`[stubbed \u2014 ${header.length?`${header.join(", ")} \u2014 `:""}${n(Object.keys(value).length)} keys, ${chars} chars]`}return`[stubbed \u2014 ${chars} chars]`}function truncateText(text,max){return text.length>max?`${text.slice(0,max)} \u2026 [truncated \u2014 ${n(text.length)} chars]`:text}function assertLimit2(limit,pattern){if(limit.kind!=="stub"&&(!Number.isSafeInteger(limit.value)||limit.value<0))throw new ContentTransferError("invalid-limit",`The limit on ${displayPath(pattern)} must be a whole number of 0 or more.`)}function concretePointers(value,pattern){let want=pointerSegments(pattern),out=[],walk=(node,depth,at2)=>{if(depth===want.length){out.push(joinPointer(at2));return}if(node===null||typeof node!="object")return;let segment=want[depth],entries=Array.isArray(node)?node.map((item,index)=>[String(index),item]):Object.entries(node);for(let[key,child]of entries)(segment==="*"||segment===key)&&walk(child,depth+1,[...at2,key])};return walk(value,0,[]),out}function applyStructureToJson(value,recipe,labels={}){recipe.exclude.forEach(pattern=>pointerSegments(pattern));let limitEntries=Object.entries(recipe.limits);limitEntries.forEach(([pattern,limit])=>{pointerSegments(pattern),assertLimit2(limit,pattern)});let excluded=new Map,limited=new Map,tally=(map,pattern,chars)=>{let current=map.get(pattern)??{count:0,chars:0};map.set(pattern,{count:current.count+1,chars:current.chars+chars})},walk=(node,segments,cap)=>{let pointer=joinPointer(segments),exclusion=segments.length?recipe.exclude.find(pattern=>patternMatches(pattern,pointer)):void 0;if(exclusion!==void 0){tally(excluded,exclusion,nodeChars(node));return}let limitEntry=limitEntries.find(([pattern])=>patternMatches(pattern,pointer)),limit=limitEntry?.[1];if(limitEntry&&limit?.kind==="stub")return tally(limited,limitEntry[0],nodeChars(node)),stubText(node);let nextCap=limitEntry&&limit?.kind==="maxChars"?{pattern:limitEntry[0],max:limit.value}:cap;if(typeof node=="string")return nextCap&&node.length>nextCap.max?(tally(limited,nextCap.pattern,node.length),truncateText(node,nextCap.max)):node;if(node===null||typeof node!="object")return node;if(Array.isArray(node)){let items=node.map((item,index)=>walk(item,[...segments,String(index)],nextCap)).filter(item=>item!==void 0);return limitEntry&&limit?.kind==="maxItems"&&items.length>limit.value&&(tally(limited,limitEntry[0],items.length-limit.value),items=[...items.slice(0,limit.value),`[\u2026 ${n(items.length-limit.value)} more items]`]),items}let out={};for(let[key,item]of Object.entries(node)){let kept=walk(item,[...segments,key],nextCap);kept!==void 0&&(out[key]=kept)}return out},next=walk(value,[],null)??null,omissions=[];for(let[pattern,{count,chars}]of excluded)omissions.push({path:pattern,reason:"excluded",count,label:labels[pattern]??`${displayPath(pattern)} \u2014 ${n(chars)} chars`});for(let[pattern,{count,chars}]of limited){let limit=recipe.limits[pattern],what=limit.kind==="stub"?`stubbed (${n(chars)} chars)`:limit.kind==="maxChars"?`cut to ${n(limit.value)} chars`:`kept the first ${n(limit.value)} items`;omissions.push({path:pattern,reason:"truncated",count,label:`${labels[pattern]??displayPath(pattern)} \u2014 ${what}`})}return{value:next,omissions}}function applyJsonStructure(draft,recipe,labels={}){let payload=draft.payload;if(payload.kind!=="json"&&payload.kind!=="registered"||!recipe.exclude.length&&!Object.keys(recipe.limits).length)return draft;let{value,omissions}=applyStructureToJson(payload.value,recipe,labels);return deriveDraft(draft,{...payload,value},omissions,"Structure choices")}function outputPointer(value,recipe,pointer){let segments=pointerSegments(pointer),out=[],node=value;for(let depth=0;depth<=segments.length;depth++){let here=joinPointer(segments.slice(0,depth));if(depth>0&&recipe.exclude.some(pattern=>patternMatches(pattern,here)))return null;let limitEntry=Object.entries(recipe.limits).find(([pattern])=>patternMatches(pattern,here));if(limitEntry?.[1].kind==="stub"||depth===segments.length)return joinPointer(out);let segment=segments[depth];if(node===null||typeof node!="object"||node===void 0)return null;if(Array.isArray(node)){let index=Number(segment);if(!Number.isSafeInteger(index)||index>=node.length)return null;let shifted=index;for(let j=0;j<index;j++)recipe.exclude.some(pattern=>patternMatches(pattern,`${here}/${j}`))&&shifted--;if(limitEntry?.[1].kind==="maxItems"&&shifted>=limitEntry[1].value)return null;out.push(String(shifted)),node=node[index]}else{if(!Object.prototype.hasOwnProperty.call(node,segment))return null;out.push(segment),node=node[segment]}}return joinPointer(out)}var RANGE=/^\/text\/(\d+)-(\d+)$/;function isProseSection(section){return RANGE.test(section.path)}function sectionLayout(text,sections,included,limits={}){let keep=new Set(included),parsed=sections.map(section=>{let m=RANGE.exec(section.path),start=m?Number(m[1]):NaN,end=m?Number(m[2]):NaN;if(!m||start>end||end>text.length)throw new ContentTransferError("invalid-section",`Section "${section.path}" is not a range of this text. Declare a prose section as /text/<start>-<end> within the text.`);let limit=limits[section.id];return limit&&assertLimit2(limit,section.path),{section,start,end,limit}}).sort((a,b)=>a.start-b.start),out="",at2=0,omissions=[],ranges={};for(let{section,start,end,limit}of parsed){if(start<at2)throw new ContentTransferError("invalid-section",`Section "${section.label}" overlaps the section before it.`);out+=text.slice(at2,start),at2=end;let body=text.slice(start,end);if(!keep.has(section.id)){omissions.push({path:section.path,reason:"excluded",label:`${section.label} \u2014 ${n(body.length)} chars`});continue}let trailing=/\s*$/.exec(body)?.[0]??"",written=body;limit?.kind==="stub"?(written=`${stubText(body.slice(0,body.length-trailing.length))}${trailing}`,omissions.push({path:section.path,reason:"truncated",label:`${section.label} \u2014 stubbed (${n(body.length)} chars)`})):limit?.kind==="maxChars"&&body.length-trailing.length>limit.value&&(written=`${truncateText(body.slice(0,body.length-trailing.length),limit.value)}${trailing}`,omissions.push({path:section.path,reason:"truncated",label:`${section.label} \u2014 cut to ${n(limit.value)} chars`})),ranges[section.id]={start:out.length,end:out.length+written.length-trailing.length},out+=written}return out+=text.slice(at2),{text:out,omissions,ranges}}function applySectionStructure(draft,sections,included,limits={}){let payload=draft.payload;if(payload.kind==="text"||payload.kind==="markdown"){let layout=sectionLayout(payload.text,sections,included,limits);return deriveDraft(draft,{...payload,text:layout.text},layout.omissions,"Selected sections")}if(payload.kind==="json"||payload.kind==="registered"){let keep=new Set(included),labels=Object.fromEntries(sections.map(section=>[section.path,section.label])),recipe={exclude:sections.filter(section=>!keep.has(section.id)).map(section=>section.path),limits:Object.fromEntries(sections.filter(section=>keep.has(section.id)&&limits[section.id]).map(section=>[section.path,limits[section.id]]))},{value,omissions}=applyStructureToJson(payload.value,recipe,labels);return deriveDraft(draft,{...payload,value},omissions,"Selected sections")}return draft}init_core();var TRANSFER_DEFAULT_RECIPE_SETTING="alchemy.transfer.default_recipe",KEY=/^[a-z0-9][a-z0-9._:-]{0,127}$/;function recipeKey(sourceKind){if(!KEY.test(sourceKind))throw new ContentTransferError("invalid-recipe-key",`"${sourceKind}" is not a source-kind id (lowercase letters, digits and . _ : -, up to 128 characters).`);return sourceKind}var isRecord=v=>v!==null&&typeof v=="object"&&!Array.isArray(v);async function resolveDefaultRecipe(ports,sourceKind,organizationId){let key=recipeKey(sourceKind),notices=[],skip=(error,sentence,remedy)=>{notices.push({sentence,remedy}),ports.diagnostics.capture(error,{area:"operate",detail:{recipeKey:key,sentence}})};if(ports.persistence)try{let own=await ports.persistence.readSetting(TRANSFER_DEFAULT_RECIPE_SETTING);if(own!==null){if(!isRecord(own))skip(new Error("person default recipes are not a map"),"Your saved default recipes could not be read (they are not a list of recipes), so they were skipped.","Save your default recipe for this source again.");else if(own[key]!==void 0){let recipe=own[key];if(isRecord(recipe))return{recipe,from:"person",notices};skip(new Error("person default recipe is not an object"),"Your default recipe for this source is not a recipe, so it was skipped.","Save your default recipe for this source again.")}}}catch(error){skip(error,"Your own default recipe could not be read, so the organization's default applies.","Reopen the workspace to try again.")}if(ports.transferKnobs)try{let org=await ports.transferKnobs.defaultRecipe(key,organizationId);if(org!==null){if(isRecord(org))return{recipe:org,from:"organization",notices};skip(new Error("organization default recipe is not an object"),"Your organization's default recipe for this source is not a recipe, so it was skipped.","Ask an organization admin to set the default recipe again.")}}catch(error){skip(error,"Your organization's default recipe could not be read, so the workspace opens on Full.","Reopen the workspace to try again.")}return{recipe:null,from:"built-in",notices}}async function setPersonDefaultRecipe(ports,sourceKind,recipe){let key=recipeKey(sourceKind),persistence=ports.persistence;if(!persistence)throw new ContentTransferError("capability-absent","This app cannot save your own settings, so a personal default recipe is not available here.");let current;try{current=await persistence.readSetting(TRANSFER_DEFAULT_RECIPE_SETTING)}catch(error){let reason=error instanceof Error?error.message:String(error);throw new ContentTransferError("read-failed",`Nothing was saved: your other default recipes could not be read (${reason}), and saving now would have replaced all of them. Try again in a moment.`)}if(current!==null&&!isRecord(current))throw new ContentTransferError("invalid-setting","Nothing was saved: your saved default recipes are not a list of recipes, so one cannot be changed without replacing them all.");let map={...current??{}};if(recipe===null){if(!(key in map))return;delete map[key]}else map[key]=recipe;await persistence.writeSetting(TRANSFER_DEFAULT_RECIPE_SETTING,Object.keys(map).length===0?null:map)}
|
|
30
30
|
//# sourceMappingURL=core.cjs.map
|