@happyvertical/smrt-approvals 0.55.20 → 0.55.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/smrt-knowledge.json +3 -3
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ObjectRegistry, SmrtCollection, SmrtObject, appendChange, field, foreig
|
|
|
3
3
|
import { registerPermissionDefinitions } from "@happyvertical/smrt-users";
|
|
4
4
|
import { TenantScoped, getTenantId, isSystemContext, tenantId, withTenant } from "@happyvertical/smrt-tenancy";
|
|
5
5
|
//#region src/__smrt-register__.ts
|
|
6
|
-
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-approvals","packageVersion":"0.55.20","objects":{"@happyvertical/smrt-approvals:ApprovalEventCollection":{"name":"approvaleventcollection","className":"ApprovalEventCollection","qualifiedName":"@happyvertical/smrt-approvals:ApprovalEventCollection","collection":"approvalevents","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalEventCollection.ts","packageName":"@happyvertical/smrt-approvals","fields":{},"methods":{},"decoratorConfig":{"api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"tableName":"approval_events"},"extends":"SmrtCollection","extendsTypeArg":"ApprovalEvent","exportName":"ApprovalEventCollection","collectionExportName":"ApprovalEventCollectionCollection","schema":{"tableName":"approval_events","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_events\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"request_id\\" UUID NOT NULL,\\n \\"type\\" TEXT NOT NULL,\\n \\"actor_id\\" TEXT NOT NULL,\\n \\"actor_type\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"subject_revision_hash\\" TEXT,\\n \\"sequence\\" INTEGER,\\n \\"vote_key\\" TEXT,\\n \\"occurred_at\\" TIMESTAMP,\\n \\"self_approved\\" BOOLEAN DEFAULT FALSE,\\n \\"self_approval_permission\\" TEXT DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"request_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"approval_requests","column":"id","onDelete":"RESTRICT","onUpdate":"RESTRICT","engines":["postgres","sqlite"]}},"type":{"type":"TEXT","notNull":true,"unique":false},"actor_id":{"type":"TEXT","notNull":true,"unique":false},"actor_type":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":false,"unique":false},"sequence":{"type":"INTEGER","notNull":false,"unique":false},"vote_key":{"type":"TEXT","notNull":false,"unique":false},"occurred_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"self_approved":{"type":"BOOLEAN","notNull":false,"unique":false,"default":false},"self_approval_permission":{"type":"TEXT","notNull":false,"unique":false,"default":""}},"indexes":[{"name":"approval_events_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_events_request_sequence_key","columns":["request_id","sequence"],"unique":true},{"name":"approval_events_request_vote_key","columns":["request_id","vote_key"],"unique":true},{"name":"approval_events_tenant_occurred_idx","columns":["tenant_id","occurred_at"]},{"name":"approval_events_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"998756b0"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalPolicyCollection":{"name":"approvalpolicycollection","className":"ApprovalPolicyCollection","qualifiedName":"@happyvertical/smrt-approvals:ApprovalPolicyCollection","collection":"approvalpolicies","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalPolicyCollection.ts","packageName":"@happyvertical/smrt-approvals","fields":{},"methods":{},"decoratorConfig":{"api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"tableName":"approval_policies"},"extends":"SmrtCollection","extendsTypeArg":"ApprovalPolicy","exportName":"ApprovalPolicyCollection","collectionExportName":"ApprovalPolicyCollectionCollection","schema":{"tableName":"approval_policies","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_policies\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"required_approvals\\" INTEGER,\\n \\"ttl_ms\\" INTEGER,\\n \\"required_permission\\" TEXT,\\n \\"updated_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"ttl_ms":{"type":"INTEGER","notNull":false,"unique":false},"required_permission":{"type":"TEXT","notNull":false,"unique":false},"updated_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_policies_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_policies_tenant_kind_key","columns":["tenant_id","kind"],"unique":true},{"name":"approval_policies_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"80929cc8"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalRequestCollection":{"name":"approvalrequestcollection","className":"ApprovalRequestCollection","qualifiedName":"@happyvertical/smrt-approvals:ApprovalRequestCollection","collection":"approvalrequests","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalRequestCollection.ts","packageName":"@happyvertical/smrt-approvals","fields":{},"methods":{},"decoratorConfig":{"api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"tableName":"approval_requests"},"extends":"SmrtCollection","extendsTypeArg":"ApprovalRequest","exportName":"ApprovalRequestCollection","collectionExportName":"ApprovalRequestCollectionCollection","schema":{"tableName":"approval_requests","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_requests\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"subject_type\\" TEXT NOT NULL,\\n \\"subject_id\\" TEXT NOT NULL,\\n \\"subject_revision_hash\\" TEXT NOT NULL,\\n \\"request_key\\" TEXT NOT NULL,\\n \\"requested_by\\" TEXT NOT NULL,\\n \\"requested_by_type\\" TEXT,\\n \\"summary\\" TEXT,\\n \\"status\\" TEXT,\\n \\"required_approvals\\" INTEGER,\\n \\"approval_count\\" INTEGER,\\n \\"required_permissions\\" TEXT,\\n \\"version\\" INTEGER,\\n \\"expires_at\\" TIMESTAMP,\\n \\"decided_at\\" TIMESTAMP,\\n \\"consumed_at\\" TIMESTAMP,\\n \\"consumed_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"subject_type":{"type":"TEXT","notNull":true,"unique":false},"subject_id":{"type":"TEXT","notNull":true,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":true,"unique":false},"request_key":{"type":"TEXT","notNull":true,"unique":false},"requested_by":{"type":"TEXT","notNull":true,"unique":false},"requested_by_type":{"type":"TEXT","notNull":false,"unique":false},"summary":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"approval_count":{"type":"INTEGER","notNull":false,"unique":false},"required_permissions":{"type":"TEXT","notNull":false,"unique":false},"version":{"type":"INTEGER","notNull":false,"unique":false},"expires_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"decided_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_requests_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_requests_tenant_request_key","columns":["tenant_id","request_key"],"unique":true},{"name":"approval_requests_status_expiry_idx","columns":["tenant_id","status","expires_at"]},{"name":"approval_requests_subject_idx","columns":["tenant_id","subject_type","subject_id"]},{"name":"approval_requests_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"a5800bdd"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalEvent":{"name":"approvalevent","className":"ApprovalEvent","qualifiedName":"@happyvertical/smrt-approvals:ApprovalEvent","collection":"approvalevents","description":"One immutable entry in an approval request's history.","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalEvent.ts","packageName":"@happyvertical/smrt-approvals","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"requestId":{"type":"foreignKey","required":true,"related":"ApprovalRequest","_meta":{"required":true,"constraint":{"engines":["postgres","sqlite"]},"onDelete":"RESTRICT","onUpdate":"RESTRICT"}},"type":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"actorId":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"actorType":{"type":"text","required":false,"_meta":{"readonly":true},"enum":["human","agent","service"],"readonly":true},"reason":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"subjectRevisionHash":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"sequence":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"voteKey":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true},"occurredAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"selfApproved":{"type":"boolean","required":false,"default":false,"_meta":{"readonly":true,"default":false},"readonly":true},"selfApprovalPermission":{"type":"text","required":false,"default":"","_meta":{"readonly":true,"default":""},"readonly":true}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"approval_events","api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"indexes":[{"name":"approval_events_request_sequence_key","columns":["requestId","sequence"],"unique":true},{"name":"approval_events_request_vote_key","columns":["requestId","voteKey"],"unique":true},{"name":"approval_events_tenant_occurred_idx","columns":["tenantId","occurredAt"]}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"ApprovalEvent","collectionExportName":"ApprovalEventCollection","validationRules":[{"field":"requestId","rule":"required","fieldType":"foreignKey"},{"field":"type","rule":"required","fieldType":"text"},{"field":"actorId","rule":"required","fieldType":"text"}],"schema":{"tableName":"approval_events","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_events\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"request_id\\" UUID NOT NULL,\\n \\"type\\" TEXT NOT NULL,\\n \\"actor_id\\" TEXT NOT NULL,\\n \\"actor_type\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"subject_revision_hash\\" TEXT,\\n \\"sequence\\" INTEGER,\\n \\"vote_key\\" TEXT,\\n \\"occurred_at\\" TIMESTAMP,\\n \\"self_approved\\" BOOLEAN DEFAULT FALSE,\\n \\"self_approval_permission\\" TEXT DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"request_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"approval_requests","column":"id","onDelete":"RESTRICT","onUpdate":"RESTRICT","engines":["postgres","sqlite"]}},"type":{"type":"TEXT","notNull":true,"unique":false},"actor_id":{"type":"TEXT","notNull":true,"unique":false},"actor_type":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":false,"unique":false},"sequence":{"type":"INTEGER","notNull":false,"unique":false},"vote_key":{"type":"TEXT","notNull":false,"unique":false},"occurred_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"self_approved":{"type":"BOOLEAN","notNull":false,"unique":false,"default":false},"self_approval_permission":{"type":"TEXT","notNull":false,"unique":false,"default":""}},"indexes":[{"name":"approval_events_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_events_request_sequence_key","columns":["request_id","sequence"],"unique":true},{"name":"approval_events_request_vote_key","columns":["request_id","vote_key"],"unique":true},{"name":"approval_events_tenant_occurred_idx","columns":["tenant_id","occurred_at"]},{"name":"approval_events_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"998756b0"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalPolicy":{"name":"approvalpolicy","className":"ApprovalPolicy","qualifiedName":"@happyvertical/smrt-approvals:ApprovalPolicy","collection":"approvalpolicies","description":"Tenant-level tightening of an approval kind. One row per tenant and kind.","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalPolicy.ts","packageName":"@happyvertical/smrt-approvals","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"kind":{"type":"text","required":true,"_meta":{"required":true}},"requiredApprovals":{"type":"integer","required":false,"_meta":{}},"ttlMs":{"type":"integer","required":false,"_meta":{}},"requiredPermission":{"type":"text","required":false,"_meta":{}},"updatedBy":{"type":"text","required":false,"_meta":{}}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"approval_policies","api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"indexes":[{"name":"approval_policies_tenant_kind_key","columns":["tenantId","kind"],"unique":true}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"ApprovalPolicy","collectionExportName":"ApprovalPolicyCollection","validationRules":[{"field":"kind","rule":"required","fieldType":"text"}],"schema":{"tableName":"approval_policies","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_policies\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"required_approvals\\" INTEGER,\\n \\"ttl_ms\\" INTEGER,\\n \\"required_permission\\" TEXT,\\n \\"updated_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"ttl_ms":{"type":"INTEGER","notNull":false,"unique":false},"required_permission":{"type":"TEXT","notNull":false,"unique":false},"updated_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_policies_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_policies_tenant_kind_key","columns":["tenant_id","kind"],"unique":true},{"name":"approval_policies_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"80929cc8"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalRequest":{"name":"approvalrequest","className":"ApprovalRequest","qualifiedName":"@happyvertical/smrt-approvals:ApprovalRequest","collection":"approvalrequests","description":"A request for approval of one subject revision.","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalRequest.ts","packageName":"@happyvertical/smrt-approvals","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"kind":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"subjectType":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"subjectId":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"subjectRevisionHash":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"requestKey":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"requestedBy":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"requestedByType":{"type":"text","required":false,"_meta":{"readonly":true},"enum":["human","agent","service"],"readonly":true},"summary":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"status":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"requiredApprovals":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"approvalCount":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"requiredPermissions":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"version":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"expiresAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"decidedAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"consumedAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"consumedBy":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true}},"methods":{"getRequiredPermissions":{"name":"getRequiredPermissions","async":false,"parameters":[],"returnType":"string[]","isStatic":false,"isPublic":true},"setRequiredPermissions":{"name":"setRequiredPermissions","async":false,"parameters":[{"name":"slugs","type":"any","optional":false,"typeUnresolved":true}],"returnType":"void","isStatic":false,"isPublic":true},"expiresAtMs":{"name":"expiresAtMs","async":false,"parameters":[],"returnType":"number","isStatic":false,"isPublic":true},"isConsumed":{"name":"isConsumed","async":false,"parameters":[],"returnType":"boolean","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"approval_requests","api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"indexes":[{"name":"approval_requests_tenant_request_key","columns":["tenantId","requestKey"],"unique":true},{"name":"approval_requests_status_expiry_idx","columns":["tenantId","status","expiresAt"]},{"name":"approval_requests_subject_idx","columns":["tenantId","subjectType","subjectId"]}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"ApprovalRequest","collectionExportName":"ApprovalRequestCollection","validationRules":[{"field":"kind","rule":"required","fieldType":"text"},{"field":"subjectType","rule":"required","fieldType":"text"},{"field":"subjectId","rule":"required","fieldType":"text"},{"field":"subjectRevisionHash","rule":"required","fieldType":"text"},{"field":"requestKey","rule":"required","fieldType":"text"},{"field":"requestedBy","rule":"required","fieldType":"text"}],"schema":{"tableName":"approval_requests","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_requests\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"subject_type\\" TEXT NOT NULL,\\n \\"subject_id\\" TEXT NOT NULL,\\n \\"subject_revision_hash\\" TEXT NOT NULL,\\n \\"request_key\\" TEXT NOT NULL,\\n \\"requested_by\\" TEXT NOT NULL,\\n \\"requested_by_type\\" TEXT,\\n \\"summary\\" TEXT,\\n \\"status\\" TEXT,\\n \\"required_approvals\\" INTEGER,\\n \\"approval_count\\" INTEGER,\\n \\"required_permissions\\" TEXT,\\n \\"version\\" INTEGER,\\n \\"expires_at\\" TIMESTAMP,\\n \\"decided_at\\" TIMESTAMP,\\n \\"consumed_at\\" TIMESTAMP,\\n \\"consumed_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"subject_type":{"type":"TEXT","notNull":true,"unique":false},"subject_id":{"type":"TEXT","notNull":true,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":true,"unique":false},"request_key":{"type":"TEXT","notNull":true,"unique":false},"requested_by":{"type":"TEXT","notNull":true,"unique":false},"requested_by_type":{"type":"TEXT","notNull":false,"unique":false},"summary":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"approval_count":{"type":"INTEGER","notNull":false,"unique":false},"required_permissions":{"type":"TEXT","notNull":false,"unique":false},"version":{"type":"INTEGER","notNull":false,"unique":false},"expires_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"decided_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_requests_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_requests_tenant_request_key","columns":["tenant_id","request_key"],"unique":true},{"name":"approval_requests_status_expiry_idx","columns":["tenant_id","status","expires_at"]},{"name":"approval_requests_subject_idx","columns":["tenant_id","subject_type","subject_id"]},{"name":"approval_requests_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"a5800bdd"},"importPath":"@happyvertical/smrt-approvals"}},"moduleType":"smrt","smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-tenancy","@happyvertical/smrt-users"],"browser":{"status":"server-only","issues":["#3617","#3624","#3626"],"via":["@happyvertical/smrt-profiles","@happyvertical/smrt-tenancy","@happyvertical/smrt-users"]},"stampsConstructors":true}`));
|
|
6
|
+
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-approvals","packageVersion":"0.55.22","objects":{"@happyvertical/smrt-approvals:ApprovalEventCollection":{"name":"approvaleventcollection","className":"ApprovalEventCollection","qualifiedName":"@happyvertical/smrt-approvals:ApprovalEventCollection","collection":"approvalevents","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalEventCollection.ts","packageName":"@happyvertical/smrt-approvals","fields":{},"methods":{},"decoratorConfig":{"api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"tableName":"approval_events"},"extends":"SmrtCollection","extendsTypeArg":"ApprovalEvent","exportName":"ApprovalEventCollection","collectionExportName":"ApprovalEventCollectionCollection","schema":{"tableName":"approval_events","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_events\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"request_id\\" UUID NOT NULL,\\n \\"type\\" TEXT NOT NULL,\\n \\"actor_id\\" TEXT NOT NULL,\\n \\"actor_type\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"subject_revision_hash\\" TEXT,\\n \\"sequence\\" INTEGER,\\n \\"vote_key\\" TEXT,\\n \\"occurred_at\\" TIMESTAMP,\\n \\"self_approved\\" BOOLEAN DEFAULT FALSE,\\n \\"self_approval_permission\\" TEXT DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"request_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"approval_requests","column":"id","onDelete":"RESTRICT","onUpdate":"RESTRICT","engines":["postgres","sqlite"]}},"type":{"type":"TEXT","notNull":true,"unique":false},"actor_id":{"type":"TEXT","notNull":true,"unique":false},"actor_type":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":false,"unique":false},"sequence":{"type":"INTEGER","notNull":false,"unique":false},"vote_key":{"type":"TEXT","notNull":false,"unique":false},"occurred_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"self_approved":{"type":"BOOLEAN","notNull":false,"unique":false,"default":false},"self_approval_permission":{"type":"TEXT","notNull":false,"unique":false,"default":""}},"indexes":[{"name":"approval_events_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_events_request_sequence_key","columns":["request_id","sequence"],"unique":true},{"name":"approval_events_request_vote_key","columns":["request_id","vote_key"],"unique":true},{"name":"approval_events_tenant_occurred_idx","columns":["tenant_id","occurred_at"]},{"name":"approval_events_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"998756b0"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalPolicyCollection":{"name":"approvalpolicycollection","className":"ApprovalPolicyCollection","qualifiedName":"@happyvertical/smrt-approvals:ApprovalPolicyCollection","collection":"approvalpolicies","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalPolicyCollection.ts","packageName":"@happyvertical/smrt-approvals","fields":{},"methods":{},"decoratorConfig":{"api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"tableName":"approval_policies"},"extends":"SmrtCollection","extendsTypeArg":"ApprovalPolicy","exportName":"ApprovalPolicyCollection","collectionExportName":"ApprovalPolicyCollectionCollection","schema":{"tableName":"approval_policies","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_policies\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"required_approvals\\" INTEGER,\\n \\"ttl_ms\\" INTEGER,\\n \\"required_permission\\" TEXT,\\n \\"updated_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"ttl_ms":{"type":"INTEGER","notNull":false,"unique":false},"required_permission":{"type":"TEXT","notNull":false,"unique":false},"updated_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_policies_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_policies_tenant_kind_key","columns":["tenant_id","kind"],"unique":true},{"name":"approval_policies_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"80929cc8"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalRequestCollection":{"name":"approvalrequestcollection","className":"ApprovalRequestCollection","qualifiedName":"@happyvertical/smrt-approvals:ApprovalRequestCollection","collection":"approvalrequests","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalRequestCollection.ts","packageName":"@happyvertical/smrt-approvals","fields":{},"methods":{},"decoratorConfig":{"api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"tableName":"approval_requests"},"extends":"SmrtCollection","extendsTypeArg":"ApprovalRequest","exportName":"ApprovalRequestCollection","collectionExportName":"ApprovalRequestCollectionCollection","schema":{"tableName":"approval_requests","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_requests\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"subject_type\\" TEXT NOT NULL,\\n \\"subject_id\\" TEXT NOT NULL,\\n \\"subject_revision_hash\\" TEXT NOT NULL,\\n \\"request_key\\" TEXT NOT NULL,\\n \\"requested_by\\" TEXT NOT NULL,\\n \\"requested_by_type\\" TEXT,\\n \\"summary\\" TEXT,\\n \\"status\\" TEXT,\\n \\"required_approvals\\" INTEGER,\\n \\"approval_count\\" INTEGER,\\n \\"required_permissions\\" TEXT,\\n \\"version\\" INTEGER,\\n \\"expires_at\\" TIMESTAMP,\\n \\"decided_at\\" TIMESTAMP,\\n \\"consumed_at\\" TIMESTAMP,\\n \\"consumed_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"subject_type":{"type":"TEXT","notNull":true,"unique":false},"subject_id":{"type":"TEXT","notNull":true,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":true,"unique":false},"request_key":{"type":"TEXT","notNull":true,"unique":false},"requested_by":{"type":"TEXT","notNull":true,"unique":false},"requested_by_type":{"type":"TEXT","notNull":false,"unique":false},"summary":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"approval_count":{"type":"INTEGER","notNull":false,"unique":false},"required_permissions":{"type":"TEXT","notNull":false,"unique":false},"version":{"type":"INTEGER","notNull":false,"unique":false},"expires_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"decided_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_requests_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_requests_tenant_request_key","columns":["tenant_id","request_key"],"unique":true},{"name":"approval_requests_status_expiry_idx","columns":["tenant_id","status","expires_at"]},{"name":"approval_requests_subject_idx","columns":["tenant_id","subject_type","subject_id"]},{"name":"approval_requests_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"a5800bdd"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalEvent":{"name":"approvalevent","className":"ApprovalEvent","qualifiedName":"@happyvertical/smrt-approvals:ApprovalEvent","collection":"approvalevents","description":"One immutable entry in an approval request's history.","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalEvent.ts","packageName":"@happyvertical/smrt-approvals","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"requestId":{"type":"foreignKey","required":true,"related":"ApprovalRequest","_meta":{"required":true,"constraint":{"engines":["postgres","sqlite"]},"onDelete":"RESTRICT","onUpdate":"RESTRICT"}},"type":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"actorId":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"actorType":{"type":"text","required":false,"_meta":{"readonly":true},"enum":["human","agent","service"],"readonly":true},"reason":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"subjectRevisionHash":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"sequence":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"voteKey":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true},"occurredAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"selfApproved":{"type":"boolean","required":false,"default":false,"_meta":{"readonly":true,"default":false},"readonly":true},"selfApprovalPermission":{"type":"text","required":false,"default":"","_meta":{"readonly":true,"default":""},"readonly":true}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"approval_events","api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"indexes":[{"name":"approval_events_request_sequence_key","columns":["requestId","sequence"],"unique":true},{"name":"approval_events_request_vote_key","columns":["requestId","voteKey"],"unique":true},{"name":"approval_events_tenant_occurred_idx","columns":["tenantId","occurredAt"]}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"ApprovalEvent","collectionExportName":"ApprovalEventCollection","validationRules":[{"field":"requestId","rule":"required","fieldType":"foreignKey"},{"field":"type","rule":"required","fieldType":"text"},{"field":"actorId","rule":"required","fieldType":"text"}],"schema":{"tableName":"approval_events","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_events\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"request_id\\" UUID NOT NULL,\\n \\"type\\" TEXT NOT NULL,\\n \\"actor_id\\" TEXT NOT NULL,\\n \\"actor_type\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"subject_revision_hash\\" TEXT,\\n \\"sequence\\" INTEGER,\\n \\"vote_key\\" TEXT,\\n \\"occurred_at\\" TIMESTAMP,\\n \\"self_approved\\" BOOLEAN DEFAULT FALSE,\\n \\"self_approval_permission\\" TEXT DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"request_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"approval_requests","column":"id","onDelete":"RESTRICT","onUpdate":"RESTRICT","engines":["postgres","sqlite"]}},"type":{"type":"TEXT","notNull":true,"unique":false},"actor_id":{"type":"TEXT","notNull":true,"unique":false},"actor_type":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":false,"unique":false},"sequence":{"type":"INTEGER","notNull":false,"unique":false},"vote_key":{"type":"TEXT","notNull":false,"unique":false},"occurred_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"self_approved":{"type":"BOOLEAN","notNull":false,"unique":false,"default":false},"self_approval_permission":{"type":"TEXT","notNull":false,"unique":false,"default":""}},"indexes":[{"name":"approval_events_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_events_request_sequence_key","columns":["request_id","sequence"],"unique":true},{"name":"approval_events_request_vote_key","columns":["request_id","vote_key"],"unique":true},{"name":"approval_events_tenant_occurred_idx","columns":["tenant_id","occurred_at"]},{"name":"approval_events_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"998756b0"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalPolicy":{"name":"approvalpolicy","className":"ApprovalPolicy","qualifiedName":"@happyvertical/smrt-approvals:ApprovalPolicy","collection":"approvalpolicies","description":"Tenant-level tightening of an approval kind. One row per tenant and kind.","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalPolicy.ts","packageName":"@happyvertical/smrt-approvals","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"kind":{"type":"text","required":true,"_meta":{"required":true}},"requiredApprovals":{"type":"integer","required":false,"_meta":{}},"ttlMs":{"type":"integer","required":false,"_meta":{}},"requiredPermission":{"type":"text","required":false,"_meta":{}},"updatedBy":{"type":"text","required":false,"_meta":{}}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"approval_policies","api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"indexes":[{"name":"approval_policies_tenant_kind_key","columns":["tenantId","kind"],"unique":true}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"ApprovalPolicy","collectionExportName":"ApprovalPolicyCollection","validationRules":[{"field":"kind","rule":"required","fieldType":"text"}],"schema":{"tableName":"approval_policies","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_policies\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"required_approvals\\" INTEGER,\\n \\"ttl_ms\\" INTEGER,\\n \\"required_permission\\" TEXT,\\n \\"updated_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"ttl_ms":{"type":"INTEGER","notNull":false,"unique":false},"required_permission":{"type":"TEXT","notNull":false,"unique":false},"updated_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_policies_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_policies_tenant_kind_key","columns":["tenant_id","kind"],"unique":true},{"name":"approval_policies_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"80929cc8"},"importPath":"@happyvertical/smrt-approvals"},"@happyvertical/smrt-approvals:ApprovalRequest":{"name":"approvalrequest","className":"ApprovalRequest","qualifiedName":"@happyvertical/smrt-approvals:ApprovalRequest","collection":"approvalrequests","description":"A request for approval of one subject revision.","filePath":"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalRequest.ts","packageName":"@happyvertical/smrt-approvals","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"kind":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"subjectType":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"subjectId":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"subjectRevisionHash":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"requestKey":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"requestedBy":{"type":"text","required":true,"_meta":{"required":true,"readonly":true},"readonly":true},"requestedByType":{"type":"text","required":false,"_meta":{"readonly":true},"enum":["human","agent","service"],"readonly":true},"summary":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"status":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"requiredApprovals":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"approvalCount":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"requiredPermissions":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true},"version":{"type":"integer","required":false,"_meta":{"readonly":true},"readonly":true},"expiresAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"decidedAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"consumedAt":{"type":"datetime","required":false,"_meta":{"readonly":true},"readonly":true},"consumedBy":{"type":"text","required":false,"_meta":{"readonly":true},"readonly":true}},"methods":{"getRequiredPermissions":{"name":"getRequiredPermissions","async":false,"parameters":[],"returnType":"string[]","isStatic":false,"isPublic":true},"setRequiredPermissions":{"name":"setRequiredPermissions","async":false,"parameters":[{"name":"slugs","type":"any","optional":false,"typeUnresolved":true}],"returnType":"void","isStatic":false,"isPublic":true},"expiresAtMs":{"name":"expiresAtMs","async":false,"parameters":[],"returnType":"number","isStatic":false,"isPublic":true},"isConsumed":{"name":"isConsumed","async":false,"parameters":[],"returnType":"boolean","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"approval_requests","api":{"include":["list","get"]},"mcp":{"include":["list","get"]},"cli":false,"indexes":[{"name":"approval_requests_tenant_request_key","columns":["tenantId","requestKey"],"unique":true},{"name":"approval_requests_status_expiry_idx","columns":["tenantId","status","expiresAt"]},{"name":"approval_requests_subject_idx","columns":["tenantId","subjectType","subjectId"]}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"ApprovalRequest","collectionExportName":"ApprovalRequestCollection","validationRules":[{"field":"kind","rule":"required","fieldType":"text"},{"field":"subjectType","rule":"required","fieldType":"text"},{"field":"subjectId","rule":"required","fieldType":"text"},{"field":"subjectRevisionHash","rule":"required","fieldType":"text"},{"field":"requestKey","rule":"required","fieldType":"text"},{"field":"requestedBy","rule":"required","fieldType":"text"}],"schema":{"tableName":"approval_requests","ddl":"CREATE TABLE IF NOT EXISTS \\"approval_requests\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"kind\\" TEXT NOT NULL,\\n \\"subject_type\\" TEXT NOT NULL,\\n \\"subject_id\\" TEXT NOT NULL,\\n \\"subject_revision_hash\\" TEXT NOT NULL,\\n \\"request_key\\" TEXT NOT NULL,\\n \\"requested_by\\" TEXT NOT NULL,\\n \\"requested_by_type\\" TEXT,\\n \\"summary\\" TEXT,\\n \\"status\\" TEXT,\\n \\"required_approvals\\" INTEGER,\\n \\"approval_count\\" INTEGER,\\n \\"required_permissions\\" TEXT,\\n \\"version\\" INTEGER,\\n \\"expires_at\\" TIMESTAMP,\\n \\"decided_at\\" TIMESTAMP,\\n \\"consumed_at\\" TIMESTAMP,\\n \\"consumed_by\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"kind":{"type":"TEXT","notNull":true,"unique":false},"subject_type":{"type":"TEXT","notNull":true,"unique":false},"subject_id":{"type":"TEXT","notNull":true,"unique":false},"subject_revision_hash":{"type":"TEXT","notNull":true,"unique":false},"request_key":{"type":"TEXT","notNull":true,"unique":false},"requested_by":{"type":"TEXT","notNull":true,"unique":false},"requested_by_type":{"type":"TEXT","notNull":false,"unique":false},"summary":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"required_approvals":{"type":"INTEGER","notNull":false,"unique":false},"approval_count":{"type":"INTEGER","notNull":false,"unique":false},"required_permissions":{"type":"TEXT","notNull":false,"unique":false},"version":{"type":"INTEGER","notNull":false,"unique":false},"expires_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"decided_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"consumed_by":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"approval_requests_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"approval_requests_tenant_request_key","columns":["tenant_id","request_key"],"unique":true},{"name":"approval_requests_status_expiry_idx","columns":["tenant_id","status","expires_at"]},{"name":"approval_requests_subject_idx","columns":["tenant_id","subject_type","subject_id"]},{"name":"approval_requests_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"a5800bdd"},"importPath":"@happyvertical/smrt-approvals"}},"moduleType":"smrt","smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-tenancy","@happyvertical/smrt-users"],"browser":{"status":"server-only","issues":["#3617","#3624","#3626"],"via":["@happyvertical/smrt-profiles","@happyvertical/smrt-tenancy","@happyvertical/smrt-users"]},"stampsConstructors":true}`));
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/permissions.ts
|
|
9
9
|
var CANCEL_ANY_APPROVAL_PERMISSION = "approvals.cancel-any";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["policies"],"sources":["../src/__smrt-register__.ts","../src/permissions.ts","../src/write-capability.ts","../src/models/ApprovalRequest.ts","../src/models/ApprovalEvent.ts","../src/collections/ApprovalEventCollection.ts","../src/kinds.ts","../src/models/ApprovalPolicy.ts","../src/collections/ApprovalPolicyCollection.ts","../src/collections/ApprovalRequestCollection.ts","../src/service.ts","../src/index.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"packageVersion\\\":\\\"0.55.20\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-approvals:ApprovalEventCollection\\\":{\\\"name\\\":\\\"approvaleventcollection\\\",\\\"className\\\":\\\"ApprovalEventCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalEventCollection\\\",\\\"collection\\\":\\\"approvalevents\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalEventCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"tableName\\\":\\\"approval_events\\\"},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"ApprovalEvent\\\",\\\"exportName\\\":\\\"ApprovalEventCollection\\\",\\\"collectionExportName\\\":\\\"ApprovalEventCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"approval_events\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_events\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"request_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_type\\\\\\\" TEXT,\\\\n \\\\\\\"reason\\\\\\\" TEXT,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT,\\\\n \\\\\\\"sequence\\\\\\\" INTEGER,\\\\n \\\\\\\"vote_key\\\\\\\" TEXT,\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"self_approved\\\\\\\" BOOLEAN DEFAULT FALSE,\\\\n \\\\\\\"self_approval_permission\\\\\\\" TEXT DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"approval_requests\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sequence\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"vote_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"self_approved\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":false},\\\"self_approval_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_events_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_sequence_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"sequence\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_vote_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"vote_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_tenant_occurred_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"occurred_at\\\"]},{\\\"name\\\":\\\"approval_events_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"998756b0\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalPolicyCollection\\\":{\\\"name\\\":\\\"approvalpolicycollection\\\",\\\"className\\\":\\\"ApprovalPolicyCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalPolicyCollection\\\",\\\"collection\\\":\\\"approvalpolicies\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalPolicyCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"tableName\\\":\\\"approval_policies\\\"},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"ApprovalPolicy\\\",\\\"exportName\\\":\\\"ApprovalPolicyCollection\\\",\\\"collectionExportName\\\":\\\"ApprovalPolicyCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"approval_policies\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_policies\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"ttl_ms\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permission\\\\\\\" TEXT,\\\\n \\\\\\\"updated_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ttl_ms\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"updated_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_policies_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_kind_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"kind\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"80929cc8\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalRequestCollection\\\":{\\\"name\\\":\\\"approvalrequestcollection\\\",\\\"className\\\":\\\"ApprovalRequestCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalRequestCollection\\\",\\\"collection\\\":\\\"approvalrequests\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalRequestCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"tableName\\\":\\\"approval_requests\\\"},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"ApprovalRequest\\\",\\\"exportName\\\":\\\"ApprovalRequestCollection\\\",\\\"collectionExportName\\\":\\\"ApprovalRequestCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"approval_requests\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_requests\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"request_key\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by_type\\\\\\\" TEXT,\\\\n \\\\\\\"summary\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"approval_count\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permissions\\\\\\\" TEXT,\\\\n \\\\\\\"version\\\\\\\" INTEGER,\\\\n \\\\\\\"expires_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"decided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"summary\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"approval_count\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permissions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"version\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"expires_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"decided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_requests_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_tenant_request_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"request_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_status_expiry_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"status\\\",\\\"expires_at\\\"]},{\\\"name\\\":\\\"approval_requests_subject_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"subject_type\\\",\\\"subject_id\\\"]},{\\\"name\\\":\\\"approval_requests_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"a5800bdd\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalEvent\\\":{\\\"name\\\":\\\"approvalevent\\\",\\\"className\\\":\\\"ApprovalEvent\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalEvent\\\",\\\"collection\\\":\\\"approvalevents\\\",\\\"description\\\":\\\"One immutable entry in an approval request's history.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalEvent.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"requestId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"ApprovalRequest\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"constraint\\\":{\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]},\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\"}},\\\"type\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"actorId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"actorType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"enum\\\":[\\\"human\\\",\\\"agent\\\",\\\"service\\\"],\\\"readonly\\\":true},\\\"reason\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectRevisionHash\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"sequence\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"voteKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"occurredAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"selfApproved\\\":{\\\"type\\\":\\\"boolean\\\",\\\"required\\\":false,\\\"default\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true,\\\"default\\\":false},\\\"readonly\\\":true},\\\"selfApprovalPermission\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"readonly\\\":true,\\\"default\\\":\\\"\\\"},\\\"readonly\\\":true}},\\\"methods\\\":{\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"approval_events\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"approval_events_request_sequence_key\\\",\\\"columns\\\":[\\\"requestId\\\",\\\"sequence\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_vote_key\\\",\\\"columns\\\":[\\\"requestId\\\",\\\"voteKey\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_tenant_occurred_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"occurredAt\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"ApprovalEvent\\\",\\\"collectionExportName\\\":\\\"ApprovalEventCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"requestId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"type\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"actorId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"approval_events\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_events\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"request_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_type\\\\\\\" TEXT,\\\\n \\\\\\\"reason\\\\\\\" TEXT,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT,\\\\n \\\\\\\"sequence\\\\\\\" INTEGER,\\\\n \\\\\\\"vote_key\\\\\\\" TEXT,\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"self_approved\\\\\\\" BOOLEAN DEFAULT FALSE,\\\\n \\\\\\\"self_approval_permission\\\\\\\" TEXT DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"approval_requests\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sequence\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"vote_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"self_approved\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":false},\\\"self_approval_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_events_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_sequence_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"sequence\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_vote_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"vote_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_tenant_occurred_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"occurred_at\\\"]},{\\\"name\\\":\\\"approval_events_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"998756b0\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalPolicy\\\":{\\\"name\\\":\\\"approvalpolicy\\\",\\\"className\\\":\\\"ApprovalPolicy\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalPolicy\\\",\\\"collection\\\":\\\"approvalpolicies\\\",\\\"description\\\":\\\"Tenant-level tightening of an approval kind. One row per tenant and kind.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalPolicy.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"requiredApprovals\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{}},\\\"ttlMs\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{}},\\\"requiredPermission\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{}},\\\"updatedBy\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{}}},\\\"methods\\\":{\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"approval_policies\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"approval_policies_tenant_kind_key\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"kind\\\"],\\\"unique\\\":true}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"ApprovalPolicy\\\",\\\"collectionExportName\\\":\\\"ApprovalPolicyCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"kind\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"approval_policies\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_policies\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"ttl_ms\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permission\\\\\\\" TEXT,\\\\n \\\\\\\"updated_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ttl_ms\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"updated_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_policies_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_kind_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"kind\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"80929cc8\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalRequest\\\":{\\\"name\\\":\\\"approvalrequest\\\",\\\"className\\\":\\\"ApprovalRequest\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalRequest\\\",\\\"collection\\\":\\\"approvalrequests\\\",\\\"description\\\":\\\"A request for approval of one subject revision.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalRequest.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectRevisionHash\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestedBy\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestedByType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"enum\\\":[\\\"human\\\",\\\"agent\\\",\\\"service\\\"],\\\"readonly\\\":true},\\\"summary\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requiredApprovals\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"approvalCount\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requiredPermissions\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"version\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"expiresAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"decidedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"consumedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"consumedBy\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true}},\\\"methods\\\":{\\\"getRequiredPermissions\\\":{\\\"name\\\":\\\"getRequiredPermissions\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"string[]\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"setRequiredPermissions\\\":{\\\"name\\\":\\\"setRequiredPermissions\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"slugs\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":false,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"expiresAtMs\\\":{\\\"name\\\":\\\"expiresAtMs\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"number\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isConsumed\\\":{\\\"name\\\":\\\"isConsumed\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"approval_requests\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"approval_requests_tenant_request_key\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"requestKey\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_status_expiry_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"status\\\",\\\"expiresAt\\\"]},{\\\"name\\\":\\\"approval_requests_subject_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"subjectType\\\",\\\"subjectId\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"ApprovalRequest\\\",\\\"collectionExportName\\\":\\\"ApprovalRequestCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"kind\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"subjectType\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"subjectId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"subjectRevisionHash\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"requestKey\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"requestedBy\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"approval_requests\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_requests\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"request_key\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by_type\\\\\\\" TEXT,\\\\n \\\\\\\"summary\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"approval_count\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permissions\\\\\\\" TEXT,\\\\n \\\\\\\"version\\\\\\\" INTEGER,\\\\n \\\\\\\"expires_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"decided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"summary\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"approval_count\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permissions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"version\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"expires_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"decided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_requests_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_tenant_request_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"request_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_status_expiry_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"status\\\",\\\"expires_at\\\"]},{\\\"name\\\":\\\"approval_requests_subject_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"subject_type\\\",\\\"subject_id\\\"]},{\\\"name\\\":\\\"approval_requests_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"a5800bdd\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\",\\\"@happyvertical/smrt-users\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3617\\\",\\\"#3624\\\",\\\"#3626\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-profiles\\\",\\\"@happyvertical/smrt-tenancy\\\",\\\"@happyvertical/smrt-users\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/**\n * Permission slugs contributed by `@happyvertical/smrt-approvals` to the\n * runtime permission catalog. Deciding a request is gated by the per-kind\n * slug a package passes to `defineApprovalKind`; these slugs cover the\n * package-wide operations.\n *\n * @packageDocumentation\n */\n\nimport {\n type PermissionDefinition,\n registerPermissionDefinitions,\n} from '@happyvertical/smrt-users';\n\n/** Cancel a pending request someone else made. */\nexport const CANCEL_ANY_APPROVAL_PERMISSION = 'approvals.cancel-any';\n\n/** Write tenant approval policy rows (tighten-only). */\nexport const MANAGE_APPROVAL_POLICY_PERMISSION = 'approvals.manage-policy';\n\n/** Catalog definitions for the package-wide slugs. */\nexport const APPROVAL_PERMISSION_DEFINITIONS: PermissionDefinition[] = [\n {\n slug: CANCEL_ANY_APPROVAL_PERMISSION,\n category: 'approvals',\n name: 'Cancel Any Approval Request',\n description:\n 'Cancel a pending approval request made by someone else in the tenant',\n },\n {\n slug: MANAGE_APPROVAL_POLICY_PERMISSION,\n category: 'approvals',\n name: 'Manage Approval Policy',\n description:\n \"Tighten an approval kind's quorum, expiry, or required permission for the tenant\",\n },\n];\n\nlet registered = false;\n\n/** Register the package slugs (returns an unregister function for tests). */\nexport function registerApprovalPermissions(): () => void {\n return registerPermissionDefinitions(APPROVAL_PERMISSION_DEFINITIONS);\n}\n\n/** Register the package slugs once per process (package entry side effect). */\nexport function ensureApprovalPermissionsRegistered(): void {\n if (registered) return;\n registered = true;\n registerApprovalPermissions();\n}\n","/**\n * Service-only write capability for approval requests and events.\n *\n * `ApprovalRequest` and `ApprovalEvent` rows are inserted only by\n * `ApprovalService`. The service passes {@link SERVICE_WRITE} as a\n * constructor option; the models record the instance here and refuse any\n * insert that does not carry it. A symbol key can never arrive from JSON\n * (REST body, MCP tool arguments) and this module is not part of the\n * package's public exports, so `new ApprovalRequest({ status: 'approved' })`,\n * `ApprovalRequestCollection.create(...)`, or a forged `approved` event are\n * all refused at the model layer (the `runtime-report.ts` pattern in\n * smrt-reports). This is an in-process API guard, not a defence against raw\n * SQL; `consume()` additionally re-checks the ledger.\n *\n * @internal\n * @packageDocumentation\n */\n\n/** Constructor-option key carrying the capability. Never exported publicly. */\nexport const SERVICE_WRITE = Symbol('smrt-approvals.serviceWrite');\n\n/** The only value accepted under {@link SERVICE_WRITE}. */\nconst TOKEN = Object.freeze({ capability: 'smrt-approvals.serviceWrite' });\n\n/** Instances the service minted for exactly one insert. */\nconst minted = new WeakSet<object>();\n\n/** Constructor options fragment that grants the capability. */\nexport function serviceWriteOption(): { [SERVICE_WRITE]: object } {\n return { [SERVICE_WRITE]: TOKEN };\n}\n\n/** Record `instance` as service-minted when its options carry the token. */\nexport function adoptServiceWrite(instance: object, options: unknown): void {\n if (\n options &&\n typeof options === 'object' &&\n (options as Record<symbol, unknown>)[SERVICE_WRITE] === TOKEN\n ) {\n minted.add(instance);\n }\n}\n\n/** Whether `instance` was minted by the service for insertion. */\nexport function hasServiceWrite(instance: object): boolean {\n return minted.has(instance);\n}\n","/**\n * ApprovalRequest: one decision gate on one revision of one subject.\n *\n * The row is the authority for the decision; a consumer's own status column\n * is a projection it writes in the same transaction as `consume`. Every\n * lifecycle field is changed only by `ApprovalService` through one guarded\n * conditional UPDATE, so the generated surface is read-only and a plain\n * `save()` of a loaded request is refused.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n ApprovalError,\n type ApprovalPrincipalType,\n type ApprovalStatus,\n} from '../types.js';\nimport { adoptServiceWrite, hasServiceWrite } from '../write-capability.js';\n\n/** Constructor options for {@link ApprovalRequest}. */\nexport interface ApprovalRequestOptions extends SmrtObjectOptions {\n tenantId?: string;\n kind?: string;\n subjectType?: string;\n subjectId?: string;\n subjectRevisionHash?: string;\n requestKey?: string;\n requestedBy?: string;\n requestedByType?: ApprovalPrincipalType;\n summary?: string;\n status?: ApprovalStatus;\n requiredApprovals?: number;\n approvalCount?: number;\n requiredPermissions?: string;\n version?: number;\n expiresAt?: Date | null;\n decidedAt?: Date | null;\n consumedAt?: Date | null;\n consumedBy?: string;\n}\n\n/**\n * A request for approval of one subject revision.\n *\n * Status moves `pending` to `approved`, `rejected`, `changes_requested`,\n * `cancelled`, or `expired`; an approved request is consumed once\n * (`consumedAt` set, status stays `approved`) or expires unconsumed.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'approval_requests',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n indexes: [\n {\n name: 'approval_requests_tenant_request_key',\n columns: ['tenantId', 'requestKey'],\n unique: true,\n },\n {\n name: 'approval_requests_status_expiry_idx',\n columns: ['tenantId', 'status', 'expiresAt'],\n },\n {\n name: 'approval_requests_subject_idx',\n columns: ['tenantId', 'subjectType', 'subjectId'],\n },\n ],\n})\nexport class ApprovalRequest extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n /** Owning tenant. Every read and transition is pinned to it. */\n @tenantId()\n tenantId: string = '';\n\n /** Approval kind key, e.g. `social.post.publish`. */\n @field({ type: 'text', required: true, readonly: true })\n kind: string = '';\n\n /** Qualified subject class, e.g. `@happyvertical/smrt-social:SocialPost`. */\n @field({ type: 'text', required: true, readonly: true })\n subjectType: string = '';\n\n /** Subject id. Bare string: the subject table is polymorphic. */\n @field({ type: 'text', required: true, readonly: true })\n subjectId: string = '';\n\n /**\n * Hash of the exact subject revision being approved. `consume` must\n * present the same hash, so an approval never transfers to changed content.\n */\n @field({ type: 'text', required: true, readonly: true })\n subjectRevisionHash: string = '';\n\n /** Idempotency key, unique per tenant. A replay returns the same request. */\n @field({ type: 'text', required: true, readonly: true })\n requestKey: string = '';\n\n /** Principal id of the requester. The requester can never decide. */\n @field({ type: 'text', required: true, readonly: true })\n requestedBy: string = '';\n\n /** Principal type of the requester (`human`, `agent`, or `service`). */\n @field({ type: 'text', readonly: true })\n requestedByType: ApprovalPrincipalType = 'human';\n\n /** Short human-readable description shown to deciders. */\n @field({ type: 'text', readonly: true })\n summary: string = '';\n\n /** Lifecycle status. Changed only by guarded transitions. */\n @field({ type: 'text', readonly: true })\n status: ApprovalStatus = 'pending';\n\n /** Distinct approvers needed, fixed when the request is made. */\n @field({ type: 'integer', readonly: true })\n requiredApprovals: number = 1;\n\n /** Distinct approvals recorded so far. */\n @field({ type: 'integer', readonly: true })\n approvalCount: number = 0;\n\n /**\n * JSON array of permission slugs a decider must hold, fixed at request\n * time. Read it through {@link getRequiredPermissions}.\n */\n @field({ type: 'text', readonly: true })\n requiredPermissions: string = '[]';\n\n /** Transition counter; every guarded UPDATE requires and bumps it. */\n @field({ type: 'integer', readonly: true })\n version: number = 0;\n\n /** After this instant the request can no longer be decided or consumed. */\n @field({ type: 'datetime', readonly: true })\n expiresAt: Date | null = null;\n\n /** When the request reached a terminal decision. */\n @field({ type: 'datetime', readonly: true })\n decidedAt: Date | null = null;\n\n /** When the approval was consumed (single use). */\n @field({ type: 'datetime', readonly: true })\n consumedAt: Date | null = null;\n\n /** Principal id that consumed the approval. */\n @field({ type: 'text', readonly: true })\n consumedBy: string = '';\n\n constructor(options: ApprovalRequestOptions = {}) {\n super(options);\n adoptServiceWrite(this, options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.subjectType !== undefined)\n this.subjectType = options.subjectType;\n if (options.subjectId !== undefined) this.subjectId = options.subjectId;\n if (options.subjectRevisionHash !== undefined)\n this.subjectRevisionHash = options.subjectRevisionHash;\n if (options.requestKey !== undefined) this.requestKey = options.requestKey;\n if (options.requestedBy !== undefined)\n this.requestedBy = options.requestedBy;\n if (options.requestedByType !== undefined)\n this.requestedByType = options.requestedByType;\n if (options.summary !== undefined) this.summary = options.summary;\n if (options.status !== undefined) this.status = options.status;\n if (options.requiredApprovals !== undefined)\n this.requiredApprovals = options.requiredApprovals;\n if (options.approvalCount !== undefined)\n this.approvalCount = options.approvalCount;\n if (options.requiredPermissions !== undefined)\n this.requiredPermissions = options.requiredPermissions;\n if (options.version !== undefined) this.version = options.version;\n if (options.expiresAt !== undefined) this.expiresAt = options.expiresAt;\n if (options.decidedAt !== undefined) this.decidedAt = options.decidedAt;\n if (options.consumedAt !== undefined) this.consumedAt = options.consumedAt;\n if (options.consumedBy !== undefined) this.consumedBy = options.consumedBy;\n }\n\n /** The permission slugs a decider must hold (never throws; bad JSON = none valid). */\n getRequiredPermissions(): string[] {\n try {\n const parsed: unknown = JSON.parse(this.requiredPermissions || '[]');\n return Array.isArray(parsed)\n ? parsed.filter((slug): slug is string => typeof slug === 'string')\n : [];\n } catch {\n return [];\n }\n }\n\n /** Store the permission slugs a decider must hold. */\n setRequiredPermissions(slugs: readonly string[]): void {\n this.requiredPermissions = JSON.stringify([...slugs]);\n }\n\n /** The expiry as epoch milliseconds (`NaN` when unset or unparseable). */\n expiresAtMs(): number {\n const value = this.expiresAt as unknown;\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'string' || typeof value === 'number') {\n return new Date(value).getTime();\n }\n return Number.NaN;\n }\n\n /** True when the approval was consumed. */\n isConsumed(): boolean {\n return this.consumedAt !== null && this.consumedAt !== undefined;\n }\n\n /**\n * Refuse any insert `ApprovalService` did not mint (see\n * `write-capability.ts`), and any minted insert that does not start in the\n * initial state. Runs for ordinary saves and bulk creates alike (core\n * wraps an error thrown here; `save()` checks first so callers see it).\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN`.\n */\n protected override async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n this.assertInsertAllowed();\n }\n\n private assertInsertAllowed(): void {\n if (this.isPersisted) return;\n if (!hasServiceWrite(this)) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n 'ApprovalRequest rows are created only by ApprovalService.requestApproval().',\n );\n }\n if (\n this.status !== 'pending' ||\n Number(this.approvalCount) !== 0 ||\n Number(this.version) !== 1 ||\n this.decidedAt ||\n this.consumedAt ||\n this.consumedBy\n ) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n 'A new ApprovalRequest must start pending, undecided, and unconsumed.',\n );\n }\n }\n\n /**\n * Insert a new request. A loaded request is never re-saved: every later\n * change is a guarded transition in `ApprovalService`.\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN` for a persisted request.\n */\n override async save(): Promise<this> {\n if (this.isPersisted) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalRequest ${this.id} is changed only through ApprovalService transitions.`,\n );\n }\n this.assertInsertAllowed();\n this.requireInsertOnSave();\n return await super.save();\n }\n\n /**\n * Requests are durable records of a decision.\n *\n * @throws {ApprovalError} always.\n */\n override async delete(): Promise<void> {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalRequest ${this.id} cannot be deleted.`,\n );\n }\n}\n","/**\n * ApprovalEvent: the append-only ledger of an approval request.\n *\n * Events are the source of truth for who did what: every transition inserts\n * exactly one event in the same transaction as its guarded UPDATE. The\n * generated surface is read-only, `save()` only ever inserts, and `delete()`\n * is refused. `(requestId, sequence)` is unique (one event per request\n * version) and `(requestId, voteKey)` is unique (one decision per actor).\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n ApprovalError,\n type ApprovalEventType,\n type ApprovalPrincipalType,\n} from '../types.js';\nimport { adoptServiceWrite, hasServiceWrite } from '../write-capability.js';\nimport { ApprovalRequest } from './ApprovalRequest.js';\n\n/** Constructor options for {@link ApprovalEvent}. */\nexport interface ApprovalEventOptions extends SmrtObjectOptions {\n tenantId?: string;\n requestId?: string;\n type?: ApprovalEventType;\n actorId?: string;\n actorType?: ApprovalPrincipalType;\n reason?: string;\n selfApproved?: boolean;\n selfApprovalPermission?: string;\n subjectRevisionHash?: string;\n sequence?: number;\n voteKey?: string | null;\n occurredAt?: Date | null;\n}\n\n/** One immutable entry in an approval request's history. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'approval_events',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n indexes: [\n {\n name: 'approval_events_request_sequence_key',\n columns: ['requestId', 'sequence'],\n unique: true,\n },\n {\n name: 'approval_events_request_vote_key',\n columns: ['requestId', 'voteKey'],\n unique: true,\n },\n {\n name: 'approval_events_tenant_occurred_idx',\n columns: ['tenantId', 'occurredAt'],\n },\n ],\n})\nexport class ApprovalEvent extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n /** Owning tenant; always the request's tenant. */\n @tenantId()\n tenantId: string = '';\n\n /**\n * The request this event belongs to. DuckDB executes an UPDATE of an\n * indexed column on a referenced row as delete plus insert, so a physical\n * FK there would refuse every transition of a request that has events;\n * the constraint is physical on PostgreSQL and SQLite only. Requests are\n * never deleted, so no engine can orphan an event.\n */\n @foreignKey(ApprovalRequest, {\n required: true,\n readonly: true,\n onDelete: 'RESTRICT',\n onUpdate: 'RESTRICT',\n constraint: { engines: ['postgres', 'sqlite'] },\n })\n requestId: string = '';\n\n /** What happened. */\n @field({ type: 'text', required: true, readonly: true })\n type: ApprovalEventType = 'created';\n\n /** Principal id of the actor. */\n @field({ type: 'text', required: true, readonly: true })\n actorId: string = '';\n\n /** Principal type of the actor. */\n @field({ type: 'text', readonly: true })\n actorType: ApprovalPrincipalType = 'human';\n\n /** Free-text reason (rejection note, cancellation reason, and so on). */\n @field({ type: 'text', readonly: true })\n reason: string = '';\n\n /** The subject revision the request was bound to when this happened. */\n @field({ type: 'text', readonly: true })\n subjectRevisionHash: string = '';\n\n /** The request `version` this event produced; unique per request. */\n @field({ type: 'integer', readonly: true })\n sequence: number = 0;\n\n /**\n * The deciding actor's id on decision events, `null` otherwise; unique per\n * request so one actor decides at most once.\n */\n @field({ type: 'text', nullable: true, readonly: true })\n voteKey: string | null = null;\n\n /** When the event happened. */\n @field({ type: 'datetime', readonly: true })\n occurredAt: Date | null = null;\n\n /** Whether the requester used the explicit self-decision allowance. */\n @field({ type: 'boolean', readonly: true, default: false })\n selfApproved: boolean = false;\n\n /** Permission checked when this self-decision was recorded. Empty otherwise. */\n @field({ type: 'text', readonly: true, default: '' })\n selfApprovalPermission: string = '';\n\n constructor(options: ApprovalEventOptions = {}) {\n super(options);\n adoptServiceWrite(this, options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.requestId !== undefined) this.requestId = options.requestId;\n if (options.type !== undefined) this.type = options.type;\n if (options.actorId !== undefined) this.actorId = options.actorId;\n if (options.actorType !== undefined) this.actorType = options.actorType;\n if (options.reason !== undefined) this.reason = options.reason;\n if (options.selfApproved !== undefined)\n this.selfApproved = options.selfApproved;\n if (options.selfApprovalPermission !== undefined)\n this.selfApprovalPermission = options.selfApprovalPermission;\n if (options.subjectRevisionHash !== undefined)\n this.subjectRevisionHash = options.subjectRevisionHash;\n if (options.sequence !== undefined) this.sequence = options.sequence;\n if (options.voteKey !== undefined) this.voteKey = options.voteKey;\n if (options.occurredAt !== undefined) this.occurredAt = options.occurredAt;\n }\n\n /**\n * Append the event. An event is written once and never updated.\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN` for a persisted event.\n */\n override async save(): Promise<this> {\n if (this.isPersisted) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalEvent ${this.id} is append-only and cannot be updated.`,\n );\n }\n this.assertInsertAllowed();\n if (!this.occurredAt) this.occurredAt = new Date();\n this.requireInsertOnSave();\n return await super.save();\n }\n\n /**\n * Refuse any insert `ApprovalService` did not mint in the same transaction\n * as its guarded UPDATE (see `write-capability.ts`): a forged `approved`\n * event would otherwise count toward quorum. Runs for ordinary saves and\n * bulk creates alike.\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN`.\n */\n protected override async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n this.assertInsertAllowed();\n }\n\n private assertInsertAllowed(): void {\n if (this.isPersisted || hasServiceWrite(this)) return;\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n 'ApprovalEvent rows are appended only by ApprovalService transitions.',\n );\n }\n\n /**\n * Events are append-only.\n *\n * @throws {ApprovalError} always.\n */\n override async delete(): Promise<void> {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalEvent ${this.id} is append-only and cannot be deleted.`,\n );\n }\n}\n","/**\n * Collection for {@link ApprovalEvent}. Reads only: every write goes\n * through `ApprovalService`.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection, smrt } from '@happyvertical/smrt-core';\nimport { ApprovalEvent } from '../models/ApprovalEvent.js';\n\n/** Tenant-scoped reads of {@link ApprovalEvent} rows. */\n// Core applies a collection's `@smrt()` config to its item class as well,\n// and an undecorated collection keeps its own registry entry with the\n// full-CRUD default. Repeat the model's read-only surface exactly.\n@smrt({\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class ApprovalEventCollection extends SmrtCollection<ApprovalEvent> { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n static readonly _itemClass = ApprovalEvent;\n}\n","/**\n * The approval-kind registry and tighten-only policy arithmetic.\n *\n * A package opts in with {@link defineApprovalKind}: the kind's defaults are\n * the loosest rules any tenant can run. A tenant {@link ApprovalPolicy} row\n * may raise the quorum, shorten the expiry, or add a required permission,\n * never the reverse; {@link assertPolicyTightens} refuses a loosening write\n * and {@link effectiveRules} clamps any stored row to the defaults, so a row\n * written around the service still cannot loosen a kind.\n *\n * @packageDocumentation\n */\n\nimport {\n ApprovalError,\n type ApprovalKind,\n type ApprovalKindInput,\n type EffectiveApprovalRules,\n} from './types.js';\n\n/** Upper bound on quorum: a gate, not a ballot. */\nexport const MAX_REQUIRED_APPROVALS = 25;\n\n/** Default lifetime of a request: seven days. */\nexport const DEFAULT_APPROVAL_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** Longest lifetime a kind may declare: one year. */\nexport const MAX_APPROVAL_TTL_MS = 366 * 24 * 60 * 60 * 1000;\n\n/** Shortest lifetime anything may set: one minute. */\nexport const MIN_APPROVAL_TTL_MS = 60 * 1000;\n\nconst KIND_KEY = /^[a-z][a-z0-9-]*(?:\\.[a-z][a-z0-9_-]*)+$/;\nconst QUALIFIED_CLASS =\n /^@[a-z0-9][a-z0-9._-]*\\/[a-z0-9][a-z0-9._-]*:[A-Za-z_$][\\w$]*$/;\nconst PERMISSION_SLUG = /^[a-z][a-z0-9_-]*(?:\\.[a-z0-9][a-z0-9_-]*)+$/;\n\nconst kinds = new Map<string, ApprovalKind>();\n\n/** True for a well-formed permission slug such as `social.approve-post`. */\nexport function isPermissionSlug(value: unknown): value is string {\n return typeof value === 'string' && PERMISSION_SLUG.test(value);\n}\n\nfunction assertQuorum(value: number, label: string): void {\n if (\n !Number.isSafeInteger(value) ||\n value < 1 ||\n value > MAX_REQUIRED_APPROVALS\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be an integer from 1 to ${MAX_REQUIRED_APPROVALS}, got ${String(value)}.`,\n );\n }\n}\n\nfunction assertTtl(value: number, label: string): void {\n if (\n !Number.isSafeInteger(value) ||\n value < MIN_APPROVAL_TTL_MS ||\n value > MAX_APPROVAL_TTL_MS\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be an integer number of milliseconds from ${MIN_APPROVAL_TTL_MS} to ${MAX_APPROVAL_TTL_MS}, got ${String(value)}.`,\n );\n }\n}\n\n/**\n * Register an approval kind. Calling it again with an identical definition\n * returns the registered kind (module re-evaluation is harmless); a\n * different definition under the same key throws.\n *\n * @throws {ApprovalError} `APPROVAL_INVALID` or `APPROVAL_KIND_CONFLICT`.\n */\nexport function defineApprovalKind(input: ApprovalKindInput): ApprovalKind {\n if (!KIND_KEY.test(input.key ?? '')) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval kind key must be dotted lower case such as 'social.post.publish', got '${String(input.key)}'.`,\n );\n }\n if (!QUALIFIED_CLASS.test(input.subject ?? '')) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval kind '${input.key}' subject must be a qualified class name such as '@happyvertical/smrt-social:SocialPost', got '${String(input.subject)}'.`,\n );\n }\n if (!isPermissionSlug(input.permission)) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval kind '${input.key}' permission must be a slug such as 'social.approve-post', got '${String(input.permission)}'.`,\n );\n }\n if (\n input.selfApprovalPermission !== undefined &&\n !isPermissionSlug(input.selfApprovalPermission)\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'selfApprovalPermission must be a permission slug.',\n );\n }\n const requiredApprovals = input.defaults?.requiredApprovals ?? 1;\n const ttlMs = input.defaults?.ttlMs ?? DEFAULT_APPROVAL_TTL_MS;\n assertQuorum(\n requiredApprovals,\n `Approval kind '${input.key}' requiredApprovals`,\n );\n assertTtl(ttlMs, `Approval kind '${input.key}' ttlMs`);\n\n const kind: ApprovalKind = Object.freeze({\n key: input.key,\n subject: input.subject,\n permission: input.permission,\n selfApprovalPermission: input.selfApprovalPermission,\n defaults: Object.freeze({ requiredApprovals, ttlMs }),\n });\n const existing = kinds.get(kind.key);\n if (existing) {\n if (\n existing.subject === kind.subject &&\n existing.permission === kind.permission &&\n existing.selfApprovalPermission === kind.selfApprovalPermission &&\n existing.defaults.requiredApprovals === requiredApprovals &&\n existing.defaults.ttlMs === ttlMs\n ) {\n return existing;\n }\n throw new ApprovalError(\n 'APPROVAL_KIND_CONFLICT',\n `Approval kind '${kind.key}' is already defined with different rules.`,\n );\n }\n kinds.set(kind.key, kind);\n return kind;\n}\n\n/** The registered kind for `key`, or `undefined`. */\nexport function getApprovalKind(key: string): ApprovalKind | undefined {\n return kinds.get(key);\n}\n\n/** Every registered kind, sorted by key. */\nexport function listApprovalKinds(): ApprovalKind[] {\n return [...kinds.values()].sort((a, b) => a.key.localeCompare(b.key));\n}\n\n/** The registered kind for `key`; throws when it is unknown. */\nexport function requireApprovalKind(key: string): ApprovalKind {\n const kind = kinds.get(key);\n if (!kind) {\n throw new ApprovalError(\n 'APPROVAL_KIND_UNKNOWN',\n `Approval kind '${key}' is not defined in this process. Import the package that calls defineApprovalKind() for it.`,\n );\n }\n return kind;\n}\n\n/** Remove a kind (test helper). */\nexport function unregisterApprovalKind(key: string): boolean {\n return kinds.delete(key);\n}\n\n/** The tightening a tenant policy row may carry. `0`/`''` mean \"inherit\". */\nexport interface ApprovalPolicyRules {\n requiredApprovals?: number;\n ttlMs?: number;\n requiredPermission?: string;\n}\n\n/**\n * Refuse a policy that would loosen `kind`: a quorum below the default, an\n * expiry above the default, or a malformed permission slug.\n *\n * @throws {ApprovalError} `APPROVAL_POLICY_LOOSENS` or `APPROVAL_INVALID`.\n */\nexport function assertPolicyTightens(\n kind: ApprovalKind,\n rules: ApprovalPolicyRules,\n): void {\n const quorum = rules.requiredApprovals ?? 0;\n if (quorum !== 0) {\n assertQuorum(quorum, `Approval policy for '${kind.key}' requiredApprovals`);\n if (quorum < kind.defaults.requiredApprovals) {\n throw new ApprovalError(\n 'APPROVAL_POLICY_LOOSENS',\n `Approval policy for '${kind.key}' may only raise requiredApprovals (default ${kind.defaults.requiredApprovals}), got ${quorum}.`,\n );\n }\n }\n const ttl = rules.ttlMs ?? 0;\n if (ttl !== 0) {\n assertTtl(ttl, `Approval policy for '${kind.key}' ttlMs`);\n if (ttl > kind.defaults.ttlMs) {\n throw new ApprovalError(\n 'APPROVAL_POLICY_LOOSENS',\n `Approval policy for '${kind.key}' may only shorten ttlMs (default ${kind.defaults.ttlMs}), got ${ttl}.`,\n );\n }\n }\n const permission = rules.requiredPermission ?? '';\n if (permission !== '' && !isPermissionSlug(permission)) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval policy for '${kind.key}' requiredPermission must be a permission slug, got '${permission}'.`,\n );\n }\n}\n\n/**\n * The rules a request runs under: the kind's defaults tightened by `policy`.\n * Clamps rather than trusts the row, so a stored row that would loosen the\n * kind (written around the service, or left over after a package raised its\n * defaults) is ignored for the loosening part; a malformed permission slug\n * fails closed by staying in the required set (no principal holds it).\n */\nexport function effectiveRules(\n kind: ApprovalKind,\n policy?: ApprovalPolicyRules | null,\n): EffectiveApprovalRules {\n const policyQuorum = Number(policy?.requiredApprovals ?? 0);\n const policyTtl = Number(policy?.ttlMs ?? 0);\n const requiredApprovals =\n Number.isSafeInteger(policyQuorum) && policyQuorum > 0\n ? Math.min(\n Math.max(kind.defaults.requiredApprovals, policyQuorum),\n MAX_REQUIRED_APPROVALS,\n )\n : kind.defaults.requiredApprovals;\n const ttlMs =\n Number.isSafeInteger(policyTtl) && policyTtl > 0\n ? Math.max(Math.min(kind.defaults.ttlMs, policyTtl), MIN_APPROVAL_TTL_MS)\n : kind.defaults.ttlMs;\n const requiredPermissions = [kind.permission];\n const extra = String(policy?.requiredPermission ?? '').trim();\n if (extra && !requiredPermissions.includes(extra)) {\n requiredPermissions.push(extra);\n }\n return { requiredApprovals, ttlMs, requiredPermissions };\n}\n","/**\n * ApprovalPolicy: a tenant's tightening of one approval kind.\n *\n * A row may raise the quorum, shorten the expiry, or add one required\n * permission; it can never loosen the kind's package defaults. Writes go\n * through `ApprovalService.setPolicy`, which refuses loosening, and\n * `effectiveRules` clamps any stored row when a request is made. A policy\n * applies to requests made after it is written; existing requests keep the\n * rules fixed at request time.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { assertPolicyTightens, requireApprovalKind } from '../kinds.js';\n\n/** Constructor options for {@link ApprovalPolicy}. */\nexport interface ApprovalPolicyOptions extends SmrtObjectOptions {\n tenantId?: string;\n kind?: string;\n requiredApprovals?: number;\n ttlMs?: number;\n requiredPermission?: string;\n updatedBy?: string;\n}\n\n/** Tenant-level tightening of an approval kind. One row per tenant and kind. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'approval_policies',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n indexes: [\n {\n name: 'approval_policies_tenant_kind_key',\n columns: ['tenantId', 'kind'],\n unique: true,\n },\n ],\n})\nexport class ApprovalPolicy extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n /** Owning tenant. */\n @tenantId()\n tenantId: string = '';\n\n /** Approval kind key this row tightens. */\n @field({ type: 'text', required: true })\n kind: string = '';\n\n /** Raised quorum; `0` inherits the kind default. */\n @field({ type: 'integer' })\n requiredApprovals: number = 0;\n\n /** Shortened lifetime in milliseconds; `0` inherits the kind default. */\n @field({ type: 'integer' })\n ttlMs: number = 0;\n\n /** Extra permission slug a decider must hold; empty for none. */\n @field({ type: 'text' })\n requiredPermission: string = '';\n\n /** Principal id that last wrote the row. */\n @field({ type: 'text' })\n updatedBy: string = '';\n\n constructor(options: ApprovalPolicyOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.requiredApprovals !== undefined)\n this.requiredApprovals = options.requiredApprovals;\n if (options.ttlMs !== undefined) this.ttlMs = options.ttlMs;\n if (options.requiredPermission !== undefined)\n this.requiredPermission = options.requiredPermission;\n if (options.updatedBy !== undefined) this.updatedBy = options.updatedBy;\n }\n\n /**\n * Validate against the registered kind, then persist. A row for an unknown\n * kind, or one that would loosen the kind, is refused.\n *\n * @throws {ApprovalError} `APPROVAL_KIND_UNKNOWN`,\n * `APPROVAL_POLICY_LOOSENS`, or `APPROVAL_INVALID`.\n */\n override async save(): Promise<this> {\n this.requiredPermission = String(this.requiredPermission ?? '').trim();\n this.requiredApprovals = Number(this.requiredApprovals ?? 0);\n this.ttlMs = Number(this.ttlMs ?? 0);\n assertPolicyTightens(requireApprovalKind(this.kind), {\n requiredApprovals: this.requiredApprovals,\n ttlMs: this.ttlMs,\n requiredPermission: this.requiredPermission,\n });\n return await super.save();\n }\n}\n","/**\n * Collection for {@link ApprovalPolicy}. Reads only: every write goes\n * through `ApprovalService`.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection, smrt } from '@happyvertical/smrt-core';\nimport { ApprovalPolicy } from '../models/ApprovalPolicy.js';\n\n/** Tenant-scoped reads of {@link ApprovalPolicy} rows. */\n// Core applies a collection's `@smrt()` config to its item class as well,\n// and an undecorated collection keeps its own registry entry with the\n// full-CRUD default. Repeat the model's read-only surface exactly.\n@smrt({\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class ApprovalPolicyCollection extends SmrtCollection<ApprovalPolicy> { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n static readonly _itemClass = ApprovalPolicy;\n}\n","/**\n * Collection for {@link ApprovalRequest}. Reads only: every write goes\n * through `ApprovalService`.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection, smrt } from '@happyvertical/smrt-core';\nimport { ApprovalRequest } from '../models/ApprovalRequest.js';\n\n/** Tenant-scoped reads of {@link ApprovalRequest} rows. */\n// Core applies a collection's `@smrt()` config to its item class as well,\n// and an undecorated collection keeps its own registry entry with the\n// full-CRUD default. Repeat the model's read-only surface exactly.\n@smrt({\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class ApprovalRequestCollection extends SmrtCollection<ApprovalRequest> { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n static readonly _itemClass = ApprovalRequest;\n}\n","/**\n * ApprovalService: the only write path for approval requests.\n *\n * Every transition is ONE guarded conditional `UPDATE ... WHERE id AND\n * tenant_id AND status AND version AND expiry ... RETURNING version` plus\n * one {@link ApprovalEvent} insert, in the same database transaction (the\n * `CliAuthRequestCollection.approvePendingRequest` and\n * `CommissionPayoutService.transitionPayoutForSource` shape):\n *\n * - The guarded UPDATE is the arbiter. Two concurrent transitions of one\n * request both read version `v`; only one UPDATE can match `version = v`.\n * The loser matches zero rows, writes nothing, and retries from a fresh\n * read, where it sees the winner's state and is refused cleanly\n * (`not_pending`, `already_decided`, `already_consumed`).\n * - PostgreSQL runs each transaction on its own pooled connection; the\n * UPDATE's row lock serializes writers and READ COMMITTED re-evaluates the\n * predicate after the winner commits. On embedded engines (SQLite,\n * DuckDB) each transaction runs through core's embedded write queue\n * (`withEmbeddedWriteTransaction`), which takes the queue before the\n * connection lock and serializes writers per database; the predicate\n * still decides.\n * - Every statement names the tenant explicitly and the work runs inside\n * `withTenant(principal.tenantId)`, so tenancy interceptors and the raw\n * predicate both pin the row; a cross-tenant id is `not_found`.\n * - Events are inserted through a collection bound to the transaction\n * database (the tx-bound collection pattern), so a failed insert rolls\n * the UPDATE back.\n *\n * @packageDocumentation\n */\n\nimport {\n appendChange,\n isEmbeddedDatabase,\n isUniqueViolationError,\n withEmbeddedWriteQueue,\n withEmbeddedWriteTransaction,\n} from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n isSystemContext,\n withTenant,\n} from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { ApprovalEventCollection } from './collections/ApprovalEventCollection.js';\nimport { ApprovalPolicyCollection } from './collections/ApprovalPolicyCollection.js';\nimport { ApprovalRequestCollection } from './collections/ApprovalRequestCollection.js';\nimport {\n type ApprovalPolicyRules,\n assertPolicyTightens,\n effectiveRules,\n isPermissionSlug,\n requireApprovalKind,\n} from './kinds.js';\nimport type { ApprovalEvent } from './models/ApprovalEvent.js';\nimport type { ApprovalPolicy } from './models/ApprovalPolicy.js';\nimport type { ApprovalRequest } from './models/ApprovalRequest.js';\nimport {\n CANCEL_ANY_APPROVAL_PERMISSION,\n MANAGE_APPROVAL_POLICY_PERMISSION,\n} from './permissions.js';\nimport {\n APPROVAL_PRINCIPAL_TYPES,\n type ApprovalDecision,\n ApprovalError,\n type ApprovalEventType,\n type ApprovalKind,\n type ApprovalPrincipal,\n type ApprovalRefusalReason,\n type ApprovalStatus,\n type ApprovalTransitionResult,\n} from './types.js';\nimport { serviceWriteOption } from './write-capability.js';\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Longest accepted id, key, or hash string. */\nconst MAX_TOKEN_LENGTH = 256;\n\n/** Longest accepted reason or summary. */\nconst MAX_TEXT_LENGTH = 4000;\n\n/** Attempts before a transition gives up as `contention`. */\nconst DEFAULT_MAX_ATTEMPTS = 8;\n\nconst REQUESTS_TABLE = 'approval_requests';\n\n/** Adapter capabilities the service relies on. */\ntype TransactionCapableDatabase = DatabaseInterface & {\n transaction?: <T>(\n callback: (tx: DatabaseInterface) => Promise<T>,\n ) => Promise<T>;\n};\n\n/** What a transaction body reports across the commit boundary (ids only). */\ntype TxOutcome =\n | { kind: 'done'; outcome: 'transitioned' | 'already_applied'; id: string }\n | {\n kind: 'refused';\n reason: ApprovalRefusalReason;\n detail: string;\n id: string | null;\n }\n | { kind: 'retry' };\n\n/** Options for {@link ApprovalService}. */\nexport interface ApprovalServiceOptions {\n /** The database every transition runs against. Must support transactions. */\n db: DatabaseInterface;\n /** Clock override for deterministic tests. */\n now?: () => Date;\n /** Attempts before a contended transition is refused. Default 8. */\n maxAttempts?: number;\n}\n\n/** Input for {@link ApprovalService.requestApproval}. */\nexport interface RequestApprovalInput {\n /** A kind registered with `defineApprovalKind` (or its key). */\n kind: ApprovalKind | string;\n /** The subject's id. */\n subjectId: string;\n /** Hash of the exact subject revision to approve. */\n subjectRevisionHash: string;\n /**\n * Idempotency key, unique per tenant. A replay with the same subject and\n * revision returns the existing request as `already_applied`; a replay with\n * different content is refused `request_key_conflict`. Default: random.\n */\n requestKey?: string;\n /** Short description shown to deciders. */\n summary?: string;\n}\n\n/** Input for {@link ApprovalService.decide}. */\nexport interface DecideInput {\n decision: ApprovalDecision;\n /** Required for `reject` and `request_changes`. */\n reason?: string;\n}\n\n/** Options for {@link ApprovalService.consume}. */\nexport interface ConsumeOptions {\n /**\n * Run inside the caller's open transaction (a `db.transaction()` callback\n * handle) so the consumer's own write commits or rolls back together with\n * the consumption. The caller owns the transaction. On embedded engines\n * (SQLite, DuckDB, libsql) the handle must come from\n * `withEmbeddedWriteTransaction(db, isEmbeddedDatabase(db), fn)` or\n * `SmrtObject.withTransaction()` so it holds core's embedded write queue;\n * a raw `db.transaction()` handle can deadlock against concurrent saves.\n */\n transaction?: DatabaseInterface;\n}\n\n/** Result type of every transition. */\nexport type ApprovalResult = ApprovalTransitionResult<ApprovalRequest>;\n\nconst DECISION_EVENT: Record<ApprovalDecision, ApprovalEventType> = {\n approve: 'approved',\n reject: 'rejected',\n request_changes: 'changes_requested',\n};\n\nfunction refusal(\n reason: ApprovalRefusalReason,\n detail: string,\n id: string | null = null,\n): TxOutcome {\n return { kind: 'refused', reason, detail, id };\n}\n\nfunction isoNow(date: Date): string {\n return date.toISOString();\n}\n\nfunction assertToken(value: unknown, label: string): string {\n const text = typeof value === 'string' ? value.trim() : '';\n if (!text || text.length > MAX_TOKEN_LENGTH) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be a non-empty string of at most ${MAX_TOKEN_LENGTH} characters.`,\n );\n }\n return text;\n}\n\nfunction assertText(value: unknown, label: string): string {\n if (value === undefined || value === null) return '';\n if (typeof value !== 'string' || value.length > MAX_TEXT_LENGTH) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be a string of at most ${MAX_TEXT_LENGTH} characters.`,\n );\n }\n return value.trim();\n}\n\n/**\n * Refuse a malformed principal before any database work. A principal with\n * no tenant, an unknown type, or no `can` function is a programming error.\n */\nfunction assertPrincipal(principal: ApprovalPrincipal): void {\n if (!principal || typeof principal.can !== 'function') {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'An approval principal must provide can(slug).',\n );\n }\n assertToken(principal.id, 'Approval principal id');\n if (\n typeof principal.tenantId !== 'string' ||\n !UUID_RE.test(principal.tenantId)\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'An approval principal must carry the UUID of the tenant its permissions were resolved for.',\n );\n }\n if (!APPROVAL_PRINCIPAL_TYPES.includes(principal.type)) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval principal type must be one of ${APPROVAL_PRINCIPAL_TYPES.join(', ')}.`,\n );\n }\n}\n\n/**\n * Distinct actors whose `approved` events count toward quorum: human\n * principals, including explicitly ledgered self-decisions. Legacy unmarked\n * requester events and non-human events never count.\n */\nfunction countedApprovers(\n approvals: readonly ApprovalEvent[],\n request: ApprovalRequest,\n): Set<string> {\n return new Set(\n approvals\n .filter(\n (event) =>\n event.type === 'approved' &&\n event.actorType === 'human' &&\n (event.actorId !== request.requestedBy ||\n (event.selfApproved === true &&\n isPermissionSlug(event.selfApprovalPermission))),\n )\n .map((event) => event.actorId),\n );\n}\n\nfunction rowVersion(rows: unknown[] | undefined): number | null {\n const row = rows?.[0] as Record<string, unknown> | undefined;\n if (!row) return null;\n const version = Number(row.version);\n return Number.isSafeInteger(version) ? version : null;\n}\n\n/**\n * The decision gate. Construct it over the application's database; it binds\n * its own collections per call and per transaction.\n */\nexport class ApprovalService {\n private readonly db: TransactionCapableDatabase;\n private readonly clock: () => Date;\n private readonly maxAttempts: number;\n\n constructor(options: ApprovalServiceOptions) {\n if (!options?.db || typeof options.db.query !== 'function') {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'ApprovalService requires an initialized database.',\n );\n }\n if (\n typeof (options.db as TransactionCapableDatabase).transaction !==\n 'function'\n ) {\n throw new ApprovalError(\n 'APPROVAL_NO_TRANSACTION',\n 'ApprovalService requires a database adapter with transaction support.',\n );\n }\n this.db = options.db as TransactionCapableDatabase;\n this.clock = options.now ?? (() => new Date());\n this.maxAttempts = Math.max(1, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n }\n\n // -------------------------------------------------------------------------\n // Reads\n // -------------------------------------------------------------------------\n\n /** One request in the principal's tenant, or `null`. */\n async getRequest(\n principal: ApprovalPrincipal,\n requestId: string,\n ): Promise<ApprovalRequest | null> {\n assertPrincipal(principal);\n if (!UUID_RE.test(String(requestId ?? ''))) return null;\n return await this.inTenant(principal, () =>\n this.loadRequest(this.db, principal.tenantId, requestId),\n );\n }\n\n /** A request's events in order, in the principal's tenant. */\n async listEvents(\n principal: ApprovalPrincipal,\n requestId: string,\n ): Promise<ApprovalEvent[]> {\n assertPrincipal(principal);\n if (!UUID_RE.test(String(requestId ?? ''))) return [];\n return await this.inTenant(principal, async () => {\n const events = await ApprovalEventCollection.create({ db: this.db });\n return await events.list({\n where: { tenantId: principal.tenantId, requestId },\n orderBy: 'sequence ASC',\n limit: 1000,\n });\n });\n }\n\n // -------------------------------------------------------------------------\n // Transitions\n // -------------------------------------------------------------------------\n\n /**\n * Open a request for approval of one subject revision. Any principal type\n * may request. The quorum, expiry, and required permissions are fixed now\n * from the kind's defaults tightened by the tenant's policy.\n */\n async requestApproval(\n principal: ApprovalPrincipal,\n input: RequestApprovalInput,\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const kind = requireApprovalKind(\n typeof input.kind === 'string' ? input.kind : input.kind?.key,\n );\n const subjectId = assertToken(input.subjectId, 'subjectId');\n const subjectRevisionHash = assertToken(\n input.subjectRevisionHash,\n 'subjectRevisionHash',\n );\n const requestKey =\n input.requestKey === undefined\n ? globalThis.crypto.randomUUID()\n : assertToken(input.requestKey, 'requestKey');\n const summary = assertText(input.summary, 'summary');\n const tenantId = principal.tenantId;\n\n const sameContent = (row: ApprovalRequest) =>\n row.kind === kind.key &&\n row.subjectType === kind.subject &&\n row.subjectId === subjectId &&\n row.subjectRevisionHash === subjectRevisionHash;\n\n if (this.contextMismatch(principal)) {\n return ApprovalService.mismatchResult();\n }\n return await this.inTenant(principal, async () => {\n let outcome: TxOutcome;\n try {\n outcome = await this.runTransaction(async (tx) => {\n const requests = await this.txCollection(\n ApprovalRequestCollection,\n tx,\n );\n const [existing] = await requests.list({\n where: { tenantId, requestKey },\n limit: 1,\n });\n if (existing) {\n return sameContent(existing)\n ? ({\n kind: 'done',\n outcome: 'already_applied',\n id: String(existing.id),\n } as const)\n : refusal(\n 'request_key_conflict',\n `requestKey '${requestKey}' already names a different request`,\n );\n }\n\n const policy = await this.loadPolicy(tx, tenantId, kind.key);\n const rules = effectiveRules(kind, policy);\n const now = this.clock();\n const request = await requests.create({\n tenantId,\n kind: kind.key,\n subjectType: kind.subject,\n subjectId,\n subjectRevisionHash,\n requestKey,\n requestedBy: principal.id,\n requestedByType: principal.type,\n summary,\n status: 'pending',\n requiredApprovals: rules.requiredApprovals,\n approvalCount: 0,\n requiredPermissions: JSON.stringify(rules.requiredPermissions),\n version: 1,\n expiresAt: new Date(now.getTime() + rules.ttlMs),\n // The only place a request insert is authorized.\n ...serviceWriteOption(),\n } as Parameters<ApprovalRequestCollection['create']>[0]);\n const id = String(request.id);\n await this.appendEvent(tx, {\n tenantId,\n requestId: id,\n type: 'created',\n principal,\n reason: summary,\n subjectRevisionHash,\n sequence: 1,\n now,\n });\n return { kind: 'done', outcome: 'transitioned', id } as const;\n });\n } catch (error) {\n // A concurrent request with the same key won the unique index.\n if (!isUniqueViolationError(error)) throw error;\n const requests = await ApprovalRequestCollection.create({\n db: this.db,\n });\n const [winner] = await requests.list({\n where: { tenantId, requestKey },\n limit: 1,\n });\n if (!winner) throw error;\n outcome = sameContent(winner)\n ? { kind: 'done', outcome: 'already_applied', id: String(winner.id) }\n : refusal(\n 'request_key_conflict',\n `requestKey '${requestKey}' already names a different request`,\n );\n }\n return await this.toResult(principal.tenantId, outcome);\n });\n }\n\n /**\n * Record a decision. Only a `human` principal of the request's tenant who\n * holds every required permission may decide (requesters also need the\n * kind's explicit selfApprovalPermission),\n * once, while the request is pending and unexpired. `approve` counts\n * toward the quorum of distinct approvers; `reject` and `request_changes`\n * end the request.\n */\n async decide(\n principal: ApprovalPrincipal,\n requestId: string,\n input: DecideInput,\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const eventType = DECISION_EVENT[input?.decision];\n if (!eventType) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Unknown decision '${String(input?.decision)}'.`,\n );\n }\n const reason = assertText(input.reason, 'reason');\n if (input.decision !== 'approve' && !reason) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `A '${input.decision}' decision requires a reason.`,\n );\n }\n const tenantId = principal.tenantId;\n\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (principal.type !== 'human') {\n return refusal(\n 'not_human',\n `a ${principal.type} principal cannot decide`,\n request.id,\n );\n }\n const selfApproved = principal.id === request.requestedBy;\n const selfApprovalPermission = selfApproved\n ? requireApprovalKind(request.kind).selfApprovalPermission\n : undefined;\n if (\n selfApproved &&\n (!selfApprovalPermission || !principal.can(selfApprovalPermission))\n ) {\n return refusal(\n 'self_approval',\n 'the requester lacks the kind self-approval allowance',\n request.id,\n );\n }\n const missing = (await this.requiredPermissionsFor(tx, request)).filter(\n (slug) => !principal.can(slug),\n );\n if (missing.length > 0) {\n return refusal(\n 'forbidden',\n `missing permission: ${missing.join(', ')}`,\n request.id,\n );\n }\n if (request.status !== 'pending') {\n return refusal(\n 'not_pending',\n `request is ${request.status}`,\n request.id,\n );\n }\n if (!(request.expiresAtMs() > now.getTime())) {\n return refusal('expired', 'the request expired', request.id);\n }\n\n const events = await this.txCollection(ApprovalEventCollection, tx);\n const decided = await events.list({\n where: { tenantId, requestId: request.id, voteKey: principal.id },\n limit: 1,\n });\n if (decided.length > 0) {\n return refusal(\n 'already_decided',\n 'this principal already decided',\n request.id,\n );\n }\n\n const version = Number(request.version);\n const nowIso = isoNow(now);\n let updated: { rows?: unknown[] };\n if (input.decision === 'approve') {\n // Quorum counts distinct approvers from the ledger, not a counter.\n const approvals = await events.list({\n where: { tenantId, requestId: request.id, type: 'approved' },\n limit: 1000,\n });\n const voters = countedApprovers(approvals, request);\n voters.add(principal.id);\n const count = voters.size;\n const reached = count >= Number(request.requiredApprovals);\n updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET approval_count = ?, status = ?, decided_at = ${reached ? '?' : 'decided_at'},\n version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'pending'\n AND version = ? AND expires_at > ?\n RETURNING version`,\n ...[\n count,\n reached ? 'approved' : 'pending',\n ...(reached ? [nowIso] : []),\n nowIso,\n request.id,\n tenantId,\n version,\n nowIso,\n ],\n );\n } else {\n const status: ApprovalStatus =\n input.decision === 'reject' ? 'rejected' : 'changes_requested';\n updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET status = ?, decided_at = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'pending'\n AND version = ? AND expires_at > ?\n RETURNING version`,\n status,\n nowIso,\n nowIso,\n request.id,\n tenantId,\n version,\n nowIso,\n );\n }\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: eventType,\n principal,\n reason,\n subjectRevisionHash: request.subjectRevisionHash,\n sequence: next,\n voteKey: principal.id,\n selfApproved,\n selfApprovalPermission,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n );\n }\n\n /**\n * Cancel a pending request. The requester may cancel their own request;\n * anyone else needs `approvals.cancel-any`.\n */\n async cancel(\n principal: ApprovalPrincipal,\n requestId: string,\n input: { reason?: string } = {},\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const reason = assertText(input.reason, 'reason');\n const tenantId = principal.tenantId;\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (\n principal.id !== request.requestedBy &&\n !principal.can(CANCEL_ANY_APPROVAL_PERMISSION)\n ) {\n return refusal(\n 'forbidden',\n `only the requester or a holder of ${CANCEL_ANY_APPROVAL_PERMISSION} may cancel`,\n request.id,\n );\n }\n if (request.status !== 'pending') {\n return refusal(\n 'not_pending',\n `request is ${request.status}`,\n request.id,\n );\n }\n if (!(request.expiresAtMs() > now.getTime())) {\n return refusal('expired', 'the request expired', request.id);\n }\n const nowIso = isoNow(now);\n const updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET status = 'cancelled', decided_at = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'pending'\n AND version = ? AND expires_at > ?\n RETURNING version`,\n nowIso,\n nowIso,\n request.id,\n tenantId,\n Number(request.version),\n nowIso,\n );\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: 'cancelled',\n principal,\n reason,\n subjectRevisionHash: request.subjectRevisionHash,\n sequence: next,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n );\n }\n\n /**\n * Mark one request expired: a pending request, or an approved one that\n * was never consumed, whose expiry has passed. Needs no permission (it\n * only records what time already decided), so a job may call it.\n */\n async expire(\n principal: ApprovalPrincipal,\n requestId: string,\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const tenantId = principal.tenantId;\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (\n !(\n request.status === 'pending' ||\n (request.status === 'approved' && !request.isConsumed())\n )\n ) {\n return refusal(\n 'not_pending',\n request.status === 'approved'\n ? 'the approval was consumed'\n : `request is ${request.status}`,\n request.id,\n );\n }\n if (request.expiresAtMs() > now.getTime()) {\n return refusal(\n 'not_expired',\n 'the request has not expired',\n request.id,\n );\n }\n const nowIso = isoNow(now);\n const updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET status = 'expired', decided_at = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status IN ('pending', 'approved')\n AND consumed_at IS NULL AND version = ? AND expires_at <= ?\n RETURNING version`,\n nowIso,\n nowIso,\n request.id,\n tenantId,\n Number(request.version),\n nowIso,\n );\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: 'expired',\n principal,\n reason: '',\n subjectRevisionHash: request.subjectRevisionHash,\n sequence: next,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n );\n }\n\n /**\n * Expire every due request in the principal's tenant: pending requests\n * and unconsumed approvals past their deadline, oldest expiry first, at\n * most `limit`. Returns the ids this call expired.\n */\n async expireDue(\n principal: ApprovalPrincipal,\n options: { limit?: number } = {},\n ): Promise<string[]> {\n assertPrincipal(principal);\n const limit = Math.min(Math.max(1, Math.trunc(options.limit ?? 100)), 1000);\n const now = this.clock();\n const candidates = await this.inTenant(principal, async () => {\n const requests = await ApprovalRequestCollection.create({ db: this.db });\n return await requests.list({\n where: {\n tenantId: principal.tenantId,\n status: ['pending', 'approved'],\n // Exclude consumed approvals in the query, before the limit: they\n // never expire, so filtering them afterwards let a batch of them\n // starve every later due request.\n consumedAt: null,\n 'expiresAt <=': now,\n },\n orderBy: 'expires_at ASC',\n limit,\n });\n });\n const expired: string[] = [];\n for (const candidate of candidates) {\n const result = await this.expire(principal, String(candidate.id));\n if (result.outcome === 'transitioned') expired.push(String(candidate.id));\n }\n return expired;\n }\n\n /**\n * Consume an approval exactly once. The presented hash must equal the\n * revision that was approved; the request must be approved, unconsumed,\n * and unexpired. Any principal type of the tenant may consume (the\n * consumer's own service is the executor). Pass `options.transaction` to\n * make the consumption part of the consumer's own transaction.\n */\n async consume(\n principal: ApprovalPrincipal,\n requestId: string,\n subjectRevisionHash: string,\n options: ConsumeOptions = {},\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const hash = assertToken(subjectRevisionHash, 'subjectRevisionHash');\n const tenantId = principal.tenantId;\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (request.status !== 'approved') {\n return refusal(\n 'not_approved',\n `request is ${request.status}`,\n request.id,\n );\n }\n if (request.isConsumed()) {\n return refusal(\n 'already_consumed',\n 'the approval was already used',\n request.id,\n );\n }\n if (request.subjectRevisionHash !== hash) {\n return refusal(\n 'revision_mismatch',\n 'the subject changed after it was approved',\n request.id,\n );\n }\n if (!(request.expiresAtMs() > now.getTime())) {\n return refusal('expired', 'the approval expired', request.id);\n }\n if (!(await this.ledgerBacksApproval(tx, request))) {\n return refusal(\n 'unbacked_approval',\n 'the ledger does not record this approval',\n request.id,\n );\n }\n const nowIso = isoNow(now);\n const updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET consumed_at = ?, consumed_by = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'approved'\n AND consumed_at IS NULL AND subject_revision_hash = ?\n AND version = ? AND expires_at > ?\n RETURNING version`,\n nowIso,\n principal.id,\n nowIso,\n request.id,\n tenantId,\n hash,\n Number(request.version),\n nowIso,\n );\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: 'consumed',\n principal,\n reason: '',\n subjectRevisionHash: hash,\n sequence: next,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n options.transaction,\n );\n }\n\n // -------------------------------------------------------------------------\n // Policy\n // -------------------------------------------------------------------------\n\n /**\n * Write the tenant's tightening of a kind. Needs\n * `approvals.manage-policy`; a rule that would loosen the kind's defaults\n * throws `APPROVAL_POLICY_LOOSENS`. `0`/`''` clear a rule back to the\n * default. Applies to requests made afterwards.\n */\n async setPolicy(\n principal: ApprovalPrincipal,\n kindKey: ApprovalKind | string,\n rules: ApprovalPolicyRules,\n ): Promise<ApprovalPolicy> {\n assertPrincipal(principal);\n if (\n principal.type !== 'human' ||\n !principal.can(MANAGE_APPROVAL_POLICY_PERMISSION)\n ) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `Setting approval policy needs a human principal holding ${MANAGE_APPROVAL_POLICY_PERMISSION}.`,\n );\n }\n const kind = requireApprovalKind(\n typeof kindKey === 'string' ? kindKey : kindKey?.key,\n );\n const normalized = {\n requiredApprovals: rules.requiredApprovals ?? 0,\n ttlMs: rules.ttlMs ?? 0,\n requiredPermission: String(rules.requiredPermission ?? '').trim(),\n };\n if (\n normalized.requiredPermission &&\n !isPermissionSlug(normalized.requiredPermission)\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `requiredPermission must be a permission slug, got '${normalized.requiredPermission}'.`,\n );\n }\n assertPolicyTightens(kind, normalized);\n const tenantId = principal.tenantId;\n return await this.inTenant(principal, async () => {\n const id = await this.runTransaction(async (tx) => {\n const policies = await this.txCollection(ApprovalPolicyCollection, tx);\n const [existing] = await policies.list({\n where: { tenantId, kind: kind.key },\n limit: 1,\n });\n if (existing) {\n existing.requiredApprovals = normalized.requiredApprovals;\n existing.ttlMs = normalized.ttlMs;\n existing.requiredPermission = normalized.requiredPermission;\n existing.updatedBy = principal.id;\n await existing.save();\n return String(existing.id);\n }\n const created = await policies.create({\n tenantId,\n kind: kind.key,\n ...normalized,\n updatedBy: principal.id,\n });\n return String(created.id);\n });\n const policies = await ApprovalPolicyCollection.create({ db: this.db });\n const [saved] = await policies.list({\n where: { tenantId, id },\n limit: 1,\n });\n if (!saved) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'Saved approval policy vanished.',\n );\n }\n return saved;\n });\n }\n\n /** The effective rules a new request of `kind` would get in the tenant. */\n async rulesFor(principal: ApprovalPrincipal, kindKey: ApprovalKind | string) {\n assertPrincipal(principal);\n const kind = requireApprovalKind(\n typeof kindKey === 'string' ? kindKey : kindKey?.key,\n );\n return await this.inTenant(principal, async () =>\n effectiveRules(\n kind,\n await this.loadPolicy(this.db, principal.tenantId, kind.key),\n ),\n );\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n /**\n * Run a guarded transition with retry. `body` runs inside a transaction\n * on a fresh read of the request and returns `retry` when its guarded\n * UPDATE matched no row (a concurrent transition won).\n */\n private async transition(\n principal: ApprovalPrincipal,\n requestId: string,\n body: (\n tx: DatabaseInterface,\n request: ApprovalRequest,\n now: Date,\n ) => Promise<TxOutcome>,\n callerTransaction?: DatabaseInterface,\n ): Promise<ApprovalResult> {\n if (!UUID_RE.test(String(requestId ?? ''))) {\n return {\n outcome: 'refused',\n request: null,\n refusal: { reason: 'not_found', detail: 'not a request id' },\n };\n }\n if (this.contextMismatch(principal)) {\n return ApprovalService.mismatchResult();\n }\n const tenantId = principal.tenantId;\n return await this.inTenant(principal, async () => {\n const attempt = async (tx: DatabaseInterface): Promise<TxOutcome> => {\n const request = await this.loadRequest(tx, tenantId, requestId);\n if (!request) {\n return refusal('not_found', 'no such request in this tenant');\n }\n return await body(tx, request, this.clock());\n };\n\n if (callerTransaction) {\n // The caller owns the transaction: one attempt, no retry (a lost\n // race inside someone else's transaction is reported, not retried).\n const outcome = await attempt(callerTransaction);\n if (outcome.kind === 'retry') {\n return await this.toResult(\n tenantId,\n refusal('contention', 'a concurrent transition won', requestId),\n callerTransaction,\n );\n }\n return await this.toResult(tenantId, outcome, callerTransaction);\n }\n\n for (let i = 0; i < this.maxAttempts; i++) {\n let outcome: TxOutcome;\n try {\n outcome = await this.runTransaction(attempt);\n } catch (error) {\n // A unique ledger key lost to a concurrent writer: re-read and retry.\n if (isUniqueViolationError(error)) continue;\n throw error;\n }\n if (outcome.kind !== 'retry') {\n return await this.toResult(tenantId, outcome);\n }\n }\n return await this.toResult(\n tenantId,\n refusal('contention', 'concurrent transitions kept winning', requestId),\n );\n });\n }\n\n /** True when an active tenant context names a different tenant. */\n private contextMismatch(principal: ApprovalPrincipal): boolean {\n const active = getTenantId();\n return (\n !isSystemContext() &&\n active !== undefined &&\n active !== principal.tenantId\n );\n }\n\n /** The refusal returned when {@link contextMismatch} holds. */\n private static mismatchResult(): ApprovalResult {\n return {\n outcome: 'refused',\n request: null,\n refusal: {\n reason: 'tenant_mismatch',\n detail:\n \"the principal's tenant does not match the active tenant context\",\n },\n };\n }\n\n /** Pin the work to the principal's tenant; refuse a conflicting context. */\n private async inTenant<T>(\n principal: ApprovalPrincipal,\n fn: () => Promise<T>,\n ): Promise<T> {\n if (this.contextMismatch(principal)) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `The principal's tenant does not match the active tenant context.`,\n );\n }\n // Keep post-commit reads with embedded writers on their shared connection.\n return await withEmbeddedWriteQueue(\n this.db,\n isEmbeddedDatabase(this.db),\n () => withTenant({ tenantId: principal.tenantId }, fn),\n );\n }\n\n /**\n * Run `fn` in a transaction through core's embedded write queue.\n *\n * On embedded engines (SQLite, DuckDB, libsql) the transaction takes the\n * queue for its database BEFORE the adapter's connection lock, and the\n * model writes inside it (event inserts, change-feed appends) re-enter that\n * hold. Taking the connection lock first deadlocks against an unrelated\n * save that holds the queue and then opens its own write transaction, and\n * lets other root writes land inside this BEGIN..COMMIT. The queue also\n * serializes these transactions per database in-process, which is what\n * the former per-handle promise chain did, so that chain is gone.\n * PostgreSQL is not queued: each transaction has its own pooled\n * connection and the guarded UPDATE's row lock arbitrates.\n */\n private async runTransaction<T>(\n fn: (tx: DatabaseInterface) => Promise<T>,\n ): Promise<T> {\n return await withEmbeddedWriteTransaction(\n this.db,\n isEmbeddedDatabase(this.db),\n fn,\n );\n }\n\n /** A collection bound to a transaction database. */\n private async txCollection<C>(\n Collection: { create(options: Record<string, unknown>): Promise<C> },\n tx: DatabaseInterface,\n ): Promise<C> {\n return await Collection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n\n private async loadRequest(\n db: DatabaseInterface,\n tenantId: string,\n requestId: string,\n ): Promise<ApprovalRequest | null> {\n const requests =\n db === this.db\n ? await ApprovalRequestCollection.create({ db })\n : await this.txCollection(ApprovalRequestCollection, db);\n const [request] = await requests.list({\n where: { tenantId, id: requestId },\n limit: 1,\n });\n // Belt and braces: never act on a row from another tenant.\n return request && request.tenantId === tenantId ? request : null;\n }\n\n private async loadPolicy(\n db: DatabaseInterface,\n tenantId: string,\n kind: string,\n ): Promise<ApprovalPolicy | null> {\n const policies =\n db === this.db\n ? await ApprovalPolicyCollection.create({ db })\n : await this.txCollection(ApprovalPolicyCollection, db);\n const [policy] = await policies.list({\n where: { tenantId, kind },\n limit: 1,\n });\n return policy ?? null;\n }\n\n /**\n * Every slug a decider must hold now: the slugs fixed at request time\n * plus the kind's and the tenant policy's current ones (tightening only:\n * a later policy can add a slug, never remove one).\n */\n private async requiredPermissionsFor(\n tx: DatabaseInterface,\n request: ApprovalRequest,\n ): Promise<string[]> {\n const kind = requireApprovalKind(request.kind);\n const current = effectiveRules(\n kind,\n await this.loadPolicy(tx, request.tenantId, kind.key),\n );\n const slugs = new Set(request.getRequiredPermissions());\n for (const slug of current.requiredPermissions) slugs.add(slug);\n return [...slugs];\n }\n\n private async appendEvent(\n tx: DatabaseInterface,\n input: {\n tenantId: string;\n requestId: string;\n type: ApprovalEventType;\n principal: ApprovalPrincipal;\n reason: string;\n subjectRevisionHash: string;\n sequence: number;\n voteKey?: string;\n selfApproved?: boolean;\n selfApprovalPermission?: string;\n now: Date;\n },\n ): Promise<void> {\n const events = await this.txCollection(ApprovalEventCollection, tx);\n await events.create({\n tenantId: input.tenantId,\n requestId: input.requestId,\n type: input.type,\n actorId: input.principal.id,\n actorType: input.principal.type,\n reason: input.reason,\n subjectRevisionHash: input.subjectRevisionHash,\n sequence: input.sequence,\n voteKey: input.voteKey ?? null,\n selfApproved: input.selfApproved ?? false,\n selfApprovalPermission: input.selfApprovalPermission ?? '',\n occurredAt: input.now,\n // The only place an event insert is authorized.\n ...serviceWriteOption(),\n } as Parameters<ApprovalEventCollection['create']>[0]);\n }\n\n /**\n * Defence in depth for `consume`: the request row says `approved`, so the\n * ledger must agree. It needs the `created` event at sequence 1, no\n * terminal event, and approvals from at least `requiredApprovals` distinct\n * human actors, with explicit audit markers for self-decisions. Catches a\n * status written around the service (raw SQL); model-layer inserts are\n * already capability-gated.\n */\n private async ledgerBacksApproval(\n tx: DatabaseInterface,\n request: ApprovalRequest,\n ): Promise<boolean> {\n const events = await this.txCollection(ApprovalEventCollection, tx);\n const ledger = await events.list({\n where: { tenantId: request.tenantId, requestId: request.id },\n limit: 1000,\n });\n const created = ledger.some(\n (event) => event.type === 'created' && Number(event.sequence) === 1,\n );\n const terminal = ledger.some((event) =>\n [\n 'rejected',\n 'changes_requested',\n 'cancelled',\n 'expired',\n 'consumed',\n ].includes(event.type),\n );\n const approvers = countedApprovers(\n ledger.filter((event) => event.type === 'approved'),\n request,\n );\n return (\n created &&\n !terminal &&\n approvers.size >= Math.max(1, Number(request.requiredApprovals))\n );\n }\n\n /**\n * The guarded UPDATE bypasses save hooks, so record the change-feed entry\n * the save path would have written. Best effort, like the save path.\n */\n private async recordChange(\n tx: DatabaseInterface,\n requestId: string,\n tenantId: string,\n ): Promise<void> {\n try {\n await appendChange(tx, {\n table: REQUESTS_TABLE,\n rowId: requestId,\n operation: 'update',\n tenantId,\n });\n } catch {\n // The transition committed its own write; a missing feed entry is\n // recovered by a full resync, exactly as for a failed save append.\n }\n }\n\n /** Re-read the request after commit (ids only cross the boundary). */\n private async toResult(\n tenantId: string,\n outcome: TxOutcome,\n db: DatabaseInterface = this.db,\n ): Promise<ApprovalResult> {\n if (outcome.kind === 'retry') {\n throw new Error('ApprovalService: unresolved retry outcome');\n }\n const id = outcome.id;\n const request = id ? await this.loadRequest(db, tenantId, id) : null;\n if (outcome.kind === 'refused') {\n return {\n outcome: 'refused',\n request: outcome.reason === 'not_found' ? null : request,\n refusal: { reason: outcome.reason, detail: outcome.detail },\n };\n }\n return { outcome: outcome.outcome, request };\n }\n}\n","/**\n * @happyvertical/smrt-approvals\n *\n * A small decision gate: a package defines an approval kind, a requester\n * opens a request bound to one subject revision, eligible humans decide,\n * and the consumer consumes the approval exactly once before acting.\n *\n * @example\n * ```typescript\n * import {\n * ApprovalService,\n * defineApprovalKind,\n * } from '@happyvertical/smrt-approvals';\n *\n * export const publishPost = defineApprovalKind({\n * key: 'social.post.publish',\n * subject: '@happyvertical/smrt-social:SocialPost',\n * permission: 'social.approve-post',\n * defaults: { requiredApprovals: 1 },\n * });\n *\n * const approvals = new ApprovalService({ db });\n * const { request } = await approvals.requestApproval(author, {\n * kind: publishPost,\n * subjectId: post.id,\n * subjectRevisionHash: hashOf(post),\n * });\n * await approvals.decide(editor, request.id, { decision: 'approve' });\n * const used = await approvals.consume(publisher, request.id, hashOf(post));\n * if (used.outcome === 'transitioned') await publish(post);\n * ```\n *\n * @packageDocumentation\n */\n\n// Self-register this package's manifest before any @smrt() decorator fires\n// downstream. Must come first. See __smrt-register__.ts (#1132).\nimport './__smrt-register__.js';\nimport { ensureApprovalPermissionsRegistered } from './permissions.js';\n\nexport { ApprovalEventCollection } from './collections/ApprovalEventCollection.js';\nexport { ApprovalPolicyCollection } from './collections/ApprovalPolicyCollection.js';\nexport { ApprovalRequestCollection } from './collections/ApprovalRequestCollection.js';\nexport {\n type ApprovalPolicyRules,\n assertPolicyTightens,\n DEFAULT_APPROVAL_TTL_MS,\n defineApprovalKind,\n effectiveRules,\n getApprovalKind,\n listApprovalKinds,\n MAX_APPROVAL_TTL_MS,\n MAX_REQUIRED_APPROVALS,\n MIN_APPROVAL_TTL_MS,\n requireApprovalKind,\n unregisterApprovalKind,\n} from './kinds.js';\nexport {\n ApprovalEvent,\n type ApprovalEventOptions,\n} from './models/ApprovalEvent.js';\nexport {\n ApprovalPolicy,\n type ApprovalPolicyOptions,\n} from './models/ApprovalPolicy.js';\nexport {\n ApprovalRequest,\n type ApprovalRequestOptions,\n} from './models/ApprovalRequest.js';\nexport {\n APPROVAL_PERMISSION_DEFINITIONS,\n CANCEL_ANY_APPROVAL_PERMISSION,\n ensureApprovalPermissionsRegistered,\n MANAGE_APPROVAL_POLICY_PERMISSION,\n registerApprovalPermissions,\n} from './permissions.js';\nexport {\n type ApprovalResult,\n ApprovalService,\n type ApprovalServiceOptions,\n type ConsumeOptions,\n type DecideInput,\n type RequestApprovalInput,\n} from './service.js';\nexport {\n APPROVAL_EVENT_TYPES,\n APPROVAL_PRINCIPAL_TYPES,\n APPROVAL_STATUSES,\n type ApprovalDecision,\n ApprovalError,\n type ApprovalErrorCode,\n type ApprovalEventType,\n type ApprovalKind,\n type ApprovalKindDefaults,\n type ApprovalKindInput,\n type ApprovalPrincipal,\n type ApprovalPrincipalType,\n type ApprovalRefusalReason,\n type ApprovalStatus,\n type ApprovalTransitionOutcome,\n type ApprovalTransitionResult,\n approvalPrincipalFromPermissions,\n type EffectiveApprovalRules,\n} from './types.js';\n\nensureApprovalPermissionsRegistered();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["policies"],"sources":["../src/__smrt-register__.ts","../src/permissions.ts","../src/write-capability.ts","../src/models/ApprovalRequest.ts","../src/models/ApprovalEvent.ts","../src/collections/ApprovalEventCollection.ts","../src/kinds.ts","../src/models/ApprovalPolicy.ts","../src/collections/ApprovalPolicyCollection.ts","../src/collections/ApprovalRequestCollection.ts","../src/service.ts","../src/index.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"packageVersion\\\":\\\"0.55.22\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-approvals:ApprovalEventCollection\\\":{\\\"name\\\":\\\"approvaleventcollection\\\",\\\"className\\\":\\\"ApprovalEventCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalEventCollection\\\",\\\"collection\\\":\\\"approvalevents\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalEventCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"tableName\\\":\\\"approval_events\\\"},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"ApprovalEvent\\\",\\\"exportName\\\":\\\"ApprovalEventCollection\\\",\\\"collectionExportName\\\":\\\"ApprovalEventCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"approval_events\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_events\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"request_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_type\\\\\\\" TEXT,\\\\n \\\\\\\"reason\\\\\\\" TEXT,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT,\\\\n \\\\\\\"sequence\\\\\\\" INTEGER,\\\\n \\\\\\\"vote_key\\\\\\\" TEXT,\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"self_approved\\\\\\\" BOOLEAN DEFAULT FALSE,\\\\n \\\\\\\"self_approval_permission\\\\\\\" TEXT DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"approval_requests\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sequence\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"vote_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"self_approved\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":false},\\\"self_approval_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_events_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_sequence_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"sequence\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_vote_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"vote_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_tenant_occurred_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"occurred_at\\\"]},{\\\"name\\\":\\\"approval_events_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"998756b0\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalPolicyCollection\\\":{\\\"name\\\":\\\"approvalpolicycollection\\\",\\\"className\\\":\\\"ApprovalPolicyCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalPolicyCollection\\\",\\\"collection\\\":\\\"approvalpolicies\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalPolicyCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"tableName\\\":\\\"approval_policies\\\"},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"ApprovalPolicy\\\",\\\"exportName\\\":\\\"ApprovalPolicyCollection\\\",\\\"collectionExportName\\\":\\\"ApprovalPolicyCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"approval_policies\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_policies\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"ttl_ms\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permission\\\\\\\" TEXT,\\\\n \\\\\\\"updated_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ttl_ms\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"updated_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_policies_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_kind_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"kind\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"80929cc8\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalRequestCollection\\\":{\\\"name\\\":\\\"approvalrequestcollection\\\",\\\"className\\\":\\\"ApprovalRequestCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalRequestCollection\\\",\\\"collection\\\":\\\"approvalrequests\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/collections/ApprovalRequestCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"tableName\\\":\\\"approval_requests\\\"},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"ApprovalRequest\\\",\\\"exportName\\\":\\\"ApprovalRequestCollection\\\",\\\"collectionExportName\\\":\\\"ApprovalRequestCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"approval_requests\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_requests\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"request_key\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by_type\\\\\\\" TEXT,\\\\n \\\\\\\"summary\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"approval_count\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permissions\\\\\\\" TEXT,\\\\n \\\\\\\"version\\\\\\\" INTEGER,\\\\n \\\\\\\"expires_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"decided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"summary\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"approval_count\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permissions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"version\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"expires_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"decided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_requests_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_tenant_request_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"request_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_status_expiry_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"status\\\",\\\"expires_at\\\"]},{\\\"name\\\":\\\"approval_requests_subject_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"subject_type\\\",\\\"subject_id\\\"]},{\\\"name\\\":\\\"approval_requests_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"a5800bdd\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalEvent\\\":{\\\"name\\\":\\\"approvalevent\\\",\\\"className\\\":\\\"ApprovalEvent\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalEvent\\\",\\\"collection\\\":\\\"approvalevents\\\",\\\"description\\\":\\\"One immutable entry in an approval request's history.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalEvent.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"requestId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"ApprovalRequest\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"constraint\\\":{\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]},\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\"}},\\\"type\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"actorId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"actorType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"enum\\\":[\\\"human\\\",\\\"agent\\\",\\\"service\\\"],\\\"readonly\\\":true},\\\"reason\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectRevisionHash\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"sequence\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"voteKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"occurredAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"selfApproved\\\":{\\\"type\\\":\\\"boolean\\\",\\\"required\\\":false,\\\"default\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true,\\\"default\\\":false},\\\"readonly\\\":true},\\\"selfApprovalPermission\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"readonly\\\":true,\\\"default\\\":\\\"\\\"},\\\"readonly\\\":true}},\\\"methods\\\":{\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"approval_events\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"approval_events_request_sequence_key\\\",\\\"columns\\\":[\\\"requestId\\\",\\\"sequence\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_vote_key\\\",\\\"columns\\\":[\\\"requestId\\\",\\\"voteKey\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_tenant_occurred_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"occurredAt\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"ApprovalEvent\\\",\\\"collectionExportName\\\":\\\"ApprovalEventCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"requestId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"type\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"actorId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"approval_events\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_events\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"request_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"actor_type\\\\\\\" TEXT,\\\\n \\\\\\\"reason\\\\\\\" TEXT,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT,\\\\n \\\\\\\"sequence\\\\\\\" INTEGER,\\\\n \\\\\\\"vote_key\\\\\\\" TEXT,\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"self_approved\\\\\\\" BOOLEAN DEFAULT FALSE,\\\\n \\\\\\\"self_approval_permission\\\\\\\" TEXT DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"approval_requests\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"actor_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sequence\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"vote_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"self_approved\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":false},\\\"self_approval_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_events_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_sequence_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"sequence\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_request_vote_key\\\",\\\"columns\\\":[\\\"request_id\\\",\\\"vote_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_events_tenant_occurred_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"occurred_at\\\"]},{\\\"name\\\":\\\"approval_events_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"998756b0\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalPolicy\\\":{\\\"name\\\":\\\"approvalpolicy\\\",\\\"className\\\":\\\"ApprovalPolicy\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalPolicy\\\",\\\"collection\\\":\\\"approvalpolicies\\\",\\\"description\\\":\\\"Tenant-level tightening of an approval kind. One row per tenant and kind.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalPolicy.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"requiredApprovals\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{}},\\\"ttlMs\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{}},\\\"requiredPermission\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{}},\\\"updatedBy\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{}}},\\\"methods\\\":{\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"approval_policies\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"approval_policies_tenant_kind_key\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"kind\\\"],\\\"unique\\\":true}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"ApprovalPolicy\\\",\\\"collectionExportName\\\":\\\"ApprovalPolicyCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"kind\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"approval_policies\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_policies\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"ttl_ms\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permission\\\\\\\" TEXT,\\\\n \\\\\\\"updated_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ttl_ms\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permission\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"updated_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_policies_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_kind_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"kind\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_policies_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"80929cc8\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"},\\\"@happyvertical/smrt-approvals:ApprovalRequest\\\":{\\\"name\\\":\\\"approvalrequest\\\",\\\"className\\\":\\\"ApprovalRequest\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-approvals:ApprovalRequest\\\",\\\"collection\\\":\\\"approvalrequests\\\",\\\"description\\\":\\\"A request for approval of one subject revision.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/approvals/src/models/ApprovalRequest.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-approvals\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"subjectRevisionHash\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestedBy\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestedByType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"enum\\\":[\\\"human\\\",\\\"agent\\\",\\\"service\\\"],\\\"readonly\\\":true},\\\"summary\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requiredApprovals\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"approvalCount\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requiredPermissions\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"version\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"expiresAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"decidedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"consumedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"consumedBy\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"readonly\\\":true},\\\"readonly\\\":true}},\\\"methods\\\":{\\\"getRequiredPermissions\\\":{\\\"name\\\":\\\"getRequiredPermissions\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"string[]\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"setRequiredPermissions\\\":{\\\"name\\\":\\\"setRequiredPermissions\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"slugs\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":false,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"expiresAtMs\\\":{\\\"name\\\":\\\"expiresAtMs\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"number\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isConsumed\\\":{\\\"name\\\":\\\"isConsumed\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"approval_requests\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"approval_requests_tenant_request_key\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"requestKey\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_status_expiry_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"status\\\",\\\"expiresAt\\\"]},{\\\"name\\\":\\\"approval_requests_subject_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"subjectType\\\",\\\"subjectId\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"ApprovalRequest\\\",\\\"collectionExportName\\\":\\\"ApprovalRequestCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"kind\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"subjectType\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"subjectId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"subjectRevisionHash\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"requestKey\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"requestedBy\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"approval_requests\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"approval_requests\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"subject_revision_hash\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"request_key\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"requested_by_type\\\\\\\" TEXT,\\\\n \\\\\\\"summary\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT,\\\\n \\\\\\\"required_approvals\\\\\\\" INTEGER,\\\\n \\\\\\\"approval_count\\\\\\\" INTEGER,\\\\n \\\\\\\"required_permissions\\\\\\\" TEXT,\\\\n \\\\\\\"version\\\\\\\" INTEGER,\\\\n \\\\\\\"expires_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"decided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"consumed_by\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"subject_revision_hash\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"request_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"requested_by_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"summary\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_approvals\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"approval_count\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"required_permissions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"version\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"expires_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"decided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"consumed_by\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"approval_requests_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_tenant_request_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"request_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"approval_requests_status_expiry_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"status\\\",\\\"expires_at\\\"]},{\\\"name\\\":\\\"approval_requests_subject_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"subject_type\\\",\\\"subject_id\\\"]},{\\\"name\\\":\\\"approval_requests_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"a5800bdd\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-approvals\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\",\\\"@happyvertical/smrt-users\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3617\\\",\\\"#3624\\\",\\\"#3626\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-profiles\\\",\\\"@happyvertical/smrt-tenancy\\\",\\\"@happyvertical/smrt-users\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/**\n * Permission slugs contributed by `@happyvertical/smrt-approvals` to the\n * runtime permission catalog. Deciding a request is gated by the per-kind\n * slug a package passes to `defineApprovalKind`; these slugs cover the\n * package-wide operations.\n *\n * @packageDocumentation\n */\n\nimport {\n type PermissionDefinition,\n registerPermissionDefinitions,\n} from '@happyvertical/smrt-users';\n\n/** Cancel a pending request someone else made. */\nexport const CANCEL_ANY_APPROVAL_PERMISSION = 'approvals.cancel-any';\n\n/** Write tenant approval policy rows (tighten-only). */\nexport const MANAGE_APPROVAL_POLICY_PERMISSION = 'approvals.manage-policy';\n\n/** Catalog definitions for the package-wide slugs. */\nexport const APPROVAL_PERMISSION_DEFINITIONS: PermissionDefinition[] = [\n {\n slug: CANCEL_ANY_APPROVAL_PERMISSION,\n category: 'approvals',\n name: 'Cancel Any Approval Request',\n description:\n 'Cancel a pending approval request made by someone else in the tenant',\n },\n {\n slug: MANAGE_APPROVAL_POLICY_PERMISSION,\n category: 'approvals',\n name: 'Manage Approval Policy',\n description:\n \"Tighten an approval kind's quorum, expiry, or required permission for the tenant\",\n },\n];\n\nlet registered = false;\n\n/** Register the package slugs (returns an unregister function for tests). */\nexport function registerApprovalPermissions(): () => void {\n return registerPermissionDefinitions(APPROVAL_PERMISSION_DEFINITIONS);\n}\n\n/** Register the package slugs once per process (package entry side effect). */\nexport function ensureApprovalPermissionsRegistered(): void {\n if (registered) return;\n registered = true;\n registerApprovalPermissions();\n}\n","/**\n * Service-only write capability for approval requests and events.\n *\n * `ApprovalRequest` and `ApprovalEvent` rows are inserted only by\n * `ApprovalService`. The service passes {@link SERVICE_WRITE} as a\n * constructor option; the models record the instance here and refuse any\n * insert that does not carry it. A symbol key can never arrive from JSON\n * (REST body, MCP tool arguments) and this module is not part of the\n * package's public exports, so `new ApprovalRequest({ status: 'approved' })`,\n * `ApprovalRequestCollection.create(...)`, or a forged `approved` event are\n * all refused at the model layer (the `runtime-report.ts` pattern in\n * smrt-reports). This is an in-process API guard, not a defence against raw\n * SQL; `consume()` additionally re-checks the ledger.\n *\n * @internal\n * @packageDocumentation\n */\n\n/** Constructor-option key carrying the capability. Never exported publicly. */\nexport const SERVICE_WRITE = Symbol('smrt-approvals.serviceWrite');\n\n/** The only value accepted under {@link SERVICE_WRITE}. */\nconst TOKEN = Object.freeze({ capability: 'smrt-approvals.serviceWrite' });\n\n/** Instances the service minted for exactly one insert. */\nconst minted = new WeakSet<object>();\n\n/** Constructor options fragment that grants the capability. */\nexport function serviceWriteOption(): { [SERVICE_WRITE]: object } {\n return { [SERVICE_WRITE]: TOKEN };\n}\n\n/** Record `instance` as service-minted when its options carry the token. */\nexport function adoptServiceWrite(instance: object, options: unknown): void {\n if (\n options &&\n typeof options === 'object' &&\n (options as Record<symbol, unknown>)[SERVICE_WRITE] === TOKEN\n ) {\n minted.add(instance);\n }\n}\n\n/** Whether `instance` was minted by the service for insertion. */\nexport function hasServiceWrite(instance: object): boolean {\n return minted.has(instance);\n}\n","/**\n * ApprovalRequest: one decision gate on one revision of one subject.\n *\n * The row is the authority for the decision; a consumer's own status column\n * is a projection it writes in the same transaction as `consume`. Every\n * lifecycle field is changed only by `ApprovalService` through one guarded\n * conditional UPDATE, so the generated surface is read-only and a plain\n * `save()` of a loaded request is refused.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n ApprovalError,\n type ApprovalPrincipalType,\n type ApprovalStatus,\n} from '../types.js';\nimport { adoptServiceWrite, hasServiceWrite } from '../write-capability.js';\n\n/** Constructor options for {@link ApprovalRequest}. */\nexport interface ApprovalRequestOptions extends SmrtObjectOptions {\n tenantId?: string;\n kind?: string;\n subjectType?: string;\n subjectId?: string;\n subjectRevisionHash?: string;\n requestKey?: string;\n requestedBy?: string;\n requestedByType?: ApprovalPrincipalType;\n summary?: string;\n status?: ApprovalStatus;\n requiredApprovals?: number;\n approvalCount?: number;\n requiredPermissions?: string;\n version?: number;\n expiresAt?: Date | null;\n decidedAt?: Date | null;\n consumedAt?: Date | null;\n consumedBy?: string;\n}\n\n/**\n * A request for approval of one subject revision.\n *\n * Status moves `pending` to `approved`, `rejected`, `changes_requested`,\n * `cancelled`, or `expired`; an approved request is consumed once\n * (`consumedAt` set, status stays `approved`) or expires unconsumed.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'approval_requests',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n indexes: [\n {\n name: 'approval_requests_tenant_request_key',\n columns: ['tenantId', 'requestKey'],\n unique: true,\n },\n {\n name: 'approval_requests_status_expiry_idx',\n columns: ['tenantId', 'status', 'expiresAt'],\n },\n {\n name: 'approval_requests_subject_idx',\n columns: ['tenantId', 'subjectType', 'subjectId'],\n },\n ],\n})\nexport class ApprovalRequest extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n /** Owning tenant. Every read and transition is pinned to it. */\n @tenantId()\n tenantId: string = '';\n\n /** Approval kind key, e.g. `social.post.publish`. */\n @field({ type: 'text', required: true, readonly: true })\n kind: string = '';\n\n /** Qualified subject class, e.g. `@happyvertical/smrt-social:SocialPost`. */\n @field({ type: 'text', required: true, readonly: true })\n subjectType: string = '';\n\n /** Subject id. Bare string: the subject table is polymorphic. */\n @field({ type: 'text', required: true, readonly: true })\n subjectId: string = '';\n\n /**\n * Hash of the exact subject revision being approved. `consume` must\n * present the same hash, so an approval never transfers to changed content.\n */\n @field({ type: 'text', required: true, readonly: true })\n subjectRevisionHash: string = '';\n\n /** Idempotency key, unique per tenant. A replay returns the same request. */\n @field({ type: 'text', required: true, readonly: true })\n requestKey: string = '';\n\n /** Principal id of the requester. The requester can never decide. */\n @field({ type: 'text', required: true, readonly: true })\n requestedBy: string = '';\n\n /** Principal type of the requester (`human`, `agent`, or `service`). */\n @field({ type: 'text', readonly: true })\n requestedByType: ApprovalPrincipalType = 'human';\n\n /** Short human-readable description shown to deciders. */\n @field({ type: 'text', readonly: true })\n summary: string = '';\n\n /** Lifecycle status. Changed only by guarded transitions. */\n @field({ type: 'text', readonly: true })\n status: ApprovalStatus = 'pending';\n\n /** Distinct approvers needed, fixed when the request is made. */\n @field({ type: 'integer', readonly: true })\n requiredApprovals: number = 1;\n\n /** Distinct approvals recorded so far. */\n @field({ type: 'integer', readonly: true })\n approvalCount: number = 0;\n\n /**\n * JSON array of permission slugs a decider must hold, fixed at request\n * time. Read it through {@link getRequiredPermissions}.\n */\n @field({ type: 'text', readonly: true })\n requiredPermissions: string = '[]';\n\n /** Transition counter; every guarded UPDATE requires and bumps it. */\n @field({ type: 'integer', readonly: true })\n version: number = 0;\n\n /** After this instant the request can no longer be decided or consumed. */\n @field({ type: 'datetime', readonly: true })\n expiresAt: Date | null = null;\n\n /** When the request reached a terminal decision. */\n @field({ type: 'datetime', readonly: true })\n decidedAt: Date | null = null;\n\n /** When the approval was consumed (single use). */\n @field({ type: 'datetime', readonly: true })\n consumedAt: Date | null = null;\n\n /** Principal id that consumed the approval. */\n @field({ type: 'text', readonly: true })\n consumedBy: string = '';\n\n constructor(options: ApprovalRequestOptions = {}) {\n super(options);\n adoptServiceWrite(this, options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.subjectType !== undefined)\n this.subjectType = options.subjectType;\n if (options.subjectId !== undefined) this.subjectId = options.subjectId;\n if (options.subjectRevisionHash !== undefined)\n this.subjectRevisionHash = options.subjectRevisionHash;\n if (options.requestKey !== undefined) this.requestKey = options.requestKey;\n if (options.requestedBy !== undefined)\n this.requestedBy = options.requestedBy;\n if (options.requestedByType !== undefined)\n this.requestedByType = options.requestedByType;\n if (options.summary !== undefined) this.summary = options.summary;\n if (options.status !== undefined) this.status = options.status;\n if (options.requiredApprovals !== undefined)\n this.requiredApprovals = options.requiredApprovals;\n if (options.approvalCount !== undefined)\n this.approvalCount = options.approvalCount;\n if (options.requiredPermissions !== undefined)\n this.requiredPermissions = options.requiredPermissions;\n if (options.version !== undefined) this.version = options.version;\n if (options.expiresAt !== undefined) this.expiresAt = options.expiresAt;\n if (options.decidedAt !== undefined) this.decidedAt = options.decidedAt;\n if (options.consumedAt !== undefined) this.consumedAt = options.consumedAt;\n if (options.consumedBy !== undefined) this.consumedBy = options.consumedBy;\n }\n\n /** The permission slugs a decider must hold (never throws; bad JSON = none valid). */\n getRequiredPermissions(): string[] {\n try {\n const parsed: unknown = JSON.parse(this.requiredPermissions || '[]');\n return Array.isArray(parsed)\n ? parsed.filter((slug): slug is string => typeof slug === 'string')\n : [];\n } catch {\n return [];\n }\n }\n\n /** Store the permission slugs a decider must hold. */\n setRequiredPermissions(slugs: readonly string[]): void {\n this.requiredPermissions = JSON.stringify([...slugs]);\n }\n\n /** The expiry as epoch milliseconds (`NaN` when unset or unparseable). */\n expiresAtMs(): number {\n const value = this.expiresAt as unknown;\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'string' || typeof value === 'number') {\n return new Date(value).getTime();\n }\n return Number.NaN;\n }\n\n /** True when the approval was consumed. */\n isConsumed(): boolean {\n return this.consumedAt !== null && this.consumedAt !== undefined;\n }\n\n /**\n * Refuse any insert `ApprovalService` did not mint (see\n * `write-capability.ts`), and any minted insert that does not start in the\n * initial state. Runs for ordinary saves and bulk creates alike (core\n * wraps an error thrown here; `save()` checks first so callers see it).\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN`.\n */\n protected override async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n this.assertInsertAllowed();\n }\n\n private assertInsertAllowed(): void {\n if (this.isPersisted) return;\n if (!hasServiceWrite(this)) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n 'ApprovalRequest rows are created only by ApprovalService.requestApproval().',\n );\n }\n if (\n this.status !== 'pending' ||\n Number(this.approvalCount) !== 0 ||\n Number(this.version) !== 1 ||\n this.decidedAt ||\n this.consumedAt ||\n this.consumedBy\n ) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n 'A new ApprovalRequest must start pending, undecided, and unconsumed.',\n );\n }\n }\n\n /**\n * Insert a new request. A loaded request is never re-saved: every later\n * change is a guarded transition in `ApprovalService`.\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN` for a persisted request.\n */\n override async save(): Promise<this> {\n if (this.isPersisted) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalRequest ${this.id} is changed only through ApprovalService transitions.`,\n );\n }\n this.assertInsertAllowed();\n this.requireInsertOnSave();\n return await super.save();\n }\n\n /**\n * Requests are durable records of a decision.\n *\n * @throws {ApprovalError} always.\n */\n override async delete(): Promise<void> {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalRequest ${this.id} cannot be deleted.`,\n );\n }\n}\n","/**\n * ApprovalEvent: the append-only ledger of an approval request.\n *\n * Events are the source of truth for who did what: every transition inserts\n * exactly one event in the same transaction as its guarded UPDATE. The\n * generated surface is read-only, `save()` only ever inserts, and `delete()`\n * is refused. `(requestId, sequence)` is unique (one event per request\n * version) and `(requestId, voteKey)` is unique (one decision per actor).\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n ApprovalError,\n type ApprovalEventType,\n type ApprovalPrincipalType,\n} from '../types.js';\nimport { adoptServiceWrite, hasServiceWrite } from '../write-capability.js';\nimport { ApprovalRequest } from './ApprovalRequest.js';\n\n/** Constructor options for {@link ApprovalEvent}. */\nexport interface ApprovalEventOptions extends SmrtObjectOptions {\n tenantId?: string;\n requestId?: string;\n type?: ApprovalEventType;\n actorId?: string;\n actorType?: ApprovalPrincipalType;\n reason?: string;\n selfApproved?: boolean;\n selfApprovalPermission?: string;\n subjectRevisionHash?: string;\n sequence?: number;\n voteKey?: string | null;\n occurredAt?: Date | null;\n}\n\n/** One immutable entry in an approval request's history. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'approval_events',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n indexes: [\n {\n name: 'approval_events_request_sequence_key',\n columns: ['requestId', 'sequence'],\n unique: true,\n },\n {\n name: 'approval_events_request_vote_key',\n columns: ['requestId', 'voteKey'],\n unique: true,\n },\n {\n name: 'approval_events_tenant_occurred_idx',\n columns: ['tenantId', 'occurredAt'],\n },\n ],\n})\nexport class ApprovalEvent extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n /** Owning tenant; always the request's tenant. */\n @tenantId()\n tenantId: string = '';\n\n /**\n * The request this event belongs to. DuckDB executes an UPDATE of an\n * indexed column on a referenced row as delete plus insert, so a physical\n * FK there would refuse every transition of a request that has events;\n * the constraint is physical on PostgreSQL and SQLite only. Requests are\n * never deleted, so no engine can orphan an event.\n */\n @foreignKey(ApprovalRequest, {\n required: true,\n readonly: true,\n onDelete: 'RESTRICT',\n onUpdate: 'RESTRICT',\n constraint: { engines: ['postgres', 'sqlite'] },\n })\n requestId: string = '';\n\n /** What happened. */\n @field({ type: 'text', required: true, readonly: true })\n type: ApprovalEventType = 'created';\n\n /** Principal id of the actor. */\n @field({ type: 'text', required: true, readonly: true })\n actorId: string = '';\n\n /** Principal type of the actor. */\n @field({ type: 'text', readonly: true })\n actorType: ApprovalPrincipalType = 'human';\n\n /** Free-text reason (rejection note, cancellation reason, and so on). */\n @field({ type: 'text', readonly: true })\n reason: string = '';\n\n /** The subject revision the request was bound to when this happened. */\n @field({ type: 'text', readonly: true })\n subjectRevisionHash: string = '';\n\n /** The request `version` this event produced; unique per request. */\n @field({ type: 'integer', readonly: true })\n sequence: number = 0;\n\n /**\n * The deciding actor's id on decision events, `null` otherwise; unique per\n * request so one actor decides at most once.\n */\n @field({ type: 'text', nullable: true, readonly: true })\n voteKey: string | null = null;\n\n /** When the event happened. */\n @field({ type: 'datetime', readonly: true })\n occurredAt: Date | null = null;\n\n /** Whether the requester used the explicit self-decision allowance. */\n @field({ type: 'boolean', readonly: true, default: false })\n selfApproved: boolean = false;\n\n /** Permission checked when this self-decision was recorded. Empty otherwise. */\n @field({ type: 'text', readonly: true, default: '' })\n selfApprovalPermission: string = '';\n\n constructor(options: ApprovalEventOptions = {}) {\n super(options);\n adoptServiceWrite(this, options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.requestId !== undefined) this.requestId = options.requestId;\n if (options.type !== undefined) this.type = options.type;\n if (options.actorId !== undefined) this.actorId = options.actorId;\n if (options.actorType !== undefined) this.actorType = options.actorType;\n if (options.reason !== undefined) this.reason = options.reason;\n if (options.selfApproved !== undefined)\n this.selfApproved = options.selfApproved;\n if (options.selfApprovalPermission !== undefined)\n this.selfApprovalPermission = options.selfApprovalPermission;\n if (options.subjectRevisionHash !== undefined)\n this.subjectRevisionHash = options.subjectRevisionHash;\n if (options.sequence !== undefined) this.sequence = options.sequence;\n if (options.voteKey !== undefined) this.voteKey = options.voteKey;\n if (options.occurredAt !== undefined) this.occurredAt = options.occurredAt;\n }\n\n /**\n * Append the event. An event is written once and never updated.\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN` for a persisted event.\n */\n override async save(): Promise<this> {\n if (this.isPersisted) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalEvent ${this.id} is append-only and cannot be updated.`,\n );\n }\n this.assertInsertAllowed();\n if (!this.occurredAt) this.occurredAt = new Date();\n this.requireInsertOnSave();\n return await super.save();\n }\n\n /**\n * Refuse any insert `ApprovalService` did not mint in the same transaction\n * as its guarded UPDATE (see `write-capability.ts`): a forged `approved`\n * event would otherwise count toward quorum. Runs for ordinary saves and\n * bulk creates alike.\n *\n * @throws {ApprovalError} `APPROVAL_FORBIDDEN`.\n */\n protected override async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n this.assertInsertAllowed();\n }\n\n private assertInsertAllowed(): void {\n if (this.isPersisted || hasServiceWrite(this)) return;\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n 'ApprovalEvent rows are appended only by ApprovalService transitions.',\n );\n }\n\n /**\n * Events are append-only.\n *\n * @throws {ApprovalError} always.\n */\n override async delete(): Promise<void> {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `ApprovalEvent ${this.id} is append-only and cannot be deleted.`,\n );\n }\n}\n","/**\n * Collection for {@link ApprovalEvent}. Reads only: every write goes\n * through `ApprovalService`.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection, smrt } from '@happyvertical/smrt-core';\nimport { ApprovalEvent } from '../models/ApprovalEvent.js';\n\n/** Tenant-scoped reads of {@link ApprovalEvent} rows. */\n// Core applies a collection's `@smrt()` config to its item class as well,\n// and an undecorated collection keeps its own registry entry with the\n// full-CRUD default. Repeat the model's read-only surface exactly.\n@smrt({\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class ApprovalEventCollection extends SmrtCollection<ApprovalEvent> { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n static readonly _itemClass = ApprovalEvent;\n}\n","/**\n * The approval-kind registry and tighten-only policy arithmetic.\n *\n * A package opts in with {@link defineApprovalKind}: the kind's defaults are\n * the loosest rules any tenant can run. A tenant {@link ApprovalPolicy} row\n * may raise the quorum, shorten the expiry, or add a required permission,\n * never the reverse; {@link assertPolicyTightens} refuses a loosening write\n * and {@link effectiveRules} clamps any stored row to the defaults, so a row\n * written around the service still cannot loosen a kind.\n *\n * @packageDocumentation\n */\n\nimport {\n ApprovalError,\n type ApprovalKind,\n type ApprovalKindInput,\n type EffectiveApprovalRules,\n} from './types.js';\n\n/** Upper bound on quorum: a gate, not a ballot. */\nexport const MAX_REQUIRED_APPROVALS = 25;\n\n/** Default lifetime of a request: seven days. */\nexport const DEFAULT_APPROVAL_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** Longest lifetime a kind may declare: one year. */\nexport const MAX_APPROVAL_TTL_MS = 366 * 24 * 60 * 60 * 1000;\n\n/** Shortest lifetime anything may set: one minute. */\nexport const MIN_APPROVAL_TTL_MS = 60 * 1000;\n\nconst KIND_KEY = /^[a-z][a-z0-9-]*(?:\\.[a-z][a-z0-9_-]*)+$/;\nconst QUALIFIED_CLASS =\n /^@[a-z0-9][a-z0-9._-]*\\/[a-z0-9][a-z0-9._-]*:[A-Za-z_$][\\w$]*$/;\nconst PERMISSION_SLUG = /^[a-z][a-z0-9_-]*(?:\\.[a-z0-9][a-z0-9_-]*)+$/;\n\nconst kinds = new Map<string, ApprovalKind>();\n\n/** True for a well-formed permission slug such as `social.approve-post`. */\nexport function isPermissionSlug(value: unknown): value is string {\n return typeof value === 'string' && PERMISSION_SLUG.test(value);\n}\n\nfunction assertQuorum(value: number, label: string): void {\n if (\n !Number.isSafeInteger(value) ||\n value < 1 ||\n value > MAX_REQUIRED_APPROVALS\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be an integer from 1 to ${MAX_REQUIRED_APPROVALS}, got ${String(value)}.`,\n );\n }\n}\n\nfunction assertTtl(value: number, label: string): void {\n if (\n !Number.isSafeInteger(value) ||\n value < MIN_APPROVAL_TTL_MS ||\n value > MAX_APPROVAL_TTL_MS\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be an integer number of milliseconds from ${MIN_APPROVAL_TTL_MS} to ${MAX_APPROVAL_TTL_MS}, got ${String(value)}.`,\n );\n }\n}\n\n/**\n * Register an approval kind. Calling it again with an identical definition\n * returns the registered kind (module re-evaluation is harmless); a\n * different definition under the same key throws.\n *\n * @throws {ApprovalError} `APPROVAL_INVALID` or `APPROVAL_KIND_CONFLICT`.\n */\nexport function defineApprovalKind(input: ApprovalKindInput): ApprovalKind {\n if (!KIND_KEY.test(input.key ?? '')) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval kind key must be dotted lower case such as 'social.post.publish', got '${String(input.key)}'.`,\n );\n }\n if (!QUALIFIED_CLASS.test(input.subject ?? '')) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval kind '${input.key}' subject must be a qualified class name such as '@happyvertical/smrt-social:SocialPost', got '${String(input.subject)}'.`,\n );\n }\n if (!isPermissionSlug(input.permission)) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval kind '${input.key}' permission must be a slug such as 'social.approve-post', got '${String(input.permission)}'.`,\n );\n }\n if (\n input.selfApprovalPermission !== undefined &&\n !isPermissionSlug(input.selfApprovalPermission)\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'selfApprovalPermission must be a permission slug.',\n );\n }\n const requiredApprovals = input.defaults?.requiredApprovals ?? 1;\n const ttlMs = input.defaults?.ttlMs ?? DEFAULT_APPROVAL_TTL_MS;\n assertQuorum(\n requiredApprovals,\n `Approval kind '${input.key}' requiredApprovals`,\n );\n assertTtl(ttlMs, `Approval kind '${input.key}' ttlMs`);\n\n const kind: ApprovalKind = Object.freeze({\n key: input.key,\n subject: input.subject,\n permission: input.permission,\n selfApprovalPermission: input.selfApprovalPermission,\n defaults: Object.freeze({ requiredApprovals, ttlMs }),\n });\n const existing = kinds.get(kind.key);\n if (existing) {\n if (\n existing.subject === kind.subject &&\n existing.permission === kind.permission &&\n existing.selfApprovalPermission === kind.selfApprovalPermission &&\n existing.defaults.requiredApprovals === requiredApprovals &&\n existing.defaults.ttlMs === ttlMs\n ) {\n return existing;\n }\n throw new ApprovalError(\n 'APPROVAL_KIND_CONFLICT',\n `Approval kind '${kind.key}' is already defined with different rules.`,\n );\n }\n kinds.set(kind.key, kind);\n return kind;\n}\n\n/** The registered kind for `key`, or `undefined`. */\nexport function getApprovalKind(key: string): ApprovalKind | undefined {\n return kinds.get(key);\n}\n\n/** Every registered kind, sorted by key. */\nexport function listApprovalKinds(): ApprovalKind[] {\n return [...kinds.values()].sort((a, b) => a.key.localeCompare(b.key));\n}\n\n/** The registered kind for `key`; throws when it is unknown. */\nexport function requireApprovalKind(key: string): ApprovalKind {\n const kind = kinds.get(key);\n if (!kind) {\n throw new ApprovalError(\n 'APPROVAL_KIND_UNKNOWN',\n `Approval kind '${key}' is not defined in this process. Import the package that calls defineApprovalKind() for it.`,\n );\n }\n return kind;\n}\n\n/** Remove a kind (test helper). */\nexport function unregisterApprovalKind(key: string): boolean {\n return kinds.delete(key);\n}\n\n/** The tightening a tenant policy row may carry. `0`/`''` mean \"inherit\". */\nexport interface ApprovalPolicyRules {\n requiredApprovals?: number;\n ttlMs?: number;\n requiredPermission?: string;\n}\n\n/**\n * Refuse a policy that would loosen `kind`: a quorum below the default, an\n * expiry above the default, or a malformed permission slug.\n *\n * @throws {ApprovalError} `APPROVAL_POLICY_LOOSENS` or `APPROVAL_INVALID`.\n */\nexport function assertPolicyTightens(\n kind: ApprovalKind,\n rules: ApprovalPolicyRules,\n): void {\n const quorum = rules.requiredApprovals ?? 0;\n if (quorum !== 0) {\n assertQuorum(quorum, `Approval policy for '${kind.key}' requiredApprovals`);\n if (quorum < kind.defaults.requiredApprovals) {\n throw new ApprovalError(\n 'APPROVAL_POLICY_LOOSENS',\n `Approval policy for '${kind.key}' may only raise requiredApprovals (default ${kind.defaults.requiredApprovals}), got ${quorum}.`,\n );\n }\n }\n const ttl = rules.ttlMs ?? 0;\n if (ttl !== 0) {\n assertTtl(ttl, `Approval policy for '${kind.key}' ttlMs`);\n if (ttl > kind.defaults.ttlMs) {\n throw new ApprovalError(\n 'APPROVAL_POLICY_LOOSENS',\n `Approval policy for '${kind.key}' may only shorten ttlMs (default ${kind.defaults.ttlMs}), got ${ttl}.`,\n );\n }\n }\n const permission = rules.requiredPermission ?? '';\n if (permission !== '' && !isPermissionSlug(permission)) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval policy for '${kind.key}' requiredPermission must be a permission slug, got '${permission}'.`,\n );\n }\n}\n\n/**\n * The rules a request runs under: the kind's defaults tightened by `policy`.\n * Clamps rather than trusts the row, so a stored row that would loosen the\n * kind (written around the service, or left over after a package raised its\n * defaults) is ignored for the loosening part; a malformed permission slug\n * fails closed by staying in the required set (no principal holds it).\n */\nexport function effectiveRules(\n kind: ApprovalKind,\n policy?: ApprovalPolicyRules | null,\n): EffectiveApprovalRules {\n const policyQuorum = Number(policy?.requiredApprovals ?? 0);\n const policyTtl = Number(policy?.ttlMs ?? 0);\n const requiredApprovals =\n Number.isSafeInteger(policyQuorum) && policyQuorum > 0\n ? Math.min(\n Math.max(kind.defaults.requiredApprovals, policyQuorum),\n MAX_REQUIRED_APPROVALS,\n )\n : kind.defaults.requiredApprovals;\n const ttlMs =\n Number.isSafeInteger(policyTtl) && policyTtl > 0\n ? Math.max(Math.min(kind.defaults.ttlMs, policyTtl), MIN_APPROVAL_TTL_MS)\n : kind.defaults.ttlMs;\n const requiredPermissions = [kind.permission];\n const extra = String(policy?.requiredPermission ?? '').trim();\n if (extra && !requiredPermissions.includes(extra)) {\n requiredPermissions.push(extra);\n }\n return { requiredApprovals, ttlMs, requiredPermissions };\n}\n","/**\n * ApprovalPolicy: a tenant's tightening of one approval kind.\n *\n * A row may raise the quorum, shorten the expiry, or add one required\n * permission; it can never loosen the kind's package defaults. Writes go\n * through `ApprovalService.setPolicy`, which refuses loosening, and\n * `effectiveRules` clamps any stored row when a request is made. A policy\n * applies to requests made after it is written; existing requests keep the\n * rules fixed at request time.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { assertPolicyTightens, requireApprovalKind } from '../kinds.js';\n\n/** Constructor options for {@link ApprovalPolicy}. */\nexport interface ApprovalPolicyOptions extends SmrtObjectOptions {\n tenantId?: string;\n kind?: string;\n requiredApprovals?: number;\n ttlMs?: number;\n requiredPermission?: string;\n updatedBy?: string;\n}\n\n/** Tenant-level tightening of an approval kind. One row per tenant and kind. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'approval_policies',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n indexes: [\n {\n name: 'approval_policies_tenant_kind_key',\n columns: ['tenantId', 'kind'],\n unique: true,\n },\n ],\n})\nexport class ApprovalPolicy extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n /** Owning tenant. */\n @tenantId()\n tenantId: string = '';\n\n /** Approval kind key this row tightens. */\n @field({ type: 'text', required: true })\n kind: string = '';\n\n /** Raised quorum; `0` inherits the kind default. */\n @field({ type: 'integer' })\n requiredApprovals: number = 0;\n\n /** Shortened lifetime in milliseconds; `0` inherits the kind default. */\n @field({ type: 'integer' })\n ttlMs: number = 0;\n\n /** Extra permission slug a decider must hold; empty for none. */\n @field({ type: 'text' })\n requiredPermission: string = '';\n\n /** Principal id that last wrote the row. */\n @field({ type: 'text' })\n updatedBy: string = '';\n\n constructor(options: ApprovalPolicyOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.requiredApprovals !== undefined)\n this.requiredApprovals = options.requiredApprovals;\n if (options.ttlMs !== undefined) this.ttlMs = options.ttlMs;\n if (options.requiredPermission !== undefined)\n this.requiredPermission = options.requiredPermission;\n if (options.updatedBy !== undefined) this.updatedBy = options.updatedBy;\n }\n\n /**\n * Validate against the registered kind, then persist. A row for an unknown\n * kind, or one that would loosen the kind, is refused.\n *\n * @throws {ApprovalError} `APPROVAL_KIND_UNKNOWN`,\n * `APPROVAL_POLICY_LOOSENS`, or `APPROVAL_INVALID`.\n */\n override async save(): Promise<this> {\n this.requiredPermission = String(this.requiredPermission ?? '').trim();\n this.requiredApprovals = Number(this.requiredApprovals ?? 0);\n this.ttlMs = Number(this.ttlMs ?? 0);\n assertPolicyTightens(requireApprovalKind(this.kind), {\n requiredApprovals: this.requiredApprovals,\n ttlMs: this.ttlMs,\n requiredPermission: this.requiredPermission,\n });\n return await super.save();\n }\n}\n","/**\n * Collection for {@link ApprovalPolicy}. Reads only: every write goes\n * through `ApprovalService`.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection, smrt } from '@happyvertical/smrt-core';\nimport { ApprovalPolicy } from '../models/ApprovalPolicy.js';\n\n/** Tenant-scoped reads of {@link ApprovalPolicy} rows. */\n// Core applies a collection's `@smrt()` config to its item class as well,\n// and an undecorated collection keeps its own registry entry with the\n// full-CRUD default. Repeat the model's read-only surface exactly.\n@smrt({\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class ApprovalPolicyCollection extends SmrtCollection<ApprovalPolicy> { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n static readonly _itemClass = ApprovalPolicy;\n}\n","/**\n * Collection for {@link ApprovalRequest}. Reads only: every write goes\n * through `ApprovalService`.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection, smrt } from '@happyvertical/smrt-core';\nimport { ApprovalRequest } from '../models/ApprovalRequest.js';\n\n/** Tenant-scoped reads of {@link ApprovalRequest} rows. */\n// Core applies a collection's `@smrt()` config to its item class as well,\n// and an undecorated collection keeps its own registry entry with the\n// full-CRUD default. Repeat the model's read-only surface exactly.\n@smrt({\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class ApprovalRequestCollection extends SmrtCollection<ApprovalRequest> { static __smrtPackage__ = \"@happyvertical/smrt-approvals\";\n static readonly _itemClass = ApprovalRequest;\n}\n","/**\n * ApprovalService: the only write path for approval requests.\n *\n * Every transition is ONE guarded conditional `UPDATE ... WHERE id AND\n * tenant_id AND status AND version AND expiry ... RETURNING version` plus\n * one {@link ApprovalEvent} insert, in the same database transaction (the\n * `CliAuthRequestCollection.approvePendingRequest` and\n * `CommissionPayoutService.transitionPayoutForSource` shape):\n *\n * - The guarded UPDATE is the arbiter. Two concurrent transitions of one\n * request both read version `v`; only one UPDATE can match `version = v`.\n * The loser matches zero rows, writes nothing, and retries from a fresh\n * read, where it sees the winner's state and is refused cleanly\n * (`not_pending`, `already_decided`, `already_consumed`).\n * - PostgreSQL runs each transaction on its own pooled connection; the\n * UPDATE's row lock serializes writers and READ COMMITTED re-evaluates the\n * predicate after the winner commits. On embedded engines (SQLite,\n * DuckDB) each transaction runs through core's embedded write queue\n * (`withEmbeddedWriteTransaction`), which takes the queue before the\n * connection lock and serializes writers per database; the predicate\n * still decides.\n * - Every statement names the tenant explicitly and the work runs inside\n * `withTenant(principal.tenantId)`, so tenancy interceptors and the raw\n * predicate both pin the row; a cross-tenant id is `not_found`.\n * - Events are inserted through a collection bound to the transaction\n * database (the tx-bound collection pattern), so a failed insert rolls\n * the UPDATE back.\n *\n * @packageDocumentation\n */\n\nimport {\n appendChange,\n isEmbeddedDatabase,\n isUniqueViolationError,\n withEmbeddedWriteQueue,\n withEmbeddedWriteTransaction,\n} from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n isSystemContext,\n withTenant,\n} from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { ApprovalEventCollection } from './collections/ApprovalEventCollection.js';\nimport { ApprovalPolicyCollection } from './collections/ApprovalPolicyCollection.js';\nimport { ApprovalRequestCollection } from './collections/ApprovalRequestCollection.js';\nimport {\n type ApprovalPolicyRules,\n assertPolicyTightens,\n effectiveRules,\n isPermissionSlug,\n requireApprovalKind,\n} from './kinds.js';\nimport type { ApprovalEvent } from './models/ApprovalEvent.js';\nimport type { ApprovalPolicy } from './models/ApprovalPolicy.js';\nimport type { ApprovalRequest } from './models/ApprovalRequest.js';\nimport {\n CANCEL_ANY_APPROVAL_PERMISSION,\n MANAGE_APPROVAL_POLICY_PERMISSION,\n} from './permissions.js';\nimport {\n APPROVAL_PRINCIPAL_TYPES,\n type ApprovalDecision,\n ApprovalError,\n type ApprovalEventType,\n type ApprovalKind,\n type ApprovalPrincipal,\n type ApprovalRefusalReason,\n type ApprovalStatus,\n type ApprovalTransitionResult,\n} from './types.js';\nimport { serviceWriteOption } from './write-capability.js';\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Longest accepted id, key, or hash string. */\nconst MAX_TOKEN_LENGTH = 256;\n\n/** Longest accepted reason or summary. */\nconst MAX_TEXT_LENGTH = 4000;\n\n/** Attempts before a transition gives up as `contention`. */\nconst DEFAULT_MAX_ATTEMPTS = 8;\n\nconst REQUESTS_TABLE = 'approval_requests';\n\n/** Adapter capabilities the service relies on. */\ntype TransactionCapableDatabase = DatabaseInterface & {\n transaction?: <T>(\n callback: (tx: DatabaseInterface) => Promise<T>,\n ) => Promise<T>;\n};\n\n/** What a transaction body reports across the commit boundary (ids only). */\ntype TxOutcome =\n | { kind: 'done'; outcome: 'transitioned' | 'already_applied'; id: string }\n | {\n kind: 'refused';\n reason: ApprovalRefusalReason;\n detail: string;\n id: string | null;\n }\n | { kind: 'retry' };\n\n/** Options for {@link ApprovalService}. */\nexport interface ApprovalServiceOptions {\n /** The database every transition runs against. Must support transactions. */\n db: DatabaseInterface;\n /** Clock override for deterministic tests. */\n now?: () => Date;\n /** Attempts before a contended transition is refused. Default 8. */\n maxAttempts?: number;\n}\n\n/** Input for {@link ApprovalService.requestApproval}. */\nexport interface RequestApprovalInput {\n /** A kind registered with `defineApprovalKind` (or its key). */\n kind: ApprovalKind | string;\n /** The subject's id. */\n subjectId: string;\n /** Hash of the exact subject revision to approve. */\n subjectRevisionHash: string;\n /**\n * Idempotency key, unique per tenant. A replay with the same subject and\n * revision returns the existing request as `already_applied`; a replay with\n * different content is refused `request_key_conflict`. Default: random.\n */\n requestKey?: string;\n /** Short description shown to deciders. */\n summary?: string;\n}\n\n/** Input for {@link ApprovalService.decide}. */\nexport interface DecideInput {\n decision: ApprovalDecision;\n /** Required for `reject` and `request_changes`. */\n reason?: string;\n}\n\n/** Options for {@link ApprovalService.consume}. */\nexport interface ConsumeOptions {\n /**\n * Run inside the caller's open transaction (a `db.transaction()` callback\n * handle) so the consumer's own write commits or rolls back together with\n * the consumption. The caller owns the transaction. On embedded engines\n * (SQLite, DuckDB, libsql) the handle must come from\n * `withEmbeddedWriteTransaction(db, isEmbeddedDatabase(db), fn)` or\n * `SmrtObject.withTransaction()` so it holds core's embedded write queue;\n * a raw `db.transaction()` handle can deadlock against concurrent saves.\n */\n transaction?: DatabaseInterface;\n}\n\n/** Result type of every transition. */\nexport type ApprovalResult = ApprovalTransitionResult<ApprovalRequest>;\n\nconst DECISION_EVENT: Record<ApprovalDecision, ApprovalEventType> = {\n approve: 'approved',\n reject: 'rejected',\n request_changes: 'changes_requested',\n};\n\nfunction refusal(\n reason: ApprovalRefusalReason,\n detail: string,\n id: string | null = null,\n): TxOutcome {\n return { kind: 'refused', reason, detail, id };\n}\n\nfunction isoNow(date: Date): string {\n return date.toISOString();\n}\n\nfunction assertToken(value: unknown, label: string): string {\n const text = typeof value === 'string' ? value.trim() : '';\n if (!text || text.length > MAX_TOKEN_LENGTH) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be a non-empty string of at most ${MAX_TOKEN_LENGTH} characters.`,\n );\n }\n return text;\n}\n\nfunction assertText(value: unknown, label: string): string {\n if (value === undefined || value === null) return '';\n if (typeof value !== 'string' || value.length > MAX_TEXT_LENGTH) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `${label} must be a string of at most ${MAX_TEXT_LENGTH} characters.`,\n );\n }\n return value.trim();\n}\n\n/**\n * Refuse a malformed principal before any database work. A principal with\n * no tenant, an unknown type, or no `can` function is a programming error.\n */\nfunction assertPrincipal(principal: ApprovalPrincipal): void {\n if (!principal || typeof principal.can !== 'function') {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'An approval principal must provide can(slug).',\n );\n }\n assertToken(principal.id, 'Approval principal id');\n if (\n typeof principal.tenantId !== 'string' ||\n !UUID_RE.test(principal.tenantId)\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'An approval principal must carry the UUID of the tenant its permissions were resolved for.',\n );\n }\n if (!APPROVAL_PRINCIPAL_TYPES.includes(principal.type)) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Approval principal type must be one of ${APPROVAL_PRINCIPAL_TYPES.join(', ')}.`,\n );\n }\n}\n\n/**\n * Distinct actors whose `approved` events count toward quorum: human\n * principals, including explicitly ledgered self-decisions. Legacy unmarked\n * requester events and non-human events never count.\n */\nfunction countedApprovers(\n approvals: readonly ApprovalEvent[],\n request: ApprovalRequest,\n): Set<string> {\n return new Set(\n approvals\n .filter(\n (event) =>\n event.type === 'approved' &&\n event.actorType === 'human' &&\n (event.actorId !== request.requestedBy ||\n (event.selfApproved === true &&\n isPermissionSlug(event.selfApprovalPermission))),\n )\n .map((event) => event.actorId),\n );\n}\n\nfunction rowVersion(rows: unknown[] | undefined): number | null {\n const row = rows?.[0] as Record<string, unknown> | undefined;\n if (!row) return null;\n const version = Number(row.version);\n return Number.isSafeInteger(version) ? version : null;\n}\n\n/**\n * The decision gate. Construct it over the application's database; it binds\n * its own collections per call and per transaction.\n */\nexport class ApprovalService {\n private readonly db: TransactionCapableDatabase;\n private readonly clock: () => Date;\n private readonly maxAttempts: number;\n\n constructor(options: ApprovalServiceOptions) {\n if (!options?.db || typeof options.db.query !== 'function') {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'ApprovalService requires an initialized database.',\n );\n }\n if (\n typeof (options.db as TransactionCapableDatabase).transaction !==\n 'function'\n ) {\n throw new ApprovalError(\n 'APPROVAL_NO_TRANSACTION',\n 'ApprovalService requires a database adapter with transaction support.',\n );\n }\n this.db = options.db as TransactionCapableDatabase;\n this.clock = options.now ?? (() => new Date());\n this.maxAttempts = Math.max(1, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n }\n\n // -------------------------------------------------------------------------\n // Reads\n // -------------------------------------------------------------------------\n\n /** One request in the principal's tenant, or `null`. */\n async getRequest(\n principal: ApprovalPrincipal,\n requestId: string,\n ): Promise<ApprovalRequest | null> {\n assertPrincipal(principal);\n if (!UUID_RE.test(String(requestId ?? ''))) return null;\n return await this.inTenant(principal, () =>\n this.loadRequest(this.db, principal.tenantId, requestId),\n );\n }\n\n /** A request's events in order, in the principal's tenant. */\n async listEvents(\n principal: ApprovalPrincipal,\n requestId: string,\n ): Promise<ApprovalEvent[]> {\n assertPrincipal(principal);\n if (!UUID_RE.test(String(requestId ?? ''))) return [];\n return await this.inTenant(principal, async () => {\n const events = await ApprovalEventCollection.create({ db: this.db });\n return await events.list({\n where: { tenantId: principal.tenantId, requestId },\n orderBy: 'sequence ASC',\n limit: 1000,\n });\n });\n }\n\n // -------------------------------------------------------------------------\n // Transitions\n // -------------------------------------------------------------------------\n\n /**\n * Open a request for approval of one subject revision. Any principal type\n * may request. The quorum, expiry, and required permissions are fixed now\n * from the kind's defaults tightened by the tenant's policy.\n */\n async requestApproval(\n principal: ApprovalPrincipal,\n input: RequestApprovalInput,\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const kind = requireApprovalKind(\n typeof input.kind === 'string' ? input.kind : input.kind?.key,\n );\n const subjectId = assertToken(input.subjectId, 'subjectId');\n const subjectRevisionHash = assertToken(\n input.subjectRevisionHash,\n 'subjectRevisionHash',\n );\n const requestKey =\n input.requestKey === undefined\n ? globalThis.crypto.randomUUID()\n : assertToken(input.requestKey, 'requestKey');\n const summary = assertText(input.summary, 'summary');\n const tenantId = principal.tenantId;\n\n const sameContent = (row: ApprovalRequest) =>\n row.kind === kind.key &&\n row.subjectType === kind.subject &&\n row.subjectId === subjectId &&\n row.subjectRevisionHash === subjectRevisionHash;\n\n if (this.contextMismatch(principal)) {\n return ApprovalService.mismatchResult();\n }\n return await this.inTenant(principal, async () => {\n let outcome: TxOutcome;\n try {\n outcome = await this.runTransaction(async (tx) => {\n const requests = await this.txCollection(\n ApprovalRequestCollection,\n tx,\n );\n const [existing] = await requests.list({\n where: { tenantId, requestKey },\n limit: 1,\n });\n if (existing) {\n return sameContent(existing)\n ? ({\n kind: 'done',\n outcome: 'already_applied',\n id: String(existing.id),\n } as const)\n : refusal(\n 'request_key_conflict',\n `requestKey '${requestKey}' already names a different request`,\n );\n }\n\n const policy = await this.loadPolicy(tx, tenantId, kind.key);\n const rules = effectiveRules(kind, policy);\n const now = this.clock();\n const request = await requests.create({\n tenantId,\n kind: kind.key,\n subjectType: kind.subject,\n subjectId,\n subjectRevisionHash,\n requestKey,\n requestedBy: principal.id,\n requestedByType: principal.type,\n summary,\n status: 'pending',\n requiredApprovals: rules.requiredApprovals,\n approvalCount: 0,\n requiredPermissions: JSON.stringify(rules.requiredPermissions),\n version: 1,\n expiresAt: new Date(now.getTime() + rules.ttlMs),\n // The only place a request insert is authorized.\n ...serviceWriteOption(),\n } as Parameters<ApprovalRequestCollection['create']>[0]);\n const id = String(request.id);\n await this.appendEvent(tx, {\n tenantId,\n requestId: id,\n type: 'created',\n principal,\n reason: summary,\n subjectRevisionHash,\n sequence: 1,\n now,\n });\n return { kind: 'done', outcome: 'transitioned', id } as const;\n });\n } catch (error) {\n // A concurrent request with the same key won the unique index.\n if (!isUniqueViolationError(error)) throw error;\n const requests = await ApprovalRequestCollection.create({\n db: this.db,\n });\n const [winner] = await requests.list({\n where: { tenantId, requestKey },\n limit: 1,\n });\n if (!winner) throw error;\n outcome = sameContent(winner)\n ? { kind: 'done', outcome: 'already_applied', id: String(winner.id) }\n : refusal(\n 'request_key_conflict',\n `requestKey '${requestKey}' already names a different request`,\n );\n }\n return await this.toResult(principal.tenantId, outcome);\n });\n }\n\n /**\n * Record a decision. Only a `human` principal of the request's tenant who\n * holds every required permission may decide (requesters also need the\n * kind's explicit selfApprovalPermission),\n * once, while the request is pending and unexpired. `approve` counts\n * toward the quorum of distinct approvers; `reject` and `request_changes`\n * end the request.\n */\n async decide(\n principal: ApprovalPrincipal,\n requestId: string,\n input: DecideInput,\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const eventType = DECISION_EVENT[input?.decision];\n if (!eventType) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `Unknown decision '${String(input?.decision)}'.`,\n );\n }\n const reason = assertText(input.reason, 'reason');\n if (input.decision !== 'approve' && !reason) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `A '${input.decision}' decision requires a reason.`,\n );\n }\n const tenantId = principal.tenantId;\n\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (principal.type !== 'human') {\n return refusal(\n 'not_human',\n `a ${principal.type} principal cannot decide`,\n request.id,\n );\n }\n const selfApproved = principal.id === request.requestedBy;\n const selfApprovalPermission = selfApproved\n ? requireApprovalKind(request.kind).selfApprovalPermission\n : undefined;\n if (\n selfApproved &&\n (!selfApprovalPermission || !principal.can(selfApprovalPermission))\n ) {\n return refusal(\n 'self_approval',\n 'the requester lacks the kind self-approval allowance',\n request.id,\n );\n }\n const missing = (await this.requiredPermissionsFor(tx, request)).filter(\n (slug) => !principal.can(slug),\n );\n if (missing.length > 0) {\n return refusal(\n 'forbidden',\n `missing permission: ${missing.join(', ')}`,\n request.id,\n );\n }\n if (request.status !== 'pending') {\n return refusal(\n 'not_pending',\n `request is ${request.status}`,\n request.id,\n );\n }\n if (!(request.expiresAtMs() > now.getTime())) {\n return refusal('expired', 'the request expired', request.id);\n }\n\n const events = await this.txCollection(ApprovalEventCollection, tx);\n const decided = await events.list({\n where: { tenantId, requestId: request.id, voteKey: principal.id },\n limit: 1,\n });\n if (decided.length > 0) {\n return refusal(\n 'already_decided',\n 'this principal already decided',\n request.id,\n );\n }\n\n const version = Number(request.version);\n const nowIso = isoNow(now);\n let updated: { rows?: unknown[] };\n if (input.decision === 'approve') {\n // Quorum counts distinct approvers from the ledger, not a counter.\n const approvals = await events.list({\n where: { tenantId, requestId: request.id, type: 'approved' },\n limit: 1000,\n });\n const voters = countedApprovers(approvals, request);\n voters.add(principal.id);\n const count = voters.size;\n const reached = count >= Number(request.requiredApprovals);\n updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET approval_count = ?, status = ?, decided_at = ${reached ? '?' : 'decided_at'},\n version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'pending'\n AND version = ? AND expires_at > ?\n RETURNING version`,\n ...[\n count,\n reached ? 'approved' : 'pending',\n ...(reached ? [nowIso] : []),\n nowIso,\n request.id,\n tenantId,\n version,\n nowIso,\n ],\n );\n } else {\n const status: ApprovalStatus =\n input.decision === 'reject' ? 'rejected' : 'changes_requested';\n updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET status = ?, decided_at = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'pending'\n AND version = ? AND expires_at > ?\n RETURNING version`,\n status,\n nowIso,\n nowIso,\n request.id,\n tenantId,\n version,\n nowIso,\n );\n }\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: eventType,\n principal,\n reason,\n subjectRevisionHash: request.subjectRevisionHash,\n sequence: next,\n voteKey: principal.id,\n selfApproved,\n selfApprovalPermission,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n );\n }\n\n /**\n * Cancel a pending request. The requester may cancel their own request;\n * anyone else needs `approvals.cancel-any`.\n */\n async cancel(\n principal: ApprovalPrincipal,\n requestId: string,\n input: { reason?: string } = {},\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const reason = assertText(input.reason, 'reason');\n const tenantId = principal.tenantId;\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (\n principal.id !== request.requestedBy &&\n !principal.can(CANCEL_ANY_APPROVAL_PERMISSION)\n ) {\n return refusal(\n 'forbidden',\n `only the requester or a holder of ${CANCEL_ANY_APPROVAL_PERMISSION} may cancel`,\n request.id,\n );\n }\n if (request.status !== 'pending') {\n return refusal(\n 'not_pending',\n `request is ${request.status}`,\n request.id,\n );\n }\n if (!(request.expiresAtMs() > now.getTime())) {\n return refusal('expired', 'the request expired', request.id);\n }\n const nowIso = isoNow(now);\n const updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET status = 'cancelled', decided_at = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'pending'\n AND version = ? AND expires_at > ?\n RETURNING version`,\n nowIso,\n nowIso,\n request.id,\n tenantId,\n Number(request.version),\n nowIso,\n );\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: 'cancelled',\n principal,\n reason,\n subjectRevisionHash: request.subjectRevisionHash,\n sequence: next,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n );\n }\n\n /**\n * Mark one request expired: a pending request, or an approved one that\n * was never consumed, whose expiry has passed. Needs no permission (it\n * only records what time already decided), so a job may call it.\n */\n async expire(\n principal: ApprovalPrincipal,\n requestId: string,\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const tenantId = principal.tenantId;\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (\n !(\n request.status === 'pending' ||\n (request.status === 'approved' && !request.isConsumed())\n )\n ) {\n return refusal(\n 'not_pending',\n request.status === 'approved'\n ? 'the approval was consumed'\n : `request is ${request.status}`,\n request.id,\n );\n }\n if (request.expiresAtMs() > now.getTime()) {\n return refusal(\n 'not_expired',\n 'the request has not expired',\n request.id,\n );\n }\n const nowIso = isoNow(now);\n const updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET status = 'expired', decided_at = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status IN ('pending', 'approved')\n AND consumed_at IS NULL AND version = ? AND expires_at <= ?\n RETURNING version`,\n nowIso,\n nowIso,\n request.id,\n tenantId,\n Number(request.version),\n nowIso,\n );\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: 'expired',\n principal,\n reason: '',\n subjectRevisionHash: request.subjectRevisionHash,\n sequence: next,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n );\n }\n\n /**\n * Expire every due request in the principal's tenant: pending requests\n * and unconsumed approvals past their deadline, oldest expiry first, at\n * most `limit`. Returns the ids this call expired.\n */\n async expireDue(\n principal: ApprovalPrincipal,\n options: { limit?: number } = {},\n ): Promise<string[]> {\n assertPrincipal(principal);\n const limit = Math.min(Math.max(1, Math.trunc(options.limit ?? 100)), 1000);\n const now = this.clock();\n const candidates = await this.inTenant(principal, async () => {\n const requests = await ApprovalRequestCollection.create({ db: this.db });\n return await requests.list({\n where: {\n tenantId: principal.tenantId,\n status: ['pending', 'approved'],\n // Exclude consumed approvals in the query, before the limit: they\n // never expire, so filtering them afterwards let a batch of them\n // starve every later due request.\n consumedAt: null,\n 'expiresAt <=': now,\n },\n orderBy: 'expires_at ASC',\n limit,\n });\n });\n const expired: string[] = [];\n for (const candidate of candidates) {\n const result = await this.expire(principal, String(candidate.id));\n if (result.outcome === 'transitioned') expired.push(String(candidate.id));\n }\n return expired;\n }\n\n /**\n * Consume an approval exactly once. The presented hash must equal the\n * revision that was approved; the request must be approved, unconsumed,\n * and unexpired. Any principal type of the tenant may consume (the\n * consumer's own service is the executor). Pass `options.transaction` to\n * make the consumption part of the consumer's own transaction.\n */\n async consume(\n principal: ApprovalPrincipal,\n requestId: string,\n subjectRevisionHash: string,\n options: ConsumeOptions = {},\n ): Promise<ApprovalResult> {\n assertPrincipal(principal);\n const hash = assertToken(subjectRevisionHash, 'subjectRevisionHash');\n const tenantId = principal.tenantId;\n return await this.transition(\n principal,\n requestId,\n async (tx, request, now) => {\n if (request.status !== 'approved') {\n return refusal(\n 'not_approved',\n `request is ${request.status}`,\n request.id,\n );\n }\n if (request.isConsumed()) {\n return refusal(\n 'already_consumed',\n 'the approval was already used',\n request.id,\n );\n }\n if (request.subjectRevisionHash !== hash) {\n return refusal(\n 'revision_mismatch',\n 'the subject changed after it was approved',\n request.id,\n );\n }\n if (!(request.expiresAtMs() > now.getTime())) {\n return refusal('expired', 'the approval expired', request.id);\n }\n if (!(await this.ledgerBacksApproval(tx, request))) {\n return refusal(\n 'unbacked_approval',\n 'the ledger does not record this approval',\n request.id,\n );\n }\n const nowIso = isoNow(now);\n const updated = await tx.query(\n `UPDATE ${REQUESTS_TABLE}\n SET consumed_at = ?, consumed_by = ?, version = version + 1, updated_at = ?\n WHERE id = ? AND tenant_id = ? AND status = 'approved'\n AND consumed_at IS NULL AND subject_revision_hash = ?\n AND version = ? AND expires_at > ?\n RETURNING version`,\n nowIso,\n principal.id,\n nowIso,\n request.id,\n tenantId,\n hash,\n Number(request.version),\n nowIso,\n );\n const next = rowVersion(updated.rows);\n if (next === null) return { kind: 'retry' };\n await this.appendEvent(tx, {\n tenantId,\n requestId: String(request.id),\n type: 'consumed',\n principal,\n reason: '',\n subjectRevisionHash: hash,\n sequence: next,\n now,\n });\n await this.recordChange(tx, String(request.id), tenantId);\n return {\n kind: 'done',\n outcome: 'transitioned',\n id: String(request.id),\n };\n },\n options.transaction,\n );\n }\n\n // -------------------------------------------------------------------------\n // Policy\n // -------------------------------------------------------------------------\n\n /**\n * Write the tenant's tightening of a kind. Needs\n * `approvals.manage-policy`; a rule that would loosen the kind's defaults\n * throws `APPROVAL_POLICY_LOOSENS`. `0`/`''` clear a rule back to the\n * default. Applies to requests made afterwards.\n */\n async setPolicy(\n principal: ApprovalPrincipal,\n kindKey: ApprovalKind | string,\n rules: ApprovalPolicyRules,\n ): Promise<ApprovalPolicy> {\n assertPrincipal(principal);\n if (\n principal.type !== 'human' ||\n !principal.can(MANAGE_APPROVAL_POLICY_PERMISSION)\n ) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `Setting approval policy needs a human principal holding ${MANAGE_APPROVAL_POLICY_PERMISSION}.`,\n );\n }\n const kind = requireApprovalKind(\n typeof kindKey === 'string' ? kindKey : kindKey?.key,\n );\n const normalized = {\n requiredApprovals: rules.requiredApprovals ?? 0,\n ttlMs: rules.ttlMs ?? 0,\n requiredPermission: String(rules.requiredPermission ?? '').trim(),\n };\n if (\n normalized.requiredPermission &&\n !isPermissionSlug(normalized.requiredPermission)\n ) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n `requiredPermission must be a permission slug, got '${normalized.requiredPermission}'.`,\n );\n }\n assertPolicyTightens(kind, normalized);\n const tenantId = principal.tenantId;\n return await this.inTenant(principal, async () => {\n const id = await this.runTransaction(async (tx) => {\n const policies = await this.txCollection(ApprovalPolicyCollection, tx);\n const [existing] = await policies.list({\n where: { tenantId, kind: kind.key },\n limit: 1,\n });\n if (existing) {\n existing.requiredApprovals = normalized.requiredApprovals;\n existing.ttlMs = normalized.ttlMs;\n existing.requiredPermission = normalized.requiredPermission;\n existing.updatedBy = principal.id;\n await existing.save();\n return String(existing.id);\n }\n const created = await policies.create({\n tenantId,\n kind: kind.key,\n ...normalized,\n updatedBy: principal.id,\n });\n return String(created.id);\n });\n const policies = await ApprovalPolicyCollection.create({ db: this.db });\n const [saved] = await policies.list({\n where: { tenantId, id },\n limit: 1,\n });\n if (!saved) {\n throw new ApprovalError(\n 'APPROVAL_INVALID',\n 'Saved approval policy vanished.',\n );\n }\n return saved;\n });\n }\n\n /** The effective rules a new request of `kind` would get in the tenant. */\n async rulesFor(principal: ApprovalPrincipal, kindKey: ApprovalKind | string) {\n assertPrincipal(principal);\n const kind = requireApprovalKind(\n typeof kindKey === 'string' ? kindKey : kindKey?.key,\n );\n return await this.inTenant(principal, async () =>\n effectiveRules(\n kind,\n await this.loadPolicy(this.db, principal.tenantId, kind.key),\n ),\n );\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n /**\n * Run a guarded transition with retry. `body` runs inside a transaction\n * on a fresh read of the request and returns `retry` when its guarded\n * UPDATE matched no row (a concurrent transition won).\n */\n private async transition(\n principal: ApprovalPrincipal,\n requestId: string,\n body: (\n tx: DatabaseInterface,\n request: ApprovalRequest,\n now: Date,\n ) => Promise<TxOutcome>,\n callerTransaction?: DatabaseInterface,\n ): Promise<ApprovalResult> {\n if (!UUID_RE.test(String(requestId ?? ''))) {\n return {\n outcome: 'refused',\n request: null,\n refusal: { reason: 'not_found', detail: 'not a request id' },\n };\n }\n if (this.contextMismatch(principal)) {\n return ApprovalService.mismatchResult();\n }\n const tenantId = principal.tenantId;\n return await this.inTenant(principal, async () => {\n const attempt = async (tx: DatabaseInterface): Promise<TxOutcome> => {\n const request = await this.loadRequest(tx, tenantId, requestId);\n if (!request) {\n return refusal('not_found', 'no such request in this tenant');\n }\n return await body(tx, request, this.clock());\n };\n\n if (callerTransaction) {\n // The caller owns the transaction: one attempt, no retry (a lost\n // race inside someone else's transaction is reported, not retried).\n const outcome = await attempt(callerTransaction);\n if (outcome.kind === 'retry') {\n return await this.toResult(\n tenantId,\n refusal('contention', 'a concurrent transition won', requestId),\n callerTransaction,\n );\n }\n return await this.toResult(tenantId, outcome, callerTransaction);\n }\n\n for (let i = 0; i < this.maxAttempts; i++) {\n let outcome: TxOutcome;\n try {\n outcome = await this.runTransaction(attempt);\n } catch (error) {\n // A unique ledger key lost to a concurrent writer: re-read and retry.\n if (isUniqueViolationError(error)) continue;\n throw error;\n }\n if (outcome.kind !== 'retry') {\n return await this.toResult(tenantId, outcome);\n }\n }\n return await this.toResult(\n tenantId,\n refusal('contention', 'concurrent transitions kept winning', requestId),\n );\n });\n }\n\n /** True when an active tenant context names a different tenant. */\n private contextMismatch(principal: ApprovalPrincipal): boolean {\n const active = getTenantId();\n return (\n !isSystemContext() &&\n active !== undefined &&\n active !== principal.tenantId\n );\n }\n\n /** The refusal returned when {@link contextMismatch} holds. */\n private static mismatchResult(): ApprovalResult {\n return {\n outcome: 'refused',\n request: null,\n refusal: {\n reason: 'tenant_mismatch',\n detail:\n \"the principal's tenant does not match the active tenant context\",\n },\n };\n }\n\n /** Pin the work to the principal's tenant; refuse a conflicting context. */\n private async inTenant<T>(\n principal: ApprovalPrincipal,\n fn: () => Promise<T>,\n ): Promise<T> {\n if (this.contextMismatch(principal)) {\n throw new ApprovalError(\n 'APPROVAL_FORBIDDEN',\n `The principal's tenant does not match the active tenant context.`,\n );\n }\n // Keep post-commit reads with embedded writers on their shared connection.\n return await withEmbeddedWriteQueue(\n this.db,\n isEmbeddedDatabase(this.db),\n () => withTenant({ tenantId: principal.tenantId }, fn),\n );\n }\n\n /**\n * Run `fn` in a transaction through core's embedded write queue.\n *\n * On embedded engines (SQLite, DuckDB, libsql) the transaction takes the\n * queue for its database BEFORE the adapter's connection lock, and the\n * model writes inside it (event inserts, change-feed appends) re-enter that\n * hold. Taking the connection lock first deadlocks against an unrelated\n * save that holds the queue and then opens its own write transaction, and\n * lets other root writes land inside this BEGIN..COMMIT. The queue also\n * serializes these transactions per database in-process, which is what\n * the former per-handle promise chain did, so that chain is gone.\n * PostgreSQL is not queued: each transaction has its own pooled\n * connection and the guarded UPDATE's row lock arbitrates.\n */\n private async runTransaction<T>(\n fn: (tx: DatabaseInterface) => Promise<T>,\n ): Promise<T> {\n return await withEmbeddedWriteTransaction(\n this.db,\n isEmbeddedDatabase(this.db),\n fn,\n );\n }\n\n /** A collection bound to a transaction database. */\n private async txCollection<C>(\n Collection: { create(options: Record<string, unknown>): Promise<C> },\n tx: DatabaseInterface,\n ): Promise<C> {\n return await Collection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n\n private async loadRequest(\n db: DatabaseInterface,\n tenantId: string,\n requestId: string,\n ): Promise<ApprovalRequest | null> {\n const requests =\n db === this.db\n ? await ApprovalRequestCollection.create({ db })\n : await this.txCollection(ApprovalRequestCollection, db);\n const [request] = await requests.list({\n where: { tenantId, id: requestId },\n limit: 1,\n });\n // Belt and braces: never act on a row from another tenant.\n return request && request.tenantId === tenantId ? request : null;\n }\n\n private async loadPolicy(\n db: DatabaseInterface,\n tenantId: string,\n kind: string,\n ): Promise<ApprovalPolicy | null> {\n const policies =\n db === this.db\n ? await ApprovalPolicyCollection.create({ db })\n : await this.txCollection(ApprovalPolicyCollection, db);\n const [policy] = await policies.list({\n where: { tenantId, kind },\n limit: 1,\n });\n return policy ?? null;\n }\n\n /**\n * Every slug a decider must hold now: the slugs fixed at request time\n * plus the kind's and the tenant policy's current ones (tightening only:\n * a later policy can add a slug, never remove one).\n */\n private async requiredPermissionsFor(\n tx: DatabaseInterface,\n request: ApprovalRequest,\n ): Promise<string[]> {\n const kind = requireApprovalKind(request.kind);\n const current = effectiveRules(\n kind,\n await this.loadPolicy(tx, request.tenantId, kind.key),\n );\n const slugs = new Set(request.getRequiredPermissions());\n for (const slug of current.requiredPermissions) slugs.add(slug);\n return [...slugs];\n }\n\n private async appendEvent(\n tx: DatabaseInterface,\n input: {\n tenantId: string;\n requestId: string;\n type: ApprovalEventType;\n principal: ApprovalPrincipal;\n reason: string;\n subjectRevisionHash: string;\n sequence: number;\n voteKey?: string;\n selfApproved?: boolean;\n selfApprovalPermission?: string;\n now: Date;\n },\n ): Promise<void> {\n const events = await this.txCollection(ApprovalEventCollection, tx);\n await events.create({\n tenantId: input.tenantId,\n requestId: input.requestId,\n type: input.type,\n actorId: input.principal.id,\n actorType: input.principal.type,\n reason: input.reason,\n subjectRevisionHash: input.subjectRevisionHash,\n sequence: input.sequence,\n voteKey: input.voteKey ?? null,\n selfApproved: input.selfApproved ?? false,\n selfApprovalPermission: input.selfApprovalPermission ?? '',\n occurredAt: input.now,\n // The only place an event insert is authorized.\n ...serviceWriteOption(),\n } as Parameters<ApprovalEventCollection['create']>[0]);\n }\n\n /**\n * Defence in depth for `consume`: the request row says `approved`, so the\n * ledger must agree. It needs the `created` event at sequence 1, no\n * terminal event, and approvals from at least `requiredApprovals` distinct\n * human actors, with explicit audit markers for self-decisions. Catches a\n * status written around the service (raw SQL); model-layer inserts are\n * already capability-gated.\n */\n private async ledgerBacksApproval(\n tx: DatabaseInterface,\n request: ApprovalRequest,\n ): Promise<boolean> {\n const events = await this.txCollection(ApprovalEventCollection, tx);\n const ledger = await events.list({\n where: { tenantId: request.tenantId, requestId: request.id },\n limit: 1000,\n });\n const created = ledger.some(\n (event) => event.type === 'created' && Number(event.sequence) === 1,\n );\n const terminal = ledger.some((event) =>\n [\n 'rejected',\n 'changes_requested',\n 'cancelled',\n 'expired',\n 'consumed',\n ].includes(event.type),\n );\n const approvers = countedApprovers(\n ledger.filter((event) => event.type === 'approved'),\n request,\n );\n return (\n created &&\n !terminal &&\n approvers.size >= Math.max(1, Number(request.requiredApprovals))\n );\n }\n\n /**\n * The guarded UPDATE bypasses save hooks, so record the change-feed entry\n * the save path would have written. Best effort, like the save path.\n */\n private async recordChange(\n tx: DatabaseInterface,\n requestId: string,\n tenantId: string,\n ): Promise<void> {\n try {\n await appendChange(tx, {\n table: REQUESTS_TABLE,\n rowId: requestId,\n operation: 'update',\n tenantId,\n });\n } catch {\n // The transition committed its own write; a missing feed entry is\n // recovered by a full resync, exactly as for a failed save append.\n }\n }\n\n /** Re-read the request after commit (ids only cross the boundary). */\n private async toResult(\n tenantId: string,\n outcome: TxOutcome,\n db: DatabaseInterface = this.db,\n ): Promise<ApprovalResult> {\n if (outcome.kind === 'retry') {\n throw new Error('ApprovalService: unresolved retry outcome');\n }\n const id = outcome.id;\n const request = id ? await this.loadRequest(db, tenantId, id) : null;\n if (outcome.kind === 'refused') {\n return {\n outcome: 'refused',\n request: outcome.reason === 'not_found' ? null : request,\n refusal: { reason: outcome.reason, detail: outcome.detail },\n };\n }\n return { outcome: outcome.outcome, request };\n }\n}\n","/**\n * @happyvertical/smrt-approvals\n *\n * A small decision gate: a package defines an approval kind, a requester\n * opens a request bound to one subject revision, eligible humans decide,\n * and the consumer consumes the approval exactly once before acting.\n *\n * @example\n * ```typescript\n * import {\n * ApprovalService,\n * defineApprovalKind,\n * } from '@happyvertical/smrt-approvals';\n *\n * export const publishPost = defineApprovalKind({\n * key: 'social.post.publish',\n * subject: '@happyvertical/smrt-social:SocialPost',\n * permission: 'social.approve-post',\n * defaults: { requiredApprovals: 1 },\n * });\n *\n * const approvals = new ApprovalService({ db });\n * const { request } = await approvals.requestApproval(author, {\n * kind: publishPost,\n * subjectId: post.id,\n * subjectRevisionHash: hashOf(post),\n * });\n * await approvals.decide(editor, request.id, { decision: 'approve' });\n * const used = await approvals.consume(publisher, request.id, hashOf(post));\n * if (used.outcome === 'transitioned') await publish(post);\n * ```\n *\n * @packageDocumentation\n */\n\n// Self-register this package's manifest before any @smrt() decorator fires\n// downstream. Must come first. See __smrt-register__.ts (#1132).\nimport './__smrt-register__.js';\nimport { ensureApprovalPermissionsRegistered } from './permissions.js';\n\nexport { ApprovalEventCollection } from './collections/ApprovalEventCollection.js';\nexport { ApprovalPolicyCollection } from './collections/ApprovalPolicyCollection.js';\nexport { ApprovalRequestCollection } from './collections/ApprovalRequestCollection.js';\nexport {\n type ApprovalPolicyRules,\n assertPolicyTightens,\n DEFAULT_APPROVAL_TTL_MS,\n defineApprovalKind,\n effectiveRules,\n getApprovalKind,\n listApprovalKinds,\n MAX_APPROVAL_TTL_MS,\n MAX_REQUIRED_APPROVALS,\n MIN_APPROVAL_TTL_MS,\n requireApprovalKind,\n unregisterApprovalKind,\n} from './kinds.js';\nexport {\n ApprovalEvent,\n type ApprovalEventOptions,\n} from './models/ApprovalEvent.js';\nexport {\n ApprovalPolicy,\n type ApprovalPolicyOptions,\n} from './models/ApprovalPolicy.js';\nexport {\n ApprovalRequest,\n type ApprovalRequestOptions,\n} from './models/ApprovalRequest.js';\nexport {\n APPROVAL_PERMISSION_DEFINITIONS,\n CANCEL_ANY_APPROVAL_PERMISSION,\n ensureApprovalPermissionsRegistered,\n MANAGE_APPROVAL_POLICY_PERMISSION,\n registerApprovalPermissions,\n} from './permissions.js';\nexport {\n type ApprovalResult,\n ApprovalService,\n type ApprovalServiceOptions,\n type ConsumeOptions,\n type DecideInput,\n type RequestApprovalInput,\n} from './service.js';\nexport {\n APPROVAL_EVENT_TYPES,\n APPROVAL_PRINCIPAL_TYPES,\n APPROVAL_STATUSES,\n type ApprovalDecision,\n ApprovalError,\n type ApprovalErrorCode,\n type ApprovalEventType,\n type ApprovalKind,\n type ApprovalKindDefaults,\n type ApprovalKindInput,\n type ApprovalPrincipal,\n type ApprovalPrincipalType,\n type ApprovalRefusalReason,\n type ApprovalStatus,\n type ApprovalTransitionOutcome,\n type ApprovalTransitionResult,\n approvalPrincipalFromPermissions,\n type EffectiveApprovalRules,\n} from './types.js';\n\nensureApprovalPermissionsRegistered();\n"],"mappings":"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"}
|
package/dist/manifest.json
CHANGED
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-approvals",
|
|
6
|
-
"packageVersion": "0.55.
|
|
6
|
+
"packageVersion": "0.55.22",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
10
|
+
"manifest": "56bf9cba9dded76167ad02530a1c91c20f60bbd2e9fcb65faa7a57902ea3ba63",
|
|
11
|
+
"packageJson": "9acf511a69249b8255cb3dd9ef544a867828ca27dcead10659c02b1b4c687fb3",
|
|
12
12
|
"agents": "d97f97c724891f846420dadc8abfc9b73af5e2d453a56ae748816cf1b039d452",
|
|
13
13
|
"moduleDoc:agents/approvals.md": "3e2b9ef6441798041de30d39b295886c758053185085174bd430d2f156b81e5a"
|
|
14
14
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-approvals",
|
|
3
|
-
"version": "0.55.
|
|
3
|
+
"version": "0.55.22",
|
|
4
4
|
"description": "Approval decision gate for the SMRT framework: revision-bound, single-use approvals with quorum, expiry, and an append-only event ledger",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
"./manifest.json": "./dist/manifest.json"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@happyvertical/smrt-core": "0.55.
|
|
24
|
-
"@happyvertical/smrt-tenancy": "0.55.
|
|
25
|
-
"@happyvertical/smrt-users": "0.55.
|
|
23
|
+
"@happyvertical/smrt-core": "0.55.22",
|
|
24
|
+
"@happyvertical/smrt-tenancy": "0.55.22",
|
|
25
|
+
"@happyvertical/smrt-users": "0.55.22",
|
|
26
26
|
"@happyvertical/sql": "^0.103.5"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@happyvertical/smrt-vitest": "0.55.
|
|
29
|
+
"@happyvertical/smrt-vitest": "0.55.22",
|
|
30
30
|
"@types/node": "24.13.6",
|
|
31
31
|
"typescript": "6.0.3",
|
|
32
32
|
"vite": "8.1.4",
|