@happyvertical/smrt-core 0.45.3 → 0.47.0
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/AGENTS.md +39 -0
- package/agents/generators.md +0 -1
- package/dist/browser.d.ts +2 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/decorators/compatibility.d.ts +46 -0
- package/dist/decorators/compatibility.d.ts.map +1 -1
- package/dist/decorators/compatibility.js +48 -5
- package/dist/decorators/compatibility.js.map +1 -1
- package/dist/decorators/index.d.ts +119 -1
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +52 -8
- package/dist/decorators/index.js.map +1 -1
- package/dist/embedded-write-queue.d.ts.map +1 -1
- package/dist/embedded-write-queue.js +20 -1
- package/dist/embedded-write-queue.js.map +1 -1
- package/dist/generators/custom-action.d.ts +450 -41
- package/dist/generators/custom-action.d.ts.map +1 -1
- package/dist/generators/custom-action.js +765 -56
- package/dist/generators/custom-action.js.map +1 -1
- package/dist/generators/index.d.ts +1 -3
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +3 -4
- package/dist/generators/mcp.d.ts.map +1 -1
- package/dist/generators/mcp.js +1 -1
- package/dist/generators/mcp.js.map +1 -1
- package/dist/generators/preflight-route.d.ts +12 -10
- package/dist/generators/preflight-route.d.ts.map +1 -1
- package/dist/generators/preflight-route.js +46 -14
- package/dist/generators/preflight-route.js.map +1 -1
- package/dist/generators/rest.d.ts +44 -0
- package/dist/generators/rest.d.ts.map +1 -1
- package/dist/generators/rest.js +84 -9
- package/dist/generators/rest.js.map +1 -1
- package/dist/generators/tenant-gate.d.ts +33 -9
- package/dist/generators/tenant-gate.d.ts.map +1 -1
- package/dist/generators/tenant-gate.js +2 -1
- package/dist/generators/tenant-gate.js.map +1 -1
- package/dist/generators.js +3 -4
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/knowledge.d.ts.map +1 -1
- package/dist/knowledge.js +87 -31
- package/dist/knowledge.js.map +1 -1
- package/dist/manifest/static-manifest.d.ts.map +1 -1
- package/dist/manifest/static-manifest.js +125 -53
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest.json +184 -53
- package/dist/migrations/framework-base-tables.d.ts +148 -0
- package/dist/migrations/framework-base-tables.d.ts.map +1 -0
- package/dist/migrations/framework-base-tables.js +419 -0
- package/dist/migrations/framework-base-tables.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +2 -1
- package/dist/migrations.js +2 -1
- package/dist/postgres-permissions.d.ts +45 -0
- package/dist/postgres-permissions.d.ts.map +1 -0
- package/dist/postgres-permissions.js +424 -0
- package/dist/postgres-permissions.js.map +1 -0
- package/dist/registry/framework-base-classes.d.ts.map +1 -1
- package/dist/registry/framework-base-classes.js +4 -1
- package/dist/registry/framework-base-classes.js.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/shared-state.d.ts +19 -0
- package/dist/registry/shared-state.d.ts.map +1 -1
- package/dist/registry/shared-state.js +16 -1
- package/dist/registry/shared-state.js.map +1 -1
- package/dist/registry.d.ts +136 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +231 -1
- package/dist/registry.js.map +1 -1
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +18 -16
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/scanner/types.d.ts +59 -6
- package/dist/scanner/types.d.ts.map +1 -1
- package/dist/scanner/types.js.map +1 -1
- package/dist/scripts/create-wrappers.js +0 -5
- package/dist/smrt-knowledge.json +35 -35
- package/dist/testing/database.d.ts +6 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +9 -1
- package/dist/testing/database.js.map +1 -1
- package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
- package/dist/vite-plugin/api-client-entries.js +23 -19
- package/dist/vite-plugin/api-client-entries.js.map +1 -1
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +3 -167
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts +31 -4
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +137 -71
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/templates/default-ui.ts +22 -1
- package/dist/vite-plugin/web-collections.d.ts.map +1 -1
- package/dist/vite-plugin/web-collections.js +1 -1
- package/dist/vite-plugin/web-collections.js.map +1 -1
- package/package.json +10 -10
- package/dist/generators/cli.d.ts +0 -155
- package/dist/generators/cli.d.ts.map +0 -1
- package/dist/generators/cli.js +0 -473
- package/dist/generators/cli.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-permissions.js","names":[],"sources":["../src/postgres-permissions.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n CREATE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION,\n CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION,\n POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY,\n POSTGRES_CHANGE_FEED_DRAIN_BATCH,\n POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY,\n} from './system/schema.js';\n\n/** PostgreSQL ACLs only; this is not application authorization or RLS. */\nexport interface PostgresPermissionContract {\n schema: string;\n /** Defaults affect every future object created by migrationOwner in schema. */\n schemaExclusive: true;\n migrationOwner: string;\n runtimeRole: string;\n managedTables: string[];\n /** Exact zero-argument trigger functions bound only to managed tables. */\n managedTriggerFunctions?: string[];\n monitor?: { role: string; tables: Record<string, string[]> };\n}\n\nexport interface PostgresPermissionDiagnostic {\n code: string;\n severity: 'missing' | 'excessive' | 'unsupported';\n role?: string;\n resource: string;\n message: string;\n}\n\nexport interface PostgresPermissionPlan {\n contract: PostgresPermissionContract;\n diagnostics: PostgresPermissionDiagnostic[];\n statements: string[];\n canApply: boolean;\n fingerprint: string;\n limitations: string[];\n}\n\ntype NormalizedPostgresPermissionContract = PostgresPermissionContract & {\n managedTriggerFunctions: string[];\n};\n\ntype Executor = Pick<DatabaseInterface, 'query'>;\ninterface Row {\n [key: string]: unknown;\n oid: string;\n name: string;\n schema: string;\n identity: string;\n argument_types: string;\n argument_count: string;\n argument_defaults: string | null;\n return_type: string;\n result: string;\n cost: string;\n rows: string;\n support: string;\n language: string;\n security_definer: boolean;\n config: unknown;\n source: string;\n volatility: string;\n parallel: string;\n leakproof: boolean;\n strict: boolean;\n function_oid: string;\n table_name: string;\n enabled: string;\n internal: boolean;\n owner: string;\n acl: Acl[];\n kind: string;\n rolname: string;\n member: string;\n parent: string;\n relation: string;\n version: string;\n executor: string;\n superuser: boolean;\n rls: boolean;\n}\ntype Acl = {\n grantee: string;\n privilege: string;\n grantable: boolean;\n grantor?: string;\n};\nconst bookkeeping = new Set([\n '_smrt_migrations',\n '_smrt_schema_migrations',\n '_smrt_backfills',\n]);\nconst identifier = (value: string) => `\"${value.replaceAll('\"', '\"\"')}\"`;\nconst literal = (value: string) =>\n `E'${value.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"''\")}'`;\nconst qualified = (schema: string, name: string) =>\n `${identifier(schema)}.${identifier(name)}`;\n\nconst normalizeFunctionSource = (value: string) =>\n value.replaceAll('\\r\\n', '\\n').trim();\nconst normalizeArgumentTypes = (value: string) =>\n value.replaceAll(/\\s*,\\s*/g, ',');\nconst normalizeFunctionResult = (value: string) =>\n value\n .replaceAll(/\\s+/g, ' ')\n .replaceAll(/\\s*,\\s*/g, ',')\n .replaceAll(/\\(\\s*/g, '(')\n .replaceAll(/\\s*\\)/g, ')')\n .trim()\n .toLowerCase();\n\nfunction sourceFromFunctionDdl(ddl: string): string {\n const match = ddl.match(\n /\\bAS\\s+\\$([A-Za-z_][A-Za-z0-9_]*)\\$\\n([\\s\\S]*?)\\n\\$\\1\\$;/,\n );\n if (!match)\n throw new Error('Framework function DDL has no dollar-quoted body.');\n return normalizeFunctionSource(match[2]);\n}\n\nfunction resultFromFunctionDdl(ddl: string): string {\n const match = ddl.match(/\\bRETURNS\\s+([\\s\\S]*?)\\nLANGUAGE\\s+/);\n if (!match) throw new Error('Framework function DDL has no return result.');\n return normalizeFunctionResult(match[1]);\n}\n\ntype FrameworkRoutine = {\n name: string;\n argumentTypes: string;\n argumentDefaults: string | null;\n result: string;\n source: string;\n};\n\nfunction frameworkRoutine(identity: string, ddl: string): FrameworkRoutine {\n const match = identity.match(/^([^()]+)\\((.*)\\)$/);\n if (!match)\n throw new Error(`Invalid framework function identity: ${identity}`);\n return {\n name: match[1],\n argumentTypes: normalizeArgumentTypes(match[2]),\n argumentDefaults:\n match[1] === '_smrt_drain_changes'\n ? String(POSTGRES_CHANGE_FEED_DRAIN_BATCH)\n : null,\n result: resultFromFunctionDdl(ddl),\n source: sourceFromFunctionDdl(ddl),\n };\n}\n\nconst frameworkRoutines = [\n frameworkRoutine(\n POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY,\n CREATE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION,\n ),\n frameworkRoutine(\n POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY,\n CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION,\n ),\n];\n\nfunction object(\n value: unknown,\n keys: string[],\n label: string,\n): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} must be an object.`);\n }\n for (const key of Object.keys(value)) {\n if (!keys.includes(key))\n throw new Error(`Unknown ${label} property: ${key}.`);\n }\n return value as Record<string, unknown>;\n}\nfunction name(value: unknown, label: string): string {\n if (\n typeof value !== 'string' ||\n !value.length ||\n value.includes('\\0') ||\n Buffer.byteLength(value) > 63\n ) {\n throw new Error(\n `${label} must be a nonempty PostgreSQL identifier (at most 63 bytes).`,\n );\n }\n return value;\n}\n/** Validate configuration before opening a connection; unknown options fail closed. */\nexport function validatePostgresPermissionContract(\n value: unknown,\n): NormalizedPostgresPermissionContract {\n const input = object(\n value,\n [\n 'schema',\n 'schemaExclusive',\n 'migrationOwner',\n 'runtimeRole',\n 'managedTables',\n 'managedTriggerFunctions',\n 'monitor',\n ],\n 'postgresPermissions',\n );\n if (input.schemaExclusive !== true)\n throw new Error(\n 'postgresPermissions.schemaExclusive must explicitly be true.',\n );\n const schema = name(input.schema, 'schema');\n if (schema === 'information_schema' || schema.startsWith('pg_'))\n throw new Error('A dedicated application schema is required.');\n const migrationOwner = name(input.migrationOwner, 'migrationOwner');\n const runtimeRole = name(input.runtimeRole, 'runtimeRole');\n if (!Array.isArray(input.managedTables))\n throw new Error('managedTables must be an array.');\n const managedTables = [\n ...new Set(\n input.managedTables.map((table) => name(table, 'managedTables entry')),\n ),\n ].sort();\n if (\n input.managedTriggerFunctions !== undefined &&\n !Array.isArray(input.managedTriggerFunctions)\n )\n throw new Error('managedTriggerFunctions must be an array.');\n const managedTriggerFunctions = [\n ...new Set(\n (input.managedTriggerFunctions ?? []).map((routine) =>\n name(routine, 'managedTriggerFunctions entry'),\n ),\n ),\n ].sort();\n let monitor: PostgresPermissionContract['monitor'];\n if (input.monitor !== undefined) {\n const entry = object(input.monitor, ['role', 'tables'], 'monitor');\n const role = name(entry.role, 'monitor.role');\n if (\n !entry.tables ||\n typeof entry.tables !== 'object' ||\n Array.isArray(entry.tables)\n )\n throw new Error('monitor.tables must map tables to column arrays.');\n const tables: Record<string, string[]> = Object.create(null);\n for (const [table, columns] of Object.entries(entry.tables).sort(\n ([a], [b]) => a.localeCompare(b),\n )) {\n name(table, 'monitor table');\n if (!Array.isArray(columns) || !columns.length)\n throw new Error(\n `monitor table ${table} requires a nonempty column array.`,\n );\n tables[table] = [\n ...new Set(columns.map((column) => name(column, 'monitor column'))),\n ].sort();\n }\n monitor = { role, tables };\n }\n const roles = [\n migrationOwner,\n runtimeRole,\n ...(monitor ? [monitor.role] : []),\n ];\n if (\n new Set(roles).size !== roles.length ||\n roles.some(\n (role) => role.toUpperCase() === 'PUBLIC' || role.startsWith('pg_'),\n )\n )\n throw new Error(\n 'Migration, runtime and monitor roles must be distinct non-system roles.',\n );\n return {\n schema,\n schemaExclusive: true,\n migrationOwner,\n runtimeRole,\n managedTables,\n managedTriggerFunctions,\n ...(monitor ? { monitor } : {}),\n };\n}\n\nconst acl = (expression: string) =>\n `COALESCE((SELECT json_agg(json_build_object('grantee', CASE WHEN a.grantee = 0 THEN 'PUBLIC' ELSE pg_get_userbyid(a.grantee) END, 'grantor', pg_get_userbyid(a.grantor), 'privilege', a.privilege_type, 'grantable', a.is_grantable) ORDER BY a.grantee, a.privilege_type, a.grantor) FROM aclexplode(${expression}) a), '[]'::json)`;\n\nasync function snapshot(\n db: Executor,\n contract: NormalizedPostgresPermissionContract,\n): Promise<Record<string, Row[]>> {\n const roleNames = [\n contract.migrationOwner,\n contract.runtimeRole,\n ...(contract.monitor ? [contract.monitor.role] : []),\n ]\n .map(literal)\n .join(',');\n const restrictedRoleNames = [\n contract.runtimeRole,\n ...(contract.monitor ? [contract.monitor.role] : []),\n ]\n .map(literal)\n .join(',');\n // information_schema.sql runs after initial ACL recording. Trust only its\n // explicitly PUBLIC-readable stock relations, never internal metadata views.\n // Normal-operation OIDs start at 16384:\n // https://www.postgresql.org/docs/16/system-catalog-initial-data.html\n // Source: postgres/postgres REL_14_STABLE..REL_18_STABLE,\n // GRANT SELECT [ON TABLE] ... TO PUBLIC in:\n // https://github.com/postgres/postgres/blob/REL_14_STABLE/src/backend/catalog/information_schema.sql\n // https://github.com/postgres/postgres/blob/REL_18_STABLE/src/backend/catalog/information_schema.sql\n const informationSchemaPublicSelect =\n \"'administrable_role_authorizations','applicable_roles','attributes','character_sets','check_constraint_routine_usage','check_constraints','collation_character_set_applicability','collations','column_column_usage','column_domain_usage','column_options','column_privileges','column_udt_usage','columns','constraint_column_usage','constraint_table_usage','data_type_privileges','domain_constraints','domain_udt_usage','domains','element_types','enabled_roles','foreign_data_wrapper_options','foreign_data_wrappers','foreign_server_options','foreign_servers','foreign_table_options','foreign_tables','information_schema_catalog_name','key_column_usage','parameters','referential_constraints','role_column_grants','role_routine_grants','role_table_grants','role_udt_grants','role_usage_grants','routine_column_usage','routine_privileges','routine_routine_usage','routine_sequence_usage','routine_table_usage','routines','schemata','sequences','sql_features','sql_implementation_info','sql_sizing','table_constraints','table_privileges','tables','triggered_update_columns','triggers','udt_privileges','usage_privileges','user_defined_types','user_mapping_options','user_mappings','view_column_usage','view_routine_usage','view_table_usage','views'\";\n // pg_init_privs records non-default initial ACLs. Missing entries use the\n // PostgreSQL object-kind default; extension-provided ACLs are not stock trust.\n // https://www.postgresql.org/docs/current/catalog-pg-init-privs.html\n const initialAcl = (fallback: string) =>\n `CASE WHEN i.privtype='i' THEN i.initprivs WHEN i.privtype='e' THEN NULL::aclitem[] ELSE ${fallback} END`;\n // Only a type referenced by another type's typarray is its generated array.\n // Nonzero typelem also describes non-array types (point); domains over arrays\n // remain independent privilege targets and must not be filtered out.\n const queries: Record<string, string> = {\n server: `SELECT current_setting('server_version_num') AS version, current_database() AS database, current_user AS executor, (SELECT rolsuper FROM pg_roles WHERE rolname=current_user) AS superuser`,\n roles: `SELECT oid::text, rolname, rolsuper, rolcreaterole, rolcreatedb, rolreplication, rolbypassrls FROM pg_roles WHERE rolname IN (${roleNames}) ORDER BY rolname`,\n memberships: `SELECT pg_get_userbyid(member) AS member, pg_get_userbyid(roleid) AS parent FROM pg_auth_members WHERE member IN (SELECT oid FROM pg_roles WHERE rolname IN (${roleNames})) OR roleid IN (SELECT oid FROM pg_roles WHERE rolname IN (${roleNames})) ORDER BY member, roleid`,\n database: `SELECT datname AS name, pg_get_userbyid(datdba) AS owner, ${acl(\"COALESCE(datacl, acldefault('d',datdba))\")} AS acl FROM pg_database WHERE datname=current_database()`,\n schemas: `SELECT nspname AS name, pg_get_userbyid(nspowner) AS owner, ${acl(\"COALESCE(nspacl, acldefault('n',nspowner))\")} AS acl FROM pg_namespace WHERE left(nspname,3) <> 'pg_' AND nspname <> 'information_schema' ORDER BY nspname`,\n relations: `SELECT c.oid::text, n.nspname AS schema, c.relname AS name, c.relkind AS kind, pg_get_userbyid(c.relowner) AS owner, c.relrowsecurity AS rls, ${acl(\"COALESCE(c.relacl, acldefault(CASE WHEN c.relkind='S' THEN 's'::\\\"char\\\" ELSE 'r'::\\\"char\\\" END,c.relowner))\")} AS acl FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE left(n.nspname,3) <> 'pg_' AND n.nspname <> 'information_schema' AND c.relkind IN ('r','p','v','m','f','S') ORDER BY n.nspname,c.relname`,\n columns: `SELECT c.oid::text AS relation, a.attname AS name, ${acl('a.attacl')} AS acl FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid JOIN pg_namespace n ON n.oid=c.relnamespace WHERE left(n.nspname,3) <> 'pg_' AND n.nspname <> 'information_schema' AND c.relkind IN ('r','p','v','m','f') AND a.attnum>0 AND NOT a.attisdropped ORDER BY c.oid,a.attnum`,\n routines: `SELECT n.nspname AS schema, p.oid::text, p.proname AS name, format('%I.%I(%s)', n.nspname, p.proname, oidvectortypes(p.proargtypes)) AS identity, oidvectortypes(p.proargtypes) AS argument_types, pg_get_expr(p.proargdefaults,0) AS argument_defaults, p.prokind AS kind, p.prorettype::regtype::text AS return_type, pg_get_function_result(p.oid) AS result, p.procost::text AS cost, p.prorows::text AS rows, p.prosupport::regproc::text AS support, p.pronargs::text AS argument_count, l.lanname AS language, p.prosecdef AS security_definer, p.provolatile::text AS volatility, p.proparallel::text AS parallel, p.proleakproof AS leakproof, p.proisstrict AS strict, COALESCE(to_json(p.proconfig),'[]'::json) AS config, p.prosrc AS source, CASE WHEN p.prokind='f' THEN pg_get_functiondef(p.oid) END AS definition, pg_get_userbyid(p.proowner) AS owner, ${acl(\"COALESCE(p.proacl, acldefault('f',p.proowner))\")} AS acl FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace JOIN pg_language l ON l.oid=p.prolang WHERE left(n.nspname,3) <> 'pg_' AND n.nspname <> 'information_schema' ORDER BY n.nspname,p.oid`,\n triggers: `SELECT t.oid::text, n.nspname AS schema, c.relname AS table_name, t.tgname AS name, t.tgfoid::text AS function_oid, t.tgenabled AS enabled, t.tgisinternal AS internal, t.tgtype::text AS type, encode(t.tgargs,'hex') AS arguments, pg_get_triggerdef(t.oid, true) AS definition FROM pg_trigger t JOIN pg_class c ON c.oid=t.tgrelid JOIN pg_namespace n ON n.oid=c.relnamespace WHERE left(n.nspname,3) <> 'pg_' AND n.nspname <> 'information_schema' ORDER BY n.nspname,c.oid,t.oid`,\n types: `SELECT n.nspname AS schema, t.typname AS name, pg_get_userbyid(t.typowner) AS owner, ${acl(\"COALESCE(t.typacl, acldefault('T',t.typowner))\")} AS acl FROM pg_type t JOIN pg_namespace n ON n.oid=t.typnamespace LEFT JOIN pg_class c ON c.oid=t.typrelid WHERE left(n.nspname,3) <> 'pg_' AND n.nspname <> 'information_schema' AND NOT EXISTS (SELECT 1 FROM pg_type element WHERE element.typarray=t.oid) AND (t.typrelid=0 OR c.relkind='c') ORDER BY n.nspname,t.typname`,\n systemSchemas: `SELECT nspname AS name, pg_get_userbyid(nspowner) AS owner, ${acl(\"COALESCE(nspacl, acldefault('n',nspowner))\")} AS acl FROM pg_namespace WHERE left(nspname,3)='pg_' OR nspname='information_schema' ORDER BY nspname`,\n systemPrivileges: `WITH resources AS (\n SELECT n.nspname AS schema, c.relname AS name, c.oid::text AS oid, CASE WHEN c.relkind='S' THEN 'sequence' ELSE 'relation' END AS kind, pg_get_userbyid(c.relowner) AS owner,\n COALESCE(c.relacl,acldefault(CASE WHEN c.relkind='S' THEN 's'::\"char\" ELSE 'r'::\"char\" END,c.relowner)) AS current_acl,\n CASE WHEN i.objoid IS NULL AND n.nspname='information_schema' AND c.oid<16384 AND c.relname IN (${informationSchemaPublicSelect}) THEN ARRAY[makeaclitem(0,c.relowner,'SELECT',false)] ELSE ${initialAcl(\"acldefault(CASE WHEN c.relkind='S' THEN 's'::\\\"char\\\" ELSE 'r'::\\\"char\\\" END,c.relowner)\")} END AS initial_acl\n FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace\n LEFT JOIN pg_init_privs i ON i.objoid=c.oid AND i.classoid='pg_class'::regclass AND i.objsubid=0\n WHERE (left(n.nspname,3)='pg_' OR n.nspname='information_schema') AND c.relkind IN ('r','p','v','m','f','S')\n UNION ALL\n SELECT n.nspname, c.relname || '.' || a.attname, c.oid::text || ':' || a.attnum::text, 'column', pg_get_userbyid(c.relowner),\n a.attacl, ${initialAcl('NULL::aclitem[]')}\n FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid JOIN pg_namespace n ON n.oid=c.relnamespace\n LEFT JOIN pg_init_privs i ON i.objoid=c.oid AND i.classoid='pg_class'::regclass AND i.objsubid=a.attnum\n WHERE (left(n.nspname,3)='pg_' OR n.nspname='information_schema') AND a.attnum>0 AND NOT a.attisdropped\n UNION ALL\n SELECT n.nspname, p.proname, p.oid::text, 'routine', pg_get_userbyid(p.proowner), COALESCE(p.proacl,acldefault('f',p.proowner)), ${initialAcl(\"CASE WHEN p.oid<16384 THEN acldefault('f',p.proowner) ELSE NULL::aclitem[] END\")}\n FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace\n LEFT JOIN pg_init_privs i ON i.objoid=p.oid AND i.classoid='pg_proc'::regclass AND i.objsubid=0\n WHERE left(n.nspname,3)='pg_' OR n.nspname='information_schema'\n UNION ALL\n SELECT n.nspname, t.typname, t.oid::text, 'type', pg_get_userbyid(t.typowner), COALESCE(t.typacl,acldefault('T',t.typowner)), ${initialAcl(\"CASE WHEN t.oid<16384 THEN acldefault('T',t.typowner) ELSE NULL::aclitem[] END\")}\n FROM pg_type t JOIN pg_namespace n ON n.oid=t.typnamespace LEFT JOIN pg_class c ON c.oid=t.typrelid\n LEFT JOIN pg_init_privs i ON i.objoid=t.oid AND i.classoid='pg_type'::regclass AND i.objsubid=0\n WHERE (left(n.nspname,3)='pg_' OR n.nspname='information_schema') AND NOT EXISTS (SELECT 1 FROM pg_type element WHERE element.typarray=t.oid) AND (t.typrelid=0 OR c.relkind='c')\n ) SELECT r.schema,r.name,r.oid,r.kind,r.owner,COALESCE(d.acl,'[]'::json) AS acl FROM resources r\n CROSS JOIN LATERAL (\n SELECT json_agg(json_build_object('grantee', CASE WHEN a.grantee=0 THEN 'PUBLIC' ELSE pg_get_userbyid(a.grantee) END,\n 'grantor',pg_get_userbyid(a.grantor),'privilege',a.privilege_type,'grantable',a.is_grantable)\n ORDER BY a.grantee,a.privilege_type,a.grantor) AS acl\n FROM aclexplode(r.current_acl) a\n WHERE a.grantee IN (SELECT oid FROM pg_roles WHERE rolname IN (${restrictedRoleNames}))\n OR (a.grantee=0 AND NOT EXISTS (SELECT 1 FROM aclexplode(r.initial_acl) b WHERE b.grantee=0 AND b.privilege_type=a.privilege_type AND (b.is_grantable OR NOT a.is_grantable)))\n ) d WHERE d.acl IS NOT NULL OR (r.kind<>'column' AND r.owner IN (${restrictedRoleNames})) ORDER BY r.schema,r.kind,r.name,r.oid`,\n largeObjects: `SELECT oid::text, pg_get_userbyid(lomowner) AS owner, ${acl(\"COALESCE(lomacl, acldefault('L',lomowner))\")} AS acl FROM pg_largeobject_metadata ORDER BY oid`,\n largeObjectSettings: `SELECT setting,reset_val,source FROM pg_settings WHERE name='lo_compat_privileges'`,\n largeObjectRoleSettings: `SELECT s.setdatabase::text AS database, CASE WHEN s.setrole=0 THEN 'ALL ROLES' ELSE pg_get_userbyid(s.setrole) END AS role, split_part(config.value,'=',2) AS setting FROM pg_db_role_setting s CROSS JOIN LATERAL unnest(s.setconfig) config(value) WHERE s.setdatabase IN (0,(SELECT oid FROM pg_database WHERE datname=current_database())) AND (s.setrole=0 OR s.setrole IN (SELECT oid FROM pg_roles WHERE rolname IN (${restrictedRoleNames}))) AND split_part(config.value,'=',1)='lo_compat_privileges' ORDER BY s.setdatabase,s.setrole,config.value`,\n parameters: `SELECT parname AS name, ${acl('paracl')} AS acl FROM pg_parameter_acl ORDER BY parname`,\n defaults: `SELECT pg_get_userbyid(d.defaclrole) AS owner, COALESCE(n.nspname,'') AS schema, d.defaclobjtype AS kind, ${acl('d.defaclacl')} AS acl FROM pg_default_acl d LEFT JOIN pg_namespace n ON n.oid=d.defaclnamespace ORDER BY d.defaclrole,d.defaclnamespace,d.defaclobjtype`,\n };\n const result: Record<string, Row[]> = {};\n // A transaction executor must never have concurrent statements dispatched to it.\n for (const [key, query] of Object.entries(queries)) {\n // Parameter ACLs were introduced in PostgreSQL 15.\n if (key === 'parameters' && Number(result.server[0].version) < 150000) {\n result[key] = [];\n continue;\n }\n result[key] = (await db.query(query)).rows as Row[];\n }\n return result;\n}\n\nasync function plan(\n db: Executor,\n input: unknown,\n): Promise<PostgresPermissionPlan> {\n const contract = validatePostgresPermissionContract(input);\n const state = await snapshot(db, contract);\n const diagnostics: PostgresPermissionDiagnostic[] = [];\n const statements: string[] = [];\n const roles = [\n contract.runtimeRole,\n ...(contract.monitor ? [contract.monitor.role] : []),\n ];\n const add = (\n severity: PostgresPermissionDiagnostic['severity'],\n code: string,\n resource: string,\n message: string,\n role?: string,\n ) =>\n diagnostics.push({\n severity,\n code,\n resource,\n message,\n ...(role ? { role } : {}),\n });\n const unsupported = (\n code: string,\n resource: string,\n message: string,\n role?: string,\n ) => add('unsupported', code, resource, message, role);\n if (Number(state.server[0].version) < 140000)\n unsupported(\n 'server-version',\n 'database',\n 'PostgreSQL 14 or later is required.',\n );\n for (const role of [contract.migrationOwner, ...roles]) {\n const row = state.roles.find((entry) => entry.rolname === role);\n if (!row) {\n unsupported(\n 'missing-role',\n role,\n 'Infrastructure must create this role.',\n role,\n );\n continue;\n }\n if (\n roles.includes(role) &&\n [\n 'rolsuper',\n 'rolcreaterole',\n 'rolcreatedb',\n 'rolreplication',\n 'rolbypassrls',\n ].some((key) => row[key])\n )\n unsupported(\n 'privileged-role',\n role,\n 'Remove SUPERUSER, CREATEROLE, CREATEDB, REPLICATION and BYPASSRLS authority using infrastructure role management.',\n role,\n );\n }\n for (const membership of state.memberships)\n unsupported(\n 'role-membership',\n membership.member,\n `Role ${membership.member} is a member of ${membership.parent}; inbound and outbound membership, inherited privileges, and SET ROLE authority require infrastructure review. Memberships are never modified.`,\n membership.member,\n );\n const schema = state.schemas.find((entry) => entry.name === contract.schema);\n if (!schema)\n unsupported(\n 'missing-schema',\n contract.schema,\n 'Create the dedicated schema as the migration owner before reconciliation.',\n );\n else if (schema.owner !== contract.migrationOwner)\n unsupported(\n 'schema-owner',\n contract.schema,\n `Schema must be owned by ${contract.migrationOwner}; ownership is never changed.`,\n );\n const database = state.database[0];\n if (roles.includes(database.owner))\n unsupported(\n 'database-owner',\n database.name,\n 'Runtime and monitor must not own the database.',\n database.owner,\n );\n\n const relevant = (entries: Acl[], role: string) =>\n entries.filter(\n (entry) => entry.grantee === role || entry.grantee === 'PUBLIC',\n );\n function reconcile(\n kind: string,\n resource: string,\n entries: Acl[],\n role: string,\n desired: string[],\n suffix = '',\n ) {\n for (const entry of entries)\n if (entry.grantor === role && entry.grantee !== role)\n unsupported(\n 'dependent-grant',\n resource,\n `Configured role granted ${entry.privilege} to ${entry.grantee}; grant chains require infrastructure review to preserve other roles.`,\n role,\n );\n for (const entry of entries) {\n if (\n entry.grantee === 'PUBLIC' &&\n !(\n kind === 'DATABASE' &&\n entry.privilege === 'CONNECT' &&\n !entry.grantable\n )\n ) {\n unsupported(\n 'public-privilege',\n resource,\n `PUBLIC ${entry.privilege} is outside the explicit role contract; infrastructure must review it without changing unrelated access.`,\n role,\n );\n }\n }\n const effective = relevant(entries, role);\n const excess = effective.filter(\n (entry) => !desired.includes(entry.privilege) || entry.grantable,\n );\n const missing = desired.filter(\n (privilege) =>\n !entries.some(\n (entry) => entry.grantee === role && entry.privilege === privilege,\n ),\n );\n for (const entry of excess) {\n add(\n 'excessive',\n 'excessive-privilege',\n resource,\n `${entry.privilege}${entry.grantable ? ' WITH GRANT OPTION' : ''} is not declared (source: ${entry.grantee}).`,\n role,\n );\n if (entry.grantee === 'PUBLIC')\n unsupported(\n 'public-privilege',\n resource,\n `PUBLIC ${entry.privilege} requires infrastructure review; revoking it would affect other roles.`,\n role,\n );\n }\n for (const privilege of missing)\n add(\n 'missing',\n 'missing-privilege',\n resource,\n `${privilege} is required.`,\n role,\n );\n if (!excess.length && !missing.length) return;\n statements.push(\n `REVOKE ALL PRIVILEGES${suffix} ON ${kind} ${resource} FROM ${identifier(role)}`,\n );\n if (desired.length)\n statements.push(\n `GRANT ${desired.join(', ')}${suffix} ON ${kind} ${resource} TO ${identifier(role)}`,\n );\n }\n function reconcileRoutine(\n resource: string,\n entries: Acl[],\n desiredByRole: ReadonlyMap<string, readonly string[]>,\n ) {\n const grantee = (role: string) =>\n role === 'PUBLIC' ? 'PUBLIC' : identifier(role);\n for (const entry of entries)\n if (\n roles.includes(entry.grantor ?? '') &&\n entry.grantee !== entry.grantor\n )\n unsupported(\n 'dependent-routine-grant',\n resource,\n `Configured role granted ${entry.privilege} to ${entry.grantee}; grant chains require infrastructure review to preserve other roles.`,\n entry.grantor,\n );\n const managedGrantees = new Set([\n contract.migrationOwner,\n ...roles,\n 'PUBLIC',\n ]);\n for (const entry of entries)\n if (!managedGrantees.has(entry.grantee))\n unsupported(\n 'outside-routine-grant',\n resource,\n `${entry.grantee} has ${entry.privilege}; direct routine access outside the declared roles requires infrastructure review.`,\n entry.grantee,\n );\n for (const role of [...roles, 'PUBLIC']) {\n const desired = desiredByRole.get(role) ?? [];\n const effective = entries.filter((entry) => entry.grantee === role);\n const excess = effective.filter(\n (entry) => !desired.includes(entry.privilege) || entry.grantable,\n );\n const missing = desired.filter(\n (privilege) =>\n !entries.some(\n (entry) => entry.grantee === role && entry.privilege === privilege,\n ),\n );\n for (const entry of excess)\n add(\n 'excessive',\n 'excessive-routine-privilege',\n resource,\n `${entry.privilege}${entry.grantable ? ' WITH GRANT OPTION' : ''} is not declared.`,\n role,\n );\n for (const privilege of missing)\n add(\n 'missing',\n 'missing-routine-privilege',\n resource,\n `${privilege} is required.`,\n role,\n );\n if (!excess.length && !missing.length) continue;\n statements.push(\n `REVOKE ALL PRIVILEGES ON FUNCTION ${resource} FROM ${grantee(role)}`,\n );\n if (desired.length)\n statements.push(\n `GRANT ${desired.join(', ')} ON FUNCTION ${resource} TO ${grantee(role)}`,\n );\n }\n }\n for (const role of roles) {\n reconcile('DATABASE', identifier(database.name), database.acl, role, [\n 'CONNECT',\n ]);\n for (const entry of state.schemas) {\n if (entry.owner === role)\n unsupported(\n 'resource-owner',\n entry.name,\n 'Configured role owns a schema and has DDL authority.',\n role,\n );\n if (entry.name === contract.schema)\n reconcile('SCHEMA', identifier(entry.name), entry.acl, role, ['USAGE']);\n else if (\n relevant(entry.acl, role).some((grant) => grant.privilege === 'CREATE')\n )\n unsupported(\n 'outside-schema-create',\n entry.name,\n 'Effective CREATE outside the dedicated schema requires infrastructure repair.',\n role,\n );\n }\n }\n for (const schema of state.systemSchemas) {\n for (const role of roles) {\n if (schema.owner === role) {\n unsupported(\n 'system-schema-owner',\n schema.name,\n 'Configured roles must not own system schemas; infrastructure must restore separate ownership. System schema ownership is never modified.',\n role,\n );\n }\n for (const grant of relevant(schema.acl, role)) {\n if (grant.privilege === 'CREATE') {\n unsupported(\n 'system-schema-authority',\n schema.name,\n `Effective CREATE on a system schema (source: ${grant.grantee}) gives DDL authority and requires infrastructure repair. System schema ACLs are never modified.`,\n role,\n );\n }\n }\n }\n }\n for (const resource of state.systemPrivileges) {\n if (resource.kind !== 'column' && roles.includes(resource.owner)) {\n unsupported(\n 'system-object-owner',\n qualified(resource.schema, resource.name),\n `Configured role owns a system ${resource.kind}; ownership retains implicit alteration and grant authority even when its ordinary ACLs are revoked. Infrastructure must restore ownership; SMRT never changes it.`,\n resource.owner,\n );\n }\n for (const grant of resource.acl) {\n unsupported(\n 'system-privilege-delta',\n qualified(resource.schema, resource.name),\n `${grant.grantee} has exceptional ${grant.privilege}${grant.grantable ? ' WITH GRANT OPTION' : ''} on a system ${resource.kind}; review infrastructure grants against PostgreSQL initial ACLs. System ACLs are never modified.`,\n grant.grantee === 'PUBLIC' ? undefined : grant.grantee,\n );\n }\n }\n for (const resource of state.largeObjects) {\n if (roles.includes(resource.owner)) {\n unsupported(\n 'large-object-owner',\n `large object ${resource.oid}`,\n 'Configured role owns a large object outside the declared table/column contract. Infrastructure must review ownership; SMRT never changes it.',\n resource.owner,\n );\n }\n for (const grant of resource.acl) {\n if (roles.includes(grant.grantee) || grant.grantee === 'PUBLIC') {\n unsupported(\n 'large-object-privilege',\n `large object ${resource.oid}`,\n `${grant.grantee} has ${grant.privilege}${grant.grantable ? ' WITH GRANT OPTION' : ''} outside the declared table/column contract. Infrastructure must review this ACL; SMRT neither reads payloads nor changes large-object permissions.`,\n grant.grantee === 'PUBLIC' ? undefined : grant.grantee,\n );\n }\n }\n }\n const explicitlyOff = (value: unknown) =>\n ['off', 'false', 'no', '0'].includes(String(value).toLowerCase());\n if (state.largeObjectSettings.length !== 1) {\n unsupported(\n 'large-object-compatibility',\n 'lo_compat_privileges',\n 'The large-object ACL compatibility setting could not be established; qualification requires an observable disabled setting.',\n );\n }\n for (const settings of state.largeObjectSettings) {\n if (\n !explicitlyOff(settings.setting) ||\n !explicitlyOff(settings.reset_val) ||\n !['default', 'configuration file', 'command line', 'database'].includes(\n String(settings.source),\n )\n ) {\n unsupported(\n 'large-object-compatibility',\n 'lo_compat_privileges',\n 'Large-object ACL checks must be enabled for every configured role. An enabled or operator-specific lo_compat_privileges override cannot establish that baseline; review deployment settings and reconnect without an operator-specific override.',\n );\n }\n }\n for (const settings of state.largeObjectRoleSettings) {\n if (!explicitlyOff(settings.setting)) {\n unsupported(\n 'large-object-compatibility',\n 'lo_compat_privileges',\n `Role/database defaults enable or do not establish large-object ACL checks (${String(settings.role)}, database OID ${String(settings.database)}). Infrastructure must disable compatibility mode before qualification.`,\n settings.role === 'ALL ROLES' ? undefined : String(settings.role),\n );\n }\n }\n for (const parameter of state.parameters) {\n for (const role of roles) {\n for (const grant of relevant(parameter.acl, role)) {\n unsupported(\n 'parameter-privilege',\n parameter.name,\n `Effective ${grant.privilege} on a PostgreSQL configuration parameter (source: ${grant.grantee}) requires infrastructure review; parameter ACLs are never modified.`,\n role,\n );\n }\n }\n }\n const tables = state.relations.filter(\n (entry) => entry.schema === contract.schema && entry.kind !== 'S',\n );\n for (const table of bookkeeping) {\n if (!tables.some((entry) => entry.name === table)) {\n unsupported(\n 'missing-bookkeeping-table',\n qualified(contract.schema, table),\n 'Bootstrap all framework bookkeeping tables as the migration owner before permission setup. Stop runtime and monitoring access during migrations or restores, then reconcile before reactivation.',\n );\n }\n }\n const declared = new Set(contract.managedTables);\n // Framework feature tables are owned by SMRT even when absent from manifests.\n for (const table of tables)\n if (table.name.startsWith('_smrt_')) declared.add(table.name);\n for (const table of declared)\n if (!tables.some((entry) => entry.name === table))\n unsupported(\n 'missing-table',\n qualified(contract.schema, table),\n 'Run supported schema migrations before reconciling permissions.',\n );\n for (const [table, columns] of Object.entries(\n contract.monitor?.tables ?? {},\n )) {\n const relation = tables.find((entry) => entry.name === table);\n if (!declared.has(table) || !relation)\n unsupported(\n 'monitor-table',\n table,\n 'Monitor tables must exist and belong to managedTables or framework tables.',\n );\n for (const column of columns)\n if (\n !relation ||\n !state.columns.some(\n (entry) => entry.relation === relation.oid && entry.name === column,\n )\n )\n unsupported(\n 'monitor-column',\n `${table}.${column}`,\n 'The declared monitoring column does not exist.',\n );\n }\n for (const relation of state.relations) {\n const resource = qualified(relation.schema, relation.name);\n const columns = state.columns.filter(\n (entry) => entry.relation === relation.oid,\n );\n if (relation.schema !== contract.schema) {\n for (const role of roles)\n if (\n relation.owner === role ||\n relevant(relation.acl, role).length ||\n columns.some((column) => relevant(column.acl, role).length)\n )\n unsupported(\n 'outside-resource-access',\n resource,\n 'Effective access to an unrelated relation requires infrastructure review; unrelated ACLs are preserved.',\n role,\n );\n continue;\n }\n if (relation.owner !== contract.migrationOwner)\n unsupported(\n 'resource-owner',\n resource,\n `Managed resources must be owned by ${contract.migrationOwner}; ownership is never changed.`,\n );\n if (relation.kind !== 'S' && !declared.has(relation.name))\n unsupported(\n 'undeclared-table',\n resource,\n 'The dedicated schema contains an undeclared table; defaults cannot safely cover a mixed schema.',\n );\n if (!['r', 'p', 'S'].includes(relation.kind))\n unsupported(\n 'unsupported-relation',\n resource,\n `Relation kind ${relation.kind} requires a separate security review.`,\n );\n if (relation.rls)\n unsupported(\n 'row-level-security',\n resource,\n 'RLS policies require a separate application authorization review; ACL verification cannot establish allowed row operations.',\n );\n for (const role of roles) {\n const isRuntime = role === contract.runtimeRole;\n const desired = isRuntime\n ? relation.kind === 'S'\n ? ['USAGE']\n : bookkeeping.has(relation.name)\n ? ['SELECT']\n : ['SELECT', 'INSERT', 'UPDATE', 'DELETE']\n : [];\n reconcile(\n relation.kind === 'S' ? 'SEQUENCE' : 'TABLE',\n resource,\n relation.acl,\n role,\n desired,\n );\n for (const column of columns) {\n const wanted =\n !isRuntime &&\n (contract.monitor?.tables[relation.name] ?? []).includes(column.name)\n ? ['SELECT']\n : [];\n reconcile(\n 'TABLE',\n resource,\n column.acl,\n role,\n wanted,\n ` (${identifier(column.name)})`,\n );\n }\n }\n }\n const triggerRoutineNames = new Set(contract.managedTriggerFunctions);\n const acceptedTriggerRoutineNames = new Set<string>();\n const routineConfigIsEmpty = (value: unknown) =>\n (Array.isArray(value) && value.length === 0) || value === '[]';\n for (const resource of state.routines) {\n const resourceName = qualified(resource.schema, resource.name);\n const framework = frameworkRoutines.find(\n (expected) =>\n resource.schema === contract.schema &&\n resource.name === expected.name &&\n normalizeArgumentTypes(resource.argument_types) ===\n expected.argumentTypes,\n );\n if (framework) {\n const valid =\n resource.owner === contract.migrationOwner &&\n resource.kind === 'f' &&\n resource.language === 'plpgsql' &&\n resource.security_definer === false &&\n resource.argument_defaults === framework.argumentDefaults &&\n normalizeFunctionResult(resource.result) === framework.result &&\n resource.cost === '100' &&\n resource.rows === '1000' &&\n resource.support === '-' &&\n resource.volatility === 'v' &&\n resource.parallel === 'u' &&\n resource.leakproof === false &&\n resource.strict === false &&\n routineConfigIsEmpty(resource.config) &&\n normalizeFunctionSource(String(resource.source)) === framework.source;\n if (!valid)\n unsupported(\n 'framework-routine-definition',\n resourceName,\n 'Framework routine must retain its canonical identity, owner, invoker security, defaults, execution properties, settings and generated body.',\n );\n else\n reconcileRoutine(\n resource.identity,\n resource.acl,\n new Map([[contract.runtimeRole, ['EXECUTE']]]),\n );\n continue;\n }\n const bindings = state.triggers.filter(\n (trigger) => trigger.function_oid === resource.oid,\n );\n const triggerRoutine =\n resource.schema === contract.schema &&\n triggerRoutineNames.has(resource.name) &&\n resource.kind === 'f' &&\n resource.return_type === 'trigger' &&\n resource.argument_types === '' &&\n resource.argument_count === '0' &&\n resource.owner === contract.migrationOwner &&\n resource.language === 'plpgsql' &&\n resource.security_definer === false &&\n routineConfigIsEmpty(resource.config) &&\n bindings.length > 0 &&\n bindings.every(\n (trigger) =>\n trigger.schema === contract.schema &&\n trigger.internal === false &&\n (trigger.enabled === 'O' || trigger.enabled === 'A') &&\n declared.has(trigger.table_name),\n );\n if (triggerRoutine) {\n acceptedTriggerRoutineNames.add(resource.name);\n reconcileRoutine(resource.identity, resource.acl, new Map());\n continue;\n }\n for (const role of roles)\n if (\n resource.schema === contract.schema ||\n resource.owner === role ||\n relevant(resource.acl, role).length\n )\n unsupported(\n 'unsupported-routines',\n resourceName,\n triggerRoutineNames.has(resource.name)\n ? 'Declared trigger routines must be migration-owner invoker PL/pgSQL functions returning trigger with no declared arguments, no function settings, and enabled non-internal bindings only to declared managed tables.'\n : 'User-defined routines are outside the supported table/sequence and declared trigger contract; review their effective privileges explicitly.',\n role,\n );\n }\n for (const name of triggerRoutineNames)\n if (!acceptedTriggerRoutineNames.has(name))\n unsupported(\n 'missing-managed-trigger-function',\n qualified(contract.schema, name),\n 'Run the migration that creates this exact managed trigger function and its enabled binding before reconciling permissions.',\n );\n for (const resource of state.types)\n for (const role of roles)\n if (\n resource.schema === contract.schema ||\n resource.owner === role ||\n relevant(resource.acl, role).length\n )\n unsupported(\n 'unsupported-types',\n qualified(resource.schema, resource.name),\n 'User-defined types are outside the supported table/sequence contract; review their effective privileges explicitly.',\n role,\n );\n // Global grants combine with schema grants: a schema REVOKE cannot cancel them.\n for (const defaults of state.defaults) {\n const resource = `DEFAULT ${defaults.kind} (${defaults.schema || 'global'})`;\n if (\n defaults.owner !== contract.migrationOwner &&\n defaults.acl.some((entry: Acl) => roles.includes(entry.grantee))\n )\n unsupported(\n 'other-creator-access',\n resource,\n `Creator ${defaults.owner} grants configured roles future access outside this contract.`,\n );\n if (\n defaults.schema !== contract.schema &&\n defaults.schema !== '' &&\n defaults.acl.some(\n (entry: Acl) =>\n entry.grantee === 'PUBLIC' || roles.includes(entry.grantee),\n )\n )\n unsupported(\n 'outside-default-privilege',\n resource,\n 'Defaults outside the managed schema grant future access and require infrastructure review.',\n );\n if (\n defaults.schema === '' &&\n defaults.acl.some(\n (entry: Acl) =>\n roles.includes(entry.grantee) ||\n (entry.grantee === 'PUBLIC' &&\n ['r', 'S', 'n'].includes(defaults.kind)),\n )\n )\n unsupported(\n 'global-default-privilege',\n resource,\n 'Global creator defaults grant configured roles or PUBLIC access and cannot be repaired within this schema.',\n );\n if (\n defaults.schema === contract.schema &&\n defaults.owner !== contract.migrationOwner\n )\n unsupported(\n 'other-creator-default',\n resource,\n `Defaults for creator ${defaults.owner} require separate ownership review.`,\n );\n if (\n defaults.schema === contract.schema &&\n !['r', 'S'].includes(defaults.kind) &&\n defaults.acl.some(\n (entry: Acl) =>\n roles.includes(entry.grantee) || entry.grantee === 'PUBLIC',\n )\n )\n unsupported(\n 'unsupported-default',\n resource,\n 'Only table and sequence schema defaults are supported.',\n );\n }\n for (const [kind, sqlKind, runtime] of [\n ['r', 'TABLES', ['SELECT', 'INSERT', 'UPDATE', 'DELETE']],\n ['S', 'SEQUENCES', ['USAGE']],\n ] as const) {\n const entry = state.defaults.find(\n (item) =>\n item.schema === contract.schema &&\n item.owner === contract.migrationOwner &&\n item.kind === kind,\n );\n if (entry?.acl.some((grant) => grant.grantee === 'PUBLIC')) {\n unsupported(\n 'public-default',\n `${contract.schema} ${sqlKind}`,\n 'PUBLIC creator defaults are outside the explicit role contract and require infrastructure review.',\n );\n }\n for (const role of roles) {\n const desired: readonly string[] =\n role === contract.runtimeRole ? runtime : [];\n const effective = relevant(entry?.acl ?? [], role);\n const extra = effective.filter(\n (grant) => !desired.includes(grant.privilege) || grant.grantable,\n );\n const missing = desired.filter(\n (privilege) =>\n !(entry?.acl ?? []).some(\n (grant) => grant.grantee === role && grant.privilege === privilege,\n ),\n );\n if (!extra.length && !missing.length) continue;\n for (const grant of extra) {\n add(\n 'excessive',\n 'default-excessive',\n `${contract.schema} ${sqlKind}`,\n `${grant.privilege} default from ${grant.grantee} is not declared.`,\n role,\n );\n if (grant.grantee === 'PUBLIC')\n unsupported(\n 'public-default',\n contract.schema,\n 'PUBLIC defaults affect other roles and require infrastructure repair.',\n );\n }\n for (const privilege of missing)\n add(\n 'missing',\n 'default-missing',\n `${contract.schema} ${sqlKind}`,\n `Creator ${contract.migrationOwner} must default ${privilege}.`,\n role,\n );\n const prefix = `ALTER DEFAULT PRIVILEGES FOR ROLE ${identifier(contract.migrationOwner)} IN SCHEMA ${identifier(contract.schema)}`;\n statements.push(\n `${prefix} REVOKE ALL PRIVILEGES ON ${sqlKind} FROM ${identifier(role)}`,\n );\n if (desired.length)\n statements.push(\n `${prefix} GRANT ${desired.join(', ')} ON ${sqlKind} TO ${identifier(role)}`,\n );\n }\n }\n const executor = state.server[0];\n if (\n statements.length &&\n !executor.superuser &&\n executor.executor !== contract.migrationOwner\n )\n unsupported(\n 'execution-authority',\n 'database',\n 'Apply requires the migration owner or a superuser; plan and apply must use the same actor.',\n );\n if (\n statements.some((sql) => sql.includes(' ON DATABASE ')) &&\n !executor.superuser &&\n database.owner !== executor.executor\n )\n unsupported(\n 'database-authority',\n database.name,\n 'Database ACL remediation requires its owner or a superuser.',\n );\n return {\n contract,\n diagnostics,\n limitations: [\n 'Only PostgreSQL table, column, sequence, schema and database ACLs are qualified; application authorization and RLS are separate. Large-object ownership/access is unsupported, and lo_compat_privileges must remain off for deployed roles.',\n 'Future user-defined routines and types are unsupported. PostgreSQL implicit global defaults grant PUBLIC EXECUTE/USAGE; rerun diagnostics after every migration before activating runtime roles.',\n 'Pause migrations and external ACL/role writers during planning and apply. The advisory lock coordinates SMRT permission writers only.',\n 'All framework bookkeeping tables must exist before setup. Stop runtime and monitor access throughout migrations, restores and repair: recreated bookkeeping tables temporarily receive creator CRUD defaults and require explicit reconciliation before either role is reactivated.',\n ],\n statements: [...new Set(statements)],\n canApply: !diagnostics.some((entry) => entry.severity === 'unsupported'),\n fingerprint: createHash('sha256')\n .update(JSON.stringify({ contract, state }))\n .digest('hex'),\n };\n}\n\n/** Read-only catalog inspection. No application records or credentials are read. */\nexport async function planPostgresPermissions(\n db: Executor,\n contract: PostgresPermissionContract,\n): Promise<PostgresPermissionPlan> {\n return plan(db, contract);\n}\n\n/** Apply the reviewed contract atomically, rejecting stale catalog snapshots. */\nexport async function applyPostgresPermissions(\n db: DatabaseInterface,\n contract: PostgresPermissionContract,\n options: { expectedFingerprint: string },\n): Promise<PostgresPermissionPlan> {\n const normalizedContract = validatePostgresPermissionContract(contract);\n if (!options || !/^[a-f0-9]{64}$/.test(options.expectedFingerprint))\n throw new Error(\n 'An expectedFingerprint from a reviewed permission plan is required.',\n );\n if (!db.transaction)\n throw new Error(\n 'PostgreSQL permissions require a transaction-capable database.',\n );\n return db.transaction(async (tx) => {\n await tx.query(\"SET LOCAL lock_timeout = '5s'\");\n await tx.query(\"SET LOCAL statement_timeout = '30s'\");\n // Cooperating permission writers serialize; operators must quiesce migrations.\n await tx.query(\n `SELECT pg_advisory_xact_lock(hashtext(${literal(`smrt-permissions:${normalizedContract.schema}`)}))`,\n );\n const before = await plan(tx, normalizedContract);\n if (before.fingerprint !== options.expectedFingerprint)\n throw new Error(\n 'Permission plan is stale; generate and review a new plan.',\n );\n if (!before.canApply)\n throw new Error(\n 'Permission plan has unsupported privilege sources or missing prerequisites; resolve its diagnostics first.',\n );\n const executor = (\n await tx.query(\n 'SELECT current_user AS name, rolsuper FROM pg_roles WHERE rolname=current_user',\n )\n ).rows[0];\n if (\n !executor.rolsuper &&\n executor.name !== normalizedContract.migrationOwner\n )\n throw new Error(\n 'Apply must execute as the migration owner or a PostgreSQL superuser.',\n );\n for (const statement of before.statements) await tx.query(statement);\n const after = await plan(tx, normalizedContract);\n if (!after.canApply || after.diagnostics.length)\n throw new Error(\n 'Permission verification failed; all permission changes have been rolled back.',\n );\n return after;\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-base-classes.d.ts","sourceRoot":"","sources":["../../src/registry/framework-base-classes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"framework-base-classes.d.ts","sourceRoot":"","sources":["../../src/registry/framework-base-classes.ts"],"names":[],"mappings":"AAgFA;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,OAAO,CAMT"}
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
* - `./schema-builder.ts` (skips table/DDL generation for these classes)
|
|
21
21
|
* - `../knowledge.ts` (the `.smrt/smrt-knowledge.json` surface projection)
|
|
22
22
|
* - `../generators/mcp.ts` (`MCPGenerator.generateTools()`)
|
|
23
|
-
* - `../generators/cli.ts` (`CLIGenerator.listCommands()`)
|
|
24
23
|
* - `../generators/rest.ts` (`APIGenerator.findClassByCollectionSegment()`)
|
|
25
24
|
* - `../vite-plugin/sveltekit-generator.ts` (REST route generation)
|
|
26
25
|
* - `../vite-plugin/sync-apply-route.ts` (`collectSyncApplyTargets()`)
|
|
@@ -28,6 +27,10 @@
|
|
|
28
27
|
* collection and WebMCP tool selectors)
|
|
29
28
|
* - `@happyvertical/smrt-cli`'s `cli-generator.ts` (the live local `smrt`
|
|
30
29
|
* binary's object command generation), via core's public export
|
|
30
|
+
* - `../testing/database.ts` (`getTestDatabase()` skips table creation for
|
|
31
|
+
* these classes, but only for an implicit `classes` list — an explicit
|
|
32
|
+
* `classes: [...]` caller naming a framework base class is still honored,
|
|
33
|
+
* unlike every unconditional filter above) (#2645)
|
|
31
34
|
*
|
|
32
35
|
* Do not add another hardcoded copy of this list at a new call site — import
|
|
33
36
|
* from here instead.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-base-classes.js","names":[],"sources":["../../src/registry/framework-base-classes.ts"],"sourcesContent":["/**\n * The framework's own abstract base classes, keyed by simple class name to\n * their declaring package.\n *\n * These are scaffolding every application model descends from — they carry\n * no `@smrt()` decorator and have no independent existence as a resource.\n * A foundation package like `@happyvertical/smrt-core` declares them as real\n * local classes (there is no other package for them to live in), so\n * `loadAllManifests()` registers them exactly like any genuine domain class\n * when a consumer installs `@happyvertical/smrt-core` — with no decoration\n * or framework-base filter of its own (#2642). The registration criterion\n * this framework was designed around is descent from `SmrtObject`, not the\n * presence of a decorator — undecorated domain classes (e.g. a hand-written\n * `SmrtCollection` subclass) keep their surfaces; only the framework's own\n * bases are excluded here, checked by class identity rather than decoration.\n *\n * This is the SINGLE shared source of truth for that identity check within\n * `@happyvertical/smrt-core` and its consumers — imported by:\n * - `./schema-builder.ts` (skips table/DDL generation for these classes)\n * - `../knowledge.ts` (the `.smrt/smrt-knowledge.json` surface projection)\n * - `../generators/mcp.ts` (`MCPGenerator.generateTools()`)\n * - `../generators/
|
|
1
|
+
{"version":3,"file":"framework-base-classes.js","names":[],"sources":["../../src/registry/framework-base-classes.ts"],"sourcesContent":["/**\n * The framework's own abstract base classes, keyed by simple class name to\n * their declaring package.\n *\n * These are scaffolding every application model descends from — they carry\n * no `@smrt()` decorator and have no independent existence as a resource.\n * A foundation package like `@happyvertical/smrt-core` declares them as real\n * local classes (there is no other package for them to live in), so\n * `loadAllManifests()` registers them exactly like any genuine domain class\n * when a consumer installs `@happyvertical/smrt-core` — with no decoration\n * or framework-base filter of its own (#2642). The registration criterion\n * this framework was designed around is descent from `SmrtObject`, not the\n * presence of a decorator — undecorated domain classes (e.g. a hand-written\n * `SmrtCollection` subclass) keep their surfaces; only the framework's own\n * bases are excluded here, checked by class identity rather than decoration.\n *\n * This is the SINGLE shared source of truth for that identity check within\n * `@happyvertical/smrt-core` and its consumers — imported by:\n * - `./schema-builder.ts` (skips table/DDL generation for these classes)\n * - `../knowledge.ts` (the `.smrt/smrt-knowledge.json` surface projection)\n * - `../generators/mcp.ts` (`MCPGenerator.generateTools()`)\n * - `../generators/rest.ts` (`APIGenerator.findClassByCollectionSegment()`)\n * - `../vite-plugin/sveltekit-generator.ts` (REST route generation)\n * - `../vite-plugin/sync-apply-route.ts` (`collectSyncApplyTargets()`)\n * - `../vite-plugin/web-collections.ts` (the `smrt-virt-web` client's\n * collection and WebMCP tool selectors)\n * - `@happyvertical/smrt-cli`'s `cli-generator.ts` (the live local `smrt`\n * binary's object command generation), via core's public export\n * - `../testing/database.ts` (`getTestDatabase()` skips table creation for\n * these classes, but only for an implicit `classes` list — an explicit\n * `classes: [...]` caller naming a framework base class is still honored,\n * unlike every unconditional filter above) (#2645)\n *\n * Do not add another hardcoded copy of this list at a new call site — import\n * from here instead.\n *\n * `packages/scanner/src/inheritance-resolver.ts` keeps its own separate\n * `FRAMEWORK_BASE_CLASSES` set: that package is a lower-level AST layer this\n * one has no reason to otherwise depend on, and that set controls a\n * different concern (scanner-level extends-chain termination and stub\n * resolution for packages that don't declare these classes locally), not\n * resource exposure.\n *\n * `scanner/manifest-generator.ts`'s `FRAMEWORK_METHOD_BASE_NAMES` is a\n * DIFFERENT, narrower (3-name: `SmrtObject`/`SmrtClass`/`SmrtCollection`) set\n * answering a different question — not \"is this class a resource?\" but\n * \"should this ancestor's METHODS merge into a subclass that doesn't declare\n * them?\" `SmrtReportCollection` and `SmrtJunction` are deliberately in this\n * 8-name resource set but NOT in that 3-name method-merge set: their declared\n * methods (`list`/`get` overrides, `attach`/`detach`/`byLeft`/`byRight`/\n * `setLinks`) are real, subclass-inherited API, not generic object-lifecycle\n * plumbing. Unifying the two sets — applying this one to method merging too —\n * strips those methods from every subclass; that regression actually\n * happened during #2624 and was caught only by a\n * `packages/template-sveltekit` snapshot test. Do not merge these lists.\n *\n * Most of these live in `@happyvertical/smrt-core` itself, but\n * `SmrtReport`/`SmrtReportCollection` are declared in\n * `@happyvertical/smrt-reports` — the owning package is per-name, not a\n * single blanket package check. A new framework base must be added here AND\n * to the scanner's `FRAMEWORK_BASE_CLASSES`.\n *\n * Deliberately NOT exported: only `isFrameworkBaseClass()` below needs to be\n * public. A `Map` survives TypeScript's `ReadonlyMap` typing only at the\n * type-check layer — a plain-JS or `as Map` caller could still `.set()`/\n * `.clear()` an exported instance at runtime and change what the framework\n * considers a base class. Keeping the map itself module-private closes that\n * off entirely rather than relying on callers not to do that.\n */\nconst FRAMEWORK_BASE_CLASS_PACKAGES: ReadonlyMap<string, string> = new Map([\n ['SmrtObject', '@happyvertical/smrt-core'],\n ['SmrtClass', '@happyvertical/smrt-core'],\n ['SmrtCollection', '@happyvertical/smrt-core'],\n ['SmrtJunction', '@happyvertical/smrt-core'],\n ['SmrtHierarchical', '@happyvertical/smrt-core'],\n ['SmrtPolymorphicAssociation', '@happyvertical/smrt-core'],\n ['SmrtReport', '@happyvertical/smrt-reports'],\n ['SmrtReportCollection', '@happyvertical/smrt-reports'],\n]);\n\n/**\n * True when `className`/`packageName` identify one of the framework's own\n * abstract base classes rather than a genuine resource.\n *\n * Both a class name AND its declaring package must match: a consuming\n * package is free to declare its own local class named e.g. `SmrtReport`\n * without colliding with the framework base of the same name.\n */\nexport function isFrameworkBaseClass(\n className: string | undefined,\n packageName: string | undefined,\n): boolean {\n return (\n className !== undefined &&\n packageName !== undefined &&\n FRAMEWORK_BASE_CLASS_PACKAGES.get(className) === packageName\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEA,IAAM,gDAA6D,IAAI,IAAI;CACzE,CAAC,cAAc,0BAA0B;CACzC,CAAC,aAAa,0BAA0B;CACxC,CAAC,kBAAkB,0BAA0B;CAC7C,CAAC,gBAAgB,0BAA0B;CAC3C,CAAC,oBAAoB,0BAA0B;CAC/C,CAAC,8BAA8B,0BAA0B;CACzD,CAAC,cAAc,6BAA6B;CAC5C,CAAC,wBAAwB,6BAA6B;AACxD,CAAC;;;;;;;;;AAUD,SAAgB,qBACd,WACA,aACS;CACT,OACE,cAAc,KAAA,KACd,gBAAgB,KAAA,KAChB,8BAA8B,IAAI,SAAS,MAAM;AAErD"}
|
package/dist/registry/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export { getEmbeddingClasses, getEmbeddingConfig, getProjectEmbeddingConfig, hasEmbeddings, resolveEmbeddingConfig, } from './embedding-manager';
|
|
8
8
|
export { findClass, findClassesByName, findClassStrict, getAllClasses, getCanonicalClassName, getClass, getClassByConstructor, getClassByQualifiedName, getClassesByPackage, getClassesByVisibility, getClassInPackage, getClassNames, getPublicClasses, getQualifiedClassNames, hasClass, hasClassCaseInsensitive, qualifyExtendsName, resolveType, } from './name-resolver';
|
|
9
9
|
export { getDependencyGraph, getRelationshipMap } from './relationship-graph';
|
|
10
|
-
export { getClasses, getCollectionCache, getCollections, getCollectionTableNames, getConstructorIndex, getDbInstanceIds, getDiscoveryAttemptCache, getFieldDecorators, getInheritanceCache, getInheritanceConfig, getNextDbId, getSchemasInitialized, getSourceFileFromStack, getStiSiblingsLoaded, setNextDbId, VERBOSE_ENABLED, verboseLog, } from './shared-state';
|
|
10
|
+
export { getClasses, getCollectionCache, getCollections, getCollectionTableNames, getConstructorIndex, getDbInstanceIds, getDiscoveryAttemptCache, getFieldDecorators, getInheritanceCache, getInheritanceConfig, getMethodDecorators, getNextDbId, getSchemasInitialized, getSourceFileFromStack, getStiSiblingsLoaded, setNextDbId, VERBOSE_ENABLED, verboseLog, } from './shared-state';
|
|
11
11
|
export type { ApiConfig, ApiHttpCacheConfig, RegisteredClass, RelationshipMetadata, RelationshipType, SmartObjectConfig, SmrtObjectConstructor, ValidatorFunction, } from './types';
|
|
12
12
|
export { compileValidators } from './validator';
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,aAAa,EACb,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,QAAQ,EACR,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,sBAAsB,EACtB,QAAQ,EACR,uBAAuB,EACvB,kBAAkB,EAClB,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE9E,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,EACX,eAAe,EACf,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,aAAa,EACb,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,QAAQ,EACR,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,sBAAsB,EACtB,QAAQ,EACR,uBAAuB,EACvB,kBAAkB,EAClB,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE9E,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,EACX,eAAe,EACf,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -10,6 +10,10 @@ declare global {
|
|
|
10
10
|
var __smrtRegistryNextDbId: number | undefined;
|
|
11
11
|
var __smrtRegistryInheritanceChainCache: LRUCache<string, string[]> | undefined;
|
|
12
12
|
var __smrtRegistryFieldDecorators: Map<string, Map<string, Record<string, unknown>>> | undefined;
|
|
13
|
+
var __smrtRegistryMethodDecorators: WeakMap<Function, Map<string, {
|
|
14
|
+
options: Record<string, unknown>;
|
|
15
|
+
isStatic: boolean;
|
|
16
|
+
}>> | undefined;
|
|
13
17
|
var __smrtRegistryStiSiblingsLoaded: Set<string> | undefined;
|
|
14
18
|
var __smrtRegistryCollectionTableNames: Map<string, string> | undefined;
|
|
15
19
|
var __smrtRegistrySchemasInitialized: WeakSet<object> | undefined;
|
|
@@ -62,6 +66,21 @@ export declare function getDbInstanceIds(): WeakMap<object, number>;
|
|
|
62
66
|
export declare function getNextDbId(): number;
|
|
63
67
|
export declare function setNextDbId(value: number): void;
|
|
64
68
|
export declare function getFieldDecorators(): Map<string, Map<string, Record<string, unknown>>>;
|
|
69
|
+
/**
|
|
70
|
+
* `@method()` decorator metadata,
|
|
71
|
+
* `constructor -> methodName -> { options, isStatic }`.
|
|
72
|
+
*
|
|
73
|
+
* Stored on `globalThis` for the same reason as {@link getFieldDecorators}:
|
|
74
|
+
* registration must survive HMR and multiple module instances. Keyed by the
|
|
75
|
+
* CONSTRUCTOR rather than the class name, unlike the field store, because two
|
|
76
|
+
* packages may declare the same simple name and the kernel forbids inferring
|
|
77
|
+
* ownership from one; a `WeakMap` also lets a discarded class's metadata be
|
|
78
|
+
* collected (#2686).
|
|
79
|
+
*/
|
|
80
|
+
export declare function getMethodDecorators(): WeakMap<Function, Map<string, {
|
|
81
|
+
options: Record<string, unknown>;
|
|
82
|
+
isStatic: boolean;
|
|
83
|
+
}>>;
|
|
65
84
|
export declare function getStiSiblingsLoaded(): Set<string>;
|
|
66
85
|
export declare function getSchemasInitialized(): WeakSet<object>;
|
|
67
86
|
export declare function getConstructorIndex(): WeakMap<SmrtObjectConstructor, string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-state.d.ts","sourceRoot":"","sources":["../../src/registry/shared-state.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-state.d.ts","sourceRoot":"","sources":["../../src/registry/shared-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -102,6 +102,21 @@ function getFieldDecorators() {
|
|
|
102
102
|
if (!globalThis.__smrtRegistryFieldDecorators) globalThis.__smrtRegistryFieldDecorators = /* @__PURE__ */ new Map();
|
|
103
103
|
return globalThis.__smrtRegistryFieldDecorators;
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* `@method()` decorator metadata,
|
|
107
|
+
* `constructor -> methodName -> { options, isStatic }`.
|
|
108
|
+
*
|
|
109
|
+
* Stored on `globalThis` for the same reason as {@link getFieldDecorators}:
|
|
110
|
+
* registration must survive HMR and multiple module instances. Keyed by the
|
|
111
|
+
* CONSTRUCTOR rather than the class name, unlike the field store, because two
|
|
112
|
+
* packages may declare the same simple name and the kernel forbids inferring
|
|
113
|
+
* ownership from one; a `WeakMap` also lets a discarded class's metadata be
|
|
114
|
+
* collected (#2686).
|
|
115
|
+
*/
|
|
116
|
+
function getMethodDecorators() {
|
|
117
|
+
if (!globalThis.__smrtRegistryMethodDecorators) globalThis.__smrtRegistryMethodDecorators = /* @__PURE__ */ new WeakMap();
|
|
118
|
+
return globalThis.__smrtRegistryMethodDecorators;
|
|
119
|
+
}
|
|
105
120
|
function getStiSiblingsLoaded() {
|
|
106
121
|
if (!globalThis.__smrtRegistryStiSiblingsLoaded) globalThis.__smrtRegistryStiSiblingsLoaded = /* @__PURE__ */ new Set();
|
|
107
122
|
return globalThis.__smrtRegistryStiSiblingsLoaded;
|
|
@@ -122,6 +137,6 @@ function getDiscoveryAttemptCache() {
|
|
|
122
137
|
return globalThis.__smrtRegistryDiscoveryAttemptCache;
|
|
123
138
|
}
|
|
124
139
|
//#endregion
|
|
125
|
-
export { VERBOSE_ENABLED, getClasses, getCollectionCache, getCollectionTableNames, getCollections, getConstructorIndex, getDbInstanceIds, getDiscoveryAttemptCache, getFieldDecorators, getInheritanceCache, getInheritanceConfig, getNextDbId, getSourceFileFromStack, getStiSiblingsLoaded, setNextDbId, verboseLog };
|
|
140
|
+
export { VERBOSE_ENABLED, getClasses, getCollectionCache, getCollectionTableNames, getCollections, getConstructorIndex, getDbInstanceIds, getDiscoveryAttemptCache, getFieldDecorators, getInheritanceCache, getInheritanceConfig, getMethodDecorators, getNextDbId, getSourceFileFromStack, getStiSiblingsLoaded, setNextDbId, verboseLog };
|
|
126
141
|
|
|
127
142
|
//# sourceMappingURL=shared-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-state.js","names":[],"sources":["../../src/registry/shared-state.ts"],"sourcesContent":["/**\n * Shared state accessors for the SMRT ObjectRegistry.\n *\n * All registry sub-modules share state via globalThis to ensure\n * cross-module consistency in monorepo environments.\n *\n * Extracted from registry.ts as part of issue #1006.\n * @see https://github.com/happyvertical/smrt/issues/1006\n * @see https://github.com/happyvertical/smrt/issues/543\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport type { SmrtCollection } from '../collection';\nimport {\n getSmrtModuleConfig,\n type SmrtGlobalConfig,\n} from '../config/global-config.js';\nimport { LRUCache } from '../utils/lru-cache';\nimport { isDecoratorRuntimeFramePath } from '../utils/stack-frames';\nimport type { RegisteredClass, SmrtObjectConstructor } from './types';\n\n// Re-export the globalThis augmentation so it's visible everywhere\ndeclare global {\n // eslint-disable-next-line no-var\n var __smrtRegistryClasses: Map<string, RegisteredClass> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryCollections: Map<string, typeof SmrtCollection> | undefined;\n // eslint-disable-next-line no-var\n // Heterogeneous cache: stores collections of many different item types keyed\n // by class name. `SmrtCollection` is invariant in its item type (it has\n // `create(options: SmrtCreateInput<ModelType>)`), so this cannot be narrowed\n // to `SmrtCollection<SmrtObject>` — the type argument stays `any` (read sites\n // cast back to the concrete collection type).\n var __smrtRegistryCollectionCache: // biome-ignore lint/suspicious/noExplicitAny: heterogeneous cache keyed by class name; `SmrtCollection` is invariant in `ModelType` so the type arg cannot narrow to `SmrtObject` (read sites cast back). S4 #1579.\n LRUCache<string, SmrtCollection<any>> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryDbInstanceIds: WeakMap<object, number> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryNextDbId: number | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryInheritanceChainCache:\n | LRUCache<string, string[]>\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryFieldDecorators:\n | Map<string, Map<string, Record<string, unknown>>>\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryStiSiblingsLoaded: Set<string> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryCollectionTableNames: Map<string, string> | undefined;\n // Release B (#1133) removed __smrtRegistryClassNameMap — case-insensitive\n // lookups now iterate the `classes` Map directly. The globalThis slot is\n // left undeclared so any leftover code that reaches for it gets a clean\n // TS error instead of silently stale data.\n // eslint-disable-next-line no-var\n var __smrtRegistrySchemasInitialized: WeakSet<object> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryConstructorIndex:\n | WeakMap<SmrtObjectConstructor, string>\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryDiscoveryAttemptCache: Map<string, boolean> | undefined;\n}\n\n/**\n * Cached verbose flag evaluated once at module load time.\n * Checks SMRT_VERBOSE=true or DEBUG containing 'smrt'.\n * Avoids repeated env var parsing on every log statement.\n * @see https://github.com/happyvertical/smrt/issues/782\n */\nexport const VERBOSE_ENABLED =\n process.env.SMRT_VERBOSE === 'true' ||\n (process.env.DEBUG?.includes('smrt') ?? false);\n\n// verboseLog() is gated by VERBOSE_ENABLED, so the level must allow debug when\n// it's set (a fixed 'info' would filter the trace out and break SMRT_VERBOSE).\nconst logger = createLogger({ level: VERBOSE_ENABLED ? 'debug' : 'info' });\n\n/**\n * Log a message only when verbose mode is enabled.\n * Used throughout registry modules to reduce noise during normal operation.\n * @param args - Arguments to pass to console.log\n */\nexport function verboseLog(...args: unknown[]): void {\n if (VERBOSE_ENABLED) {\n const [message, ...rest] = args;\n logger.debug(\n typeof message === 'string' ? message : String(message),\n rest.length > 0 ? { args: rest } : undefined,\n );\n }\n}\n\n/**\n * Get inheritance config synchronously.\n * Uses the config package's sync accessor which returns already-loaded config.\n */\nexport function getInheritanceConfig() {\n const config = getSmrtModuleConfig<SmrtGlobalConfig>('smrt', {});\n return {\n cacheSize: config.inheritance?.cacheSize ?? 200,\n onMissingAncestor:\n config.inheritance?.onMissingAncestor ?? ('warn' as 'warn' | 'error'),\n };\n}\n\n/**\n * Extract the source file path from the call stack.\n *\n * Used to identify where a class was defined for collision detection.\n * This allows the same class to be re-registered when modules are re-evaluated\n * (e.g., during vitest test file collection with isolation enabled).\n *\n * Frames from decorator-lowering runtime helpers (`@oxc-project/runtime` under\n * Vite 8, `tslib`/`@swc/helpers`/`@babel/runtime` elsewhere) are skipped too, so\n * the lowered `@smrt()` application resolves to the consumer module that declares\n * the class rather than the helper frame the compiler inserted (#1785).\n *\n * @param stackOverride - Optional stack string to parse instead of a fresh\n * `Error().stack`. Used by tests to simulate a lowered call pattern.\n * @returns The file path where the @smrt() decorator was called, or undefined\n */\nexport function getSourceFileFromStack(\n stackOverride?: string,\n): string | undefined {\n const stack = stackOverride ?? new Error().stack ?? '';\n const stackLines = stack.split('\\n');\n\n // Look for the first file path that's NOT from smrt-core internal files\n // Stack trace format: \" at FunctionName (file:///path/to/file.ts:line:col)\"\n // or \" at file:///path/to/file.ts:line:col\"\n for (const line of stackLines) {\n // Match file paths in stack trace (include all JS/TS file extensions)\n const fileMatch = line.match(\n /(?:file:\\/\\/)?([^)\\s]+\\.(?:js|ts|mjs|mts|jsx|tsx|cjs|cts))(?::\\d+:\\d+)?/,\n );\n if (fileMatch) {\n const rawPath = fileMatch[1];\n // Normalize the path:\n // - remove any leading file:// or file:/// prefix\n // - convert Windows backslashes to POSIX-style forward slashes\n const normalizedPath = rawPath\n .replace(/^file:\\/+/, '')\n .replace(/\\\\/g, '/');\n const lowerPath = normalizedPath.toLowerCase();\n\n // Skip smrt-core internal files using specific path patterns\n // to avoid false positives with user files containing \"registry\" in name\n if (\n // Installed package form: node_modules/@happyvertical/smrt-core/...\n lowerPath.includes('/node_modules/@happyvertical/smrt-core/') ||\n // Monorepo/workspace form: packages/core/src/...\n (lowerPath.includes('/packages/core/src/') &&\n !lowerPath.includes('__tests__')) ||\n // Specific manifest loader internals\n lowerPath.includes('/manifest/manifest-loader') ||\n // Decorator-lowering runtime helper (oxc/tslib/swc/babel) — the frame\n // the compiler inserts between @smrt() and the declaring module (#1785)\n isDecoratorRuntimeFramePath(normalizedPath)\n ) {\n continue;\n }\n return normalizedPath;\n }\n }\n return undefined;\n}\n\n// ── Shared state accessor functions ──────────────────────────────────────\n\nexport function getClasses(): Map<string, RegisteredClass> {\n if (!globalThis.__smrtRegistryClasses) {\n globalThis.__smrtRegistryClasses = new Map<string, RegisteredClass>();\n }\n return globalThis.__smrtRegistryClasses;\n}\n\nexport function getCollections(): Map<string, typeof SmrtCollection> {\n if (!globalThis.__smrtRegistryCollections) {\n globalThis.__smrtRegistryCollections = new Map<\n string,\n typeof SmrtCollection\n >();\n }\n return globalThis.__smrtRegistryCollections;\n}\n\nexport function getCollectionTableNames(): Map<string, string> {\n if (!globalThis.__smrtRegistryCollectionTableNames) {\n globalThis.__smrtRegistryCollectionTableNames = new Map<string, string>();\n }\n return globalThis.__smrtRegistryCollectionTableNames;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: heterogeneous cache; `SmrtCollection` is invariant in `ModelType` so the type arg cannot narrow to `SmrtObject` (read sites cast back). S4 #1579.\nexport function getCollectionCache(): LRUCache<string, SmrtCollection<any>> {\n if (!globalThis.__smrtRegistryCollectionCache) {\n globalThis.__smrtRegistryCollectionCache = new LRUCache<\n string,\n // biome-ignore lint/suspicious/noExplicitAny: same heterogeneous-cache invariance as the return type above. S4 #1579.\n SmrtCollection<any>\n >(100);\n }\n return globalThis.__smrtRegistryCollectionCache;\n}\n\nexport function getDbInstanceIds(): WeakMap<object, number> {\n if (!globalThis.__smrtRegistryDbInstanceIds) {\n globalThis.__smrtRegistryDbInstanceIds = new WeakMap<object, number>();\n }\n return globalThis.__smrtRegistryDbInstanceIds;\n}\n\nexport function getNextDbId(): number {\n if (globalThis.__smrtRegistryNextDbId === undefined) {\n globalThis.__smrtRegistryNextDbId = 1;\n }\n return globalThis.__smrtRegistryNextDbId;\n}\n\nexport function setNextDbId(value: number): void {\n globalThis.__smrtRegistryNextDbId = value;\n}\n\nexport function getFieldDecorators(): Map<\n string,\n Map<string, Record<string, unknown>>\n> {\n if (!globalThis.__smrtRegistryFieldDecorators) {\n globalThis.__smrtRegistryFieldDecorators = new Map<\n string,\n Map<string, Record<string, unknown>>\n >();\n }\n return globalThis.__smrtRegistryFieldDecorators;\n}\n\nexport function getStiSiblingsLoaded(): Set<string> {\n if (!globalThis.__smrtRegistryStiSiblingsLoaded) {\n globalThis.__smrtRegistryStiSiblingsLoaded = new Set<string>();\n }\n return globalThis.__smrtRegistryStiSiblingsLoaded;\n}\n\n// getClassNameMap removed in Release B (#1133). The eagerly-maintained\n// lowercase-simple-name → qualified-key[] index was replaced by on-demand\n// iteration over the `classes` Map in name-resolver.ts. Any remaining\n// consumer should switch to `findClassesByName`, `getCanonicalClassName`,\n// or `findClass`.\n\nexport function getSchemasInitialized(): WeakSet<object> {\n if (!globalThis.__smrtRegistrySchemasInitialized) {\n globalThis.__smrtRegistrySchemasInitialized = new WeakSet<object>();\n }\n return globalThis.__smrtRegistrySchemasInitialized;\n}\n\nexport function getConstructorIndex(): WeakMap<SmrtObjectConstructor, string> {\n if (!globalThis.__smrtRegistryConstructorIndex) {\n globalThis.__smrtRegistryConstructorIndex = new WeakMap<\n SmrtObjectConstructor,\n string\n >();\n }\n return globalThis.__smrtRegistryConstructorIndex;\n}\n\nexport function getInheritanceCache(): LRUCache<string, string[]> {\n if (!globalThis.__smrtRegistryInheritanceChainCache) {\n const config = getInheritanceConfig();\n globalThis.__smrtRegistryInheritanceChainCache = new LRUCache<\n string,\n string[]\n >(config.cacheSize);\n }\n return globalThis.__smrtRegistryInheritanceChainCache;\n}\n\nexport function getDiscoveryAttemptCache(): Map<string, boolean> {\n if (!globalThis.__smrtRegistryDiscoveryAttemptCache) {\n globalThis.__smrtRegistryDiscoveryAttemptCache = new Map<string, boolean>();\n }\n return globalThis.__smrtRegistryDiscoveryAttemptCache;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuEA,IAAa,kBACX,QAAQ,IAAI,iBAAiB,WAC5B,QAAQ,IAAI,OAAO,SAAS,MAAM,KAAK;AAI1C,IAAM,SAAS,aAAa,EAAE,OAAO,kBAAkB,UAAU,OAAO,CAAC;;;;;;AAOzE,SAAgB,WAAW,GAAG,MAAuB;CACnD,IAAI,iBAAiB;EACnB,MAAM,CAAC,SAAS,GAAG,QAAQ;EAC3B,OAAO,MACL,OAAO,YAAY,WAAW,UAAU,OAAO,OAAO,GACtD,KAAK,SAAS,IAAI,EAAE,MAAM,KAAK,IAAI,KAAA,CACrC;CACF;AACF;;;;;AAMA,SAAgB,uBAAuB;CACrC,MAAM,SAAS,oBAAsC,QAAQ,CAAC,CAAC;CAC/D,OAAO;EACL,WAAW,OAAO,aAAa,aAAa;EAC5C,mBACE,OAAO,aAAa,qBAAsB;CAC9C;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,uBACd,eACoB;CAEpB,MAAM,cADQ,kCAAiB,IAAI,MAAM,EAAA,CAAE,SAAS,GAAA,CAC3B,MAAM,IAAI;CAKnC,KAAK,MAAM,QAAQ,YAAY;EAE7B,MAAM,YAAY,KAAK,MACrB,yEACF;EACA,IAAI,WAAW;GAKb,MAAM,iBAJU,UAAU,EAIH,CACpB,QAAQ,aAAa,EAAE,CAAC,CACxB,QAAQ,OAAO,GAAG;GACrB,MAAM,YAAY,eAAe,YAAY;GAI7C,IAEE,UAAU,SAAS,yCAAyC,KAE3D,UAAU,SAAS,qBAAqB,KACvC,CAAC,UAAU,SAAS,WAAW,KAEjC,UAAU,SAAS,2BAA2B,KAG9C,4BAA4B,cAAc,GAE1C;GAEF,OAAO;EACT;CACF;AAEF;AAIA,SAAgB,aAA2C;CACzD,IAAI,CAAC,WAAW,uBACd,WAAW,wCAAwB,IAAI,IAA6B;CAEtE,OAAO,WAAW;AACpB;AAEA,SAAgB,iBAAqD;CACnE,IAAI,CAAC,WAAW,2BACd,WAAW,4CAA4B,IAAI,IAGzC;CAEJ,OAAO,WAAW;AACpB;AAEA,SAAgB,0BAA+C;CAC7D,IAAI,CAAC,WAAW,oCACd,WAAW,qDAAqC,IAAI,IAAoB;CAE1E,OAAO,WAAW;AACpB;AAGA,SAAgB,qBAA4D;CAC1E,IAAI,CAAC,WAAW,+BACd,WAAW,gCAAgC,IAAI,SAI7C,GAAG;CAEP,OAAO,WAAW;AACpB;AAEA,SAAgB,mBAA4C;CAC1D,IAAI,CAAC,WAAW,6BACd,WAAW,8CAA8B,IAAI,QAAwB;CAEvE,OAAO,WAAW;AACpB;AAEA,SAAgB,cAAsB;CACpC,IAAI,WAAW,2BAA2B,KAAA,GACxC,WAAW,yBAAyB;CAEtC,OAAO,WAAW;AACpB;AAEA,SAAgB,YAAY,OAAqB;CAC/C,WAAW,yBAAyB;AACtC;AAEA,SAAgB,qBAGd;CACA,IAAI,CAAC,WAAW,+BACd,WAAW,gDAAgC,IAAI,IAG7C;CAEJ,OAAO,WAAW;AACpB;AAEA,SAAgB,uBAAoC;CAClD,IAAI,CAAC,WAAW,iCACd,WAAW,kDAAkC,IAAI,IAAY;CAE/D,OAAO,WAAW;AACpB;AAeA,SAAgB,sBAA8D;CAC5E,IAAI,CAAC,WAAW,gCACd,WAAW,iDAAiC,IAAI,QAG9C;CAEJ,OAAO,WAAW;AACpB;AAEA,SAAgB,sBAAkD;CAChE,IAAI,CAAC,WAAW,qCAAqC;EACnD,MAAM,SAAS,qBAAqB;EACpC,WAAW,sCAAsC,IAAI,SAGnD,OAAO,SAAS;CACpB;CACA,OAAO,WAAW;AACpB;AAEA,SAAgB,2BAAiD;CAC/D,IAAI,CAAC,WAAW,qCACd,WAAW,sDAAsC,IAAI,IAAqB;CAE5E,OAAO,WAAW;AACpB"}
|
|
1
|
+
{"version":3,"file":"shared-state.js","names":[],"sources":["../../src/registry/shared-state.ts"],"sourcesContent":["/**\n * Shared state accessors for the SMRT ObjectRegistry.\n *\n * All registry sub-modules share state via globalThis to ensure\n * cross-module consistency in monorepo environments.\n *\n * Extracted from registry.ts as part of issue #1006.\n * @see https://github.com/happyvertical/smrt/issues/1006\n * @see https://github.com/happyvertical/smrt/issues/543\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport type { SmrtCollection } from '../collection';\nimport {\n getSmrtModuleConfig,\n type SmrtGlobalConfig,\n} from '../config/global-config.js';\nimport { LRUCache } from '../utils/lru-cache';\nimport { isDecoratorRuntimeFramePath } from '../utils/stack-frames';\nimport type { RegisteredClass, SmrtObjectConstructor } from './types';\n\n// Re-export the globalThis augmentation so it's visible everywhere\ndeclare global {\n // eslint-disable-next-line no-var\n var __smrtRegistryClasses: Map<string, RegisteredClass> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryCollections: Map<string, typeof SmrtCollection> | undefined;\n // eslint-disable-next-line no-var\n // Heterogeneous cache: stores collections of many different item types keyed\n // by class name. `SmrtCollection` is invariant in its item type (it has\n // `create(options: SmrtCreateInput<ModelType>)`), so this cannot be narrowed\n // to `SmrtCollection<SmrtObject>` — the type argument stays `any` (read sites\n // cast back to the concrete collection type).\n var __smrtRegistryCollectionCache: // biome-ignore lint/suspicious/noExplicitAny: heterogeneous cache keyed by class name; `SmrtCollection` is invariant in `ModelType` so the type arg cannot narrow to `SmrtObject` (read sites cast back). S4 #1579.\n LRUCache<string, SmrtCollection<any>> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryDbInstanceIds: WeakMap<object, number> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryNextDbId: number | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryInheritanceChainCache:\n | LRUCache<string, string[]>\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryFieldDecorators:\n | Map<string, Map<string, Record<string, unknown>>>\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryMethodDecorators:\n | WeakMap<\n Function,\n Map<string, { options: Record<string, unknown>; isStatic: boolean }>\n >\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryStiSiblingsLoaded: Set<string> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryCollectionTableNames: Map<string, string> | undefined;\n // Release B (#1133) removed __smrtRegistryClassNameMap — case-insensitive\n // lookups now iterate the `classes` Map directly. The globalThis slot is\n // left undeclared so any leftover code that reaches for it gets a clean\n // TS error instead of silently stale data.\n // eslint-disable-next-line no-var\n var __smrtRegistrySchemasInitialized: WeakSet<object> | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryConstructorIndex:\n | WeakMap<SmrtObjectConstructor, string>\n | undefined;\n // eslint-disable-next-line no-var\n var __smrtRegistryDiscoveryAttemptCache: Map<string, boolean> | undefined;\n}\n\n/**\n * Cached verbose flag evaluated once at module load time.\n * Checks SMRT_VERBOSE=true or DEBUG containing 'smrt'.\n * Avoids repeated env var parsing on every log statement.\n * @see https://github.com/happyvertical/smrt/issues/782\n */\nexport const VERBOSE_ENABLED =\n process.env.SMRT_VERBOSE === 'true' ||\n (process.env.DEBUG?.includes('smrt') ?? false);\n\n// verboseLog() is gated by VERBOSE_ENABLED, so the level must allow debug when\n// it's set (a fixed 'info' would filter the trace out and break SMRT_VERBOSE).\nconst logger = createLogger({ level: VERBOSE_ENABLED ? 'debug' : 'info' });\n\n/**\n * Log a message only when verbose mode is enabled.\n * Used throughout registry modules to reduce noise during normal operation.\n * @param args - Arguments to pass to console.log\n */\nexport function verboseLog(...args: unknown[]): void {\n if (VERBOSE_ENABLED) {\n const [message, ...rest] = args;\n logger.debug(\n typeof message === 'string' ? message : String(message),\n rest.length > 0 ? { args: rest } : undefined,\n );\n }\n}\n\n/**\n * Get inheritance config synchronously.\n * Uses the config package's sync accessor which returns already-loaded config.\n */\nexport function getInheritanceConfig() {\n const config = getSmrtModuleConfig<SmrtGlobalConfig>('smrt', {});\n return {\n cacheSize: config.inheritance?.cacheSize ?? 200,\n onMissingAncestor:\n config.inheritance?.onMissingAncestor ?? ('warn' as 'warn' | 'error'),\n };\n}\n\n/**\n * Extract the source file path from the call stack.\n *\n * Used to identify where a class was defined for collision detection.\n * This allows the same class to be re-registered when modules are re-evaluated\n * (e.g., during vitest test file collection with isolation enabled).\n *\n * Frames from decorator-lowering runtime helpers (`@oxc-project/runtime` under\n * Vite 8, `tslib`/`@swc/helpers`/`@babel/runtime` elsewhere) are skipped too, so\n * the lowered `@smrt()` application resolves to the consumer module that declares\n * the class rather than the helper frame the compiler inserted (#1785).\n *\n * @param stackOverride - Optional stack string to parse instead of a fresh\n * `Error().stack`. Used by tests to simulate a lowered call pattern.\n * @returns The file path where the @smrt() decorator was called, or undefined\n */\nexport function getSourceFileFromStack(\n stackOverride?: string,\n): string | undefined {\n const stack = stackOverride ?? new Error().stack ?? '';\n const stackLines = stack.split('\\n');\n\n // Look for the first file path that's NOT from smrt-core internal files\n // Stack trace format: \" at FunctionName (file:///path/to/file.ts:line:col)\"\n // or \" at file:///path/to/file.ts:line:col\"\n for (const line of stackLines) {\n // Match file paths in stack trace (include all JS/TS file extensions)\n const fileMatch = line.match(\n /(?:file:\\/\\/)?([^)\\s]+\\.(?:js|ts|mjs|mts|jsx|tsx|cjs|cts))(?::\\d+:\\d+)?/,\n );\n if (fileMatch) {\n const rawPath = fileMatch[1];\n // Normalize the path:\n // - remove any leading file:// or file:/// prefix\n // - convert Windows backslashes to POSIX-style forward slashes\n const normalizedPath = rawPath\n .replace(/^file:\\/+/, '')\n .replace(/\\\\/g, '/');\n const lowerPath = normalizedPath.toLowerCase();\n\n // Skip smrt-core internal files using specific path patterns\n // to avoid false positives with user files containing \"registry\" in name\n if (\n // Installed package form: node_modules/@happyvertical/smrt-core/...\n lowerPath.includes('/node_modules/@happyvertical/smrt-core/') ||\n // Monorepo/workspace form: packages/core/src/...\n (lowerPath.includes('/packages/core/src/') &&\n !lowerPath.includes('__tests__')) ||\n // Specific manifest loader internals\n lowerPath.includes('/manifest/manifest-loader') ||\n // Decorator-lowering runtime helper (oxc/tslib/swc/babel) — the frame\n // the compiler inserts between @smrt() and the declaring module (#1785)\n isDecoratorRuntimeFramePath(normalizedPath)\n ) {\n continue;\n }\n return normalizedPath;\n }\n }\n return undefined;\n}\n\n// ── Shared state accessor functions ──────────────────────────────────────\n\nexport function getClasses(): Map<string, RegisteredClass> {\n if (!globalThis.__smrtRegistryClasses) {\n globalThis.__smrtRegistryClasses = new Map<string, RegisteredClass>();\n }\n return globalThis.__smrtRegistryClasses;\n}\n\nexport function getCollections(): Map<string, typeof SmrtCollection> {\n if (!globalThis.__smrtRegistryCollections) {\n globalThis.__smrtRegistryCollections = new Map<\n string,\n typeof SmrtCollection\n >();\n }\n return globalThis.__smrtRegistryCollections;\n}\n\nexport function getCollectionTableNames(): Map<string, string> {\n if (!globalThis.__smrtRegistryCollectionTableNames) {\n globalThis.__smrtRegistryCollectionTableNames = new Map<string, string>();\n }\n return globalThis.__smrtRegistryCollectionTableNames;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: heterogeneous cache; `SmrtCollection` is invariant in `ModelType` so the type arg cannot narrow to `SmrtObject` (read sites cast back). S4 #1579.\nexport function getCollectionCache(): LRUCache<string, SmrtCollection<any>> {\n if (!globalThis.__smrtRegistryCollectionCache) {\n globalThis.__smrtRegistryCollectionCache = new LRUCache<\n string,\n // biome-ignore lint/suspicious/noExplicitAny: same heterogeneous-cache invariance as the return type above. S4 #1579.\n SmrtCollection<any>\n >(100);\n }\n return globalThis.__smrtRegistryCollectionCache;\n}\n\nexport function getDbInstanceIds(): WeakMap<object, number> {\n if (!globalThis.__smrtRegistryDbInstanceIds) {\n globalThis.__smrtRegistryDbInstanceIds = new WeakMap<object, number>();\n }\n return globalThis.__smrtRegistryDbInstanceIds;\n}\n\nexport function getNextDbId(): number {\n if (globalThis.__smrtRegistryNextDbId === undefined) {\n globalThis.__smrtRegistryNextDbId = 1;\n }\n return globalThis.__smrtRegistryNextDbId;\n}\n\nexport function setNextDbId(value: number): void {\n globalThis.__smrtRegistryNextDbId = value;\n}\n\nexport function getFieldDecorators(): Map<\n string,\n Map<string, Record<string, unknown>>\n> {\n if (!globalThis.__smrtRegistryFieldDecorators) {\n globalThis.__smrtRegistryFieldDecorators = new Map<\n string,\n Map<string, Record<string, unknown>>\n >();\n }\n return globalThis.__smrtRegistryFieldDecorators;\n}\n\n/**\n * `@method()` decorator metadata,\n * `constructor -> methodName -> { options, isStatic }`.\n *\n * Stored on `globalThis` for the same reason as {@link getFieldDecorators}:\n * registration must survive HMR and multiple module instances. Keyed by the\n * CONSTRUCTOR rather than the class name, unlike the field store, because two\n * packages may declare the same simple name and the kernel forbids inferring\n * ownership from one; a `WeakMap` also lets a discarded class's metadata be\n * collected (#2686).\n */\nexport function getMethodDecorators(): WeakMap<\n Function,\n Map<string, { options: Record<string, unknown>; isStatic: boolean }>\n> {\n if (!globalThis.__smrtRegistryMethodDecorators) {\n globalThis.__smrtRegistryMethodDecorators = new WeakMap<\n Function,\n Map<string, { options: Record<string, unknown>; isStatic: boolean }>\n >();\n }\n return globalThis.__smrtRegistryMethodDecorators;\n}\n\nexport function getStiSiblingsLoaded(): Set<string> {\n if (!globalThis.__smrtRegistryStiSiblingsLoaded) {\n globalThis.__smrtRegistryStiSiblingsLoaded = new Set<string>();\n }\n return globalThis.__smrtRegistryStiSiblingsLoaded;\n}\n\n// getClassNameMap removed in Release B (#1133). The eagerly-maintained\n// lowercase-simple-name → qualified-key[] index was replaced by on-demand\n// iteration over the `classes` Map in name-resolver.ts. Any remaining\n// consumer should switch to `findClassesByName`, `getCanonicalClassName`,\n// or `findClass`.\n\nexport function getSchemasInitialized(): WeakSet<object> {\n if (!globalThis.__smrtRegistrySchemasInitialized) {\n globalThis.__smrtRegistrySchemasInitialized = new WeakSet<object>();\n }\n return globalThis.__smrtRegistrySchemasInitialized;\n}\n\nexport function getConstructorIndex(): WeakMap<SmrtObjectConstructor, string> {\n if (!globalThis.__smrtRegistryConstructorIndex) {\n globalThis.__smrtRegistryConstructorIndex = new WeakMap<\n SmrtObjectConstructor,\n string\n >();\n }\n return globalThis.__smrtRegistryConstructorIndex;\n}\n\nexport function getInheritanceCache(): LRUCache<string, string[]> {\n if (!globalThis.__smrtRegistryInheritanceChainCache) {\n const config = getInheritanceConfig();\n globalThis.__smrtRegistryInheritanceChainCache = new LRUCache<\n string,\n string[]\n >(config.cacheSize);\n }\n return globalThis.__smrtRegistryInheritanceChainCache;\n}\n\nexport function getDiscoveryAttemptCache(): Map<string, boolean> {\n if (!globalThis.__smrtRegistryDiscoveryAttemptCache) {\n globalThis.__smrtRegistryDiscoveryAttemptCache = new Map<string, boolean>();\n }\n return globalThis.__smrtRegistryDiscoveryAttemptCache;\n}\n"],"mappings":"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"}
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SmrtCollection, SmrtCollectionOptions } from './collection';
|
|
2
2
|
import { CollectionCacheConfig } from './collection-cache';
|
|
3
|
-
import { FieldOptions } from './decorators/index.js';
|
|
3
|
+
import { FieldOptions, MethodOptions } from './decorators/index.js';
|
|
4
4
|
import { ClassEmbeddingConfig, ProjectEmbeddingConfig, ResolvedEmbeddingConfig } from './embeddings/types';
|
|
5
5
|
import { ValidationError } from './errors';
|
|
6
6
|
import { SmrtObject } from './object';
|
|
@@ -33,6 +33,15 @@ interface FieldDecoratorOptions extends FieldOptions {
|
|
|
33
33
|
__tenancy?: unknown;
|
|
34
34
|
__report?: unknown;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Decorator-supplied method metadata bag, from `@method()` (#2686).
|
|
38
|
+
*
|
|
39
|
+
* `MethodOptions` is the authoring type; this is the registry-input alias, kept
|
|
40
|
+
* separate for the same reason {@link FieldDecoratorOptions} is: the registry
|
|
41
|
+
* stores and forwards the bag without interpreting it, and a future method
|
|
42
|
+
* decorator can add members here without widening the public authoring type.
|
|
43
|
+
*/
|
|
44
|
+
type MethodDecoratorOptions = MethodOptions;
|
|
36
45
|
/**
|
|
37
46
|
* Constructor shape for a registered collection class.
|
|
38
47
|
*
|
|
@@ -135,6 +144,17 @@ export declare class ObjectRegistry {
|
|
|
135
144
|
* Used by @field(), @foreignKey(), @oneToMany(), @manyToMany() decorators
|
|
136
145
|
*/
|
|
137
146
|
private static get fieldDecorators();
|
|
147
|
+
/**
|
|
148
|
+
* Storage for `@method()` decorator metadata (#2686).
|
|
149
|
+
* Maps className → Map<methodName, MethodOptions>.
|
|
150
|
+
*
|
|
151
|
+
* The manifest is the primary carrier of this metadata for BUILD-time
|
|
152
|
+
* consumers (the scanner reads `@method()` into
|
|
153
|
+
* `MethodDefinition.decoratorConfig`); this store serves the runtime paths
|
|
154
|
+
* that have a live class but cannot reach a manifest entry for the method --
|
|
155
|
+
* see `resolveRuntimeMethodDecoratorConfig` for the two such cases.
|
|
156
|
+
*/
|
|
157
|
+
private static get methodDecorators();
|
|
138
158
|
/**
|
|
139
159
|
* Track collections that have been processed for STI siblings
|
|
140
160
|
* Prevents infinite recursion when loading siblings
|
|
@@ -211,6 +231,121 @@ export declare class ObjectRegistry {
|
|
|
211
231
|
* ```
|
|
212
232
|
*/
|
|
213
233
|
static getFieldDecorators(className: string): Map<string, FieldDecoratorOptions>;
|
|
234
|
+
/**
|
|
235
|
+
* Register `@method()` decorator metadata, keyed by the decorated class's
|
|
236
|
+
* CONSTRUCTOR.
|
|
237
|
+
*
|
|
238
|
+
* Constructor identity, not simple name: two packages may legitimately
|
|
239
|
+
* declare a class with the same simple name (`Account` exists in both
|
|
240
|
+
* `smrt-ledgers` and `smrt-messages`), and the kernel forbids inferring
|
|
241
|
+
* ownership from simple names. A name-keyed store would let one package's
|
|
242
|
+
* `@method({ expose: false })` withhold the other's identically-named
|
|
243
|
+
* action -- silent, non-local, and invisible in the 404 it produces.
|
|
244
|
+
*
|
|
245
|
+
* Merges with any existing options for the same method, so repeated
|
|
246
|
+
* decoration (or HMR re-evaluation) accumulates rather than replacing --
|
|
247
|
+
* matching {@link registerFieldDecorator}.
|
|
248
|
+
*/
|
|
249
|
+
static registerMethodDecorator(ctor: Function, methodName: string, options: MethodDecoratorOptions, isStatic?: boolean): void;
|
|
250
|
+
/** `@method()` options for one method, or `undefined` when undecorated. */
|
|
251
|
+
static getMethodDecorator(ctor: Function | undefined, methodName: string): MethodDecoratorOptions | undefined;
|
|
252
|
+
/**
|
|
253
|
+
* The stored `@method()` record, including the RECEIVER the decorator saw.
|
|
254
|
+
*
|
|
255
|
+
* `isStatic` cannot be recovered later in an unscanned runtime — there is no
|
|
256
|
+
* manifest to read it from — and it is what tells the standalone REST
|
|
257
|
+
* transport whether it can host the action at all (#2686).
|
|
258
|
+
*/
|
|
259
|
+
private static getMethodDecoratorEntry;
|
|
260
|
+
/** All `@method()` options declared on a class, keyed by method name. */
|
|
261
|
+
static getMethodDecorators(ctor: Function | undefined): Map<string, MethodDecoratorOptions>;
|
|
262
|
+
/**
|
|
263
|
+
* Constructors whose `@method()` decorators can govern `objectName`'s runtime
|
|
264
|
+
* REST surface: the model itself and its registered collection class, which
|
|
265
|
+
* is where a collection-hosted custom action's decorator actually lands.
|
|
266
|
+
*
|
|
267
|
+
* Resolved through the registry's own qualified-name-safe lookups, so a
|
|
268
|
+
* simple name never decides ownership.
|
|
269
|
+
*/
|
|
270
|
+
private static methodDecoratorSources;
|
|
271
|
+
/**
|
|
272
|
+
* The `@method()` config a RUNTIME transport must honor for
|
|
273
|
+
* `objectName.methodName`.
|
|
274
|
+
*
|
|
275
|
+
* The manifest is the primary carrier, but it is not always reachable from
|
|
276
|
+
* here. Two cases need the live store:
|
|
277
|
+
*
|
|
278
|
+
* - `startRestServer([Product], { db })` is a supported posture with NO
|
|
279
|
+
* manifest at all: `getMethods()` is empty while the decorators did run, so
|
|
280
|
+
* reading only the manifest drops `@method({ expose: false })` while a
|
|
281
|
+
* legacy `api.routes` entry alone still routes the withheld action.
|
|
282
|
+
* - A COLLECTION-hosted action's manifest entry lives under the collection
|
|
283
|
+
* class, which the item-keyed `getMethods(objectName)` map never contains,
|
|
284
|
+
* even in a fully scanned project.
|
|
285
|
+
*
|
|
286
|
+
* Absent exposure metadata defaults OPEN in this framework, so either drop is
|
|
287
|
+
* a widening (#2686).
|
|
288
|
+
*/
|
|
289
|
+
static resolveRuntimeMethodDecoratorConfig(objectName: string, methodName: string): Record<string, unknown> | undefined;
|
|
290
|
+
/**
|
|
291
|
+
* Whether the standalone REST transport can HOST `objectName.methodName`.
|
|
292
|
+
*
|
|
293
|
+
* That transport serves only collection-scoped custom actions: an instance
|
|
294
|
+
* method on the collection class, or a static on the item class. An instance
|
|
295
|
+
* method on the MODEL is item-scoped and has no receiver there, and the
|
|
296
|
+
* browser-plane preflight prediction has to agree with dispatch about that,
|
|
297
|
+
* or it reports a runnable step for an action that answers 404 (#2686).
|
|
298
|
+
*
|
|
299
|
+
* Resolution mirrors {@link resolveRuntimeMethodDecoratorConfig}: the item
|
|
300
|
+
* class's manifest entry first, then the live decorator store, which records
|
|
301
|
+
* the receiver the decorator saw precisely because an unscanned runtime has
|
|
302
|
+
* no manifest to recover it from.
|
|
303
|
+
*/
|
|
304
|
+
static isCollectionHostedMethod(objectName: string, methodName: string): boolean;
|
|
305
|
+
/**
|
|
306
|
+
* The method view a RUNTIME transport should read for one action, and whether
|
|
307
|
+
* this transport can host it.
|
|
308
|
+
*
|
|
309
|
+
* Three sources, in order, because no single one covers every posture:
|
|
310
|
+
*
|
|
311
|
+
* 1. The ITEM class's manifest entry — a static there is collection-hosted,
|
|
312
|
+
* an instance method is item-scoped.
|
|
313
|
+
* 2. The registered COLLECTION class's manifest entry, which is where a
|
|
314
|
+
* collection-hosted action's parameters actually live. Without this the
|
|
315
|
+
* runtime transport sees no parameter metadata for them and silently
|
|
316
|
+
* degrades every one to the legacy options-bag contract.
|
|
317
|
+
* 3. The live `@method()` store, for an unscanned project with no manifest at
|
|
318
|
+
* all. It records the receiver the decorator saw, which is the only place
|
|
319
|
+
* that fact survives there.
|
|
320
|
+
*
|
|
321
|
+
* `collectionHosted` defaults to true when nothing is known: that is the
|
|
322
|
+
* legacy `api.routes`-only shape this transport has always attempted, and
|
|
323
|
+
* predicting a denial dispatch may not issue would be its own false answer.
|
|
324
|
+
*/
|
|
325
|
+
static resolveRuntimeMethod(objectName: string, methodName: string): {
|
|
326
|
+
method?: MethodDefinition;
|
|
327
|
+
collectionHosted: boolean;
|
|
328
|
+
};
|
|
329
|
+
/** Registered collection class names for `objectName`, qualified-name safe. */
|
|
330
|
+
private static collectionClassNames;
|
|
331
|
+
/** `@method()` config from the live store alone, ignoring the manifest. */
|
|
332
|
+
private static resolveDeclaredMethodConfig;
|
|
333
|
+
/**
|
|
334
|
+
* Every method name carrying a `@method()` declaration for `objectName`,
|
|
335
|
+
* from the manifest and the live decorator store together. Runtime
|
|
336
|
+
* transports enumerate this so a decorator-declared route survives in an
|
|
337
|
+
* unscanned project.
|
|
338
|
+
*/
|
|
339
|
+
static listDecoratedMethodNames(objectName: string): string[];
|
|
340
|
+
/**
|
|
341
|
+
* The manifest-derived method map for the class registered under EXACTLY
|
|
342
|
+
* `source`, or `undefined` when no manifest described it.
|
|
343
|
+
*
|
|
344
|
+
* Matched on constructor identity, never on name: `Account` exists in both
|
|
345
|
+
* `smrt-ledgers` and `smrt-messages`, and one package's manifest must not
|
|
346
|
+
* decide what the other's live decorators may expose.
|
|
347
|
+
*/
|
|
348
|
+
private static manifestMethodsForConstructor;
|
|
214
349
|
/**
|
|
215
350
|
* Check if a class has any field decorators registered
|
|
216
351
|
*
|