@supacloud/db 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
1
  /** Install through the application's normal migration flow, never during a request. */
2
- export declare const COMMAND_PERSISTENCE_SQL = "\nDO $runtime$\nBEGIN\n IF to_regprocedure('supacloud_workflows.start_run(uuid,text,text,text,jsonb,integer)') IS NULL\n OR to_regprocedure('supacloud_commands.status(jsonb)') IS NULL THEN\n RAISE EXCEPTION 'Install the SupaCloud Commands/Workflow/PGMQ runtime before command persistence';\n END IF;\nEND\n$runtime$;\nCREATE SCHEMA IF NOT EXISTS supacloud_commands;\nREVOKE ALL ON SCHEMA supacloud_commands FROM PUBLIC;\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_receipts (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n kind text NOT NULL CHECK (kind IN ('transactional', 'external')),\n input_fingerprint text NOT NULL CHECK (input_fingerprint ~ '^[a-f0-9]{64}$'),\n input_payload text,\n dispatch_key uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE,\n status text NOT NULL CHECK (status IN ('pending', 'unknown', 'confirmed')),\n audit_state text NOT NULL CHECK (audit_state IN ('pending', 'complete')),\n result jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n CHECK ((status = 'confirmed') = (result IS NOT NULL)),\n CHECK (audit_state <> 'complete' OR status = 'confirmed'),\n CHECK (kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete'))\n);\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_audit (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n event text NOT NULL,\n details jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n FOREIGN KEY (tenant_id, actor_id, command, operation_key)\n REFERENCES supacloud_commands.execution_receipts (tenant_id, actor_id, command, operation_key)\n);\nREVOKE ALL ON supacloud_commands.execution_receipts, supacloud_commands.execution_audit FROM PUBLIC;\nCREATE OR REPLACE FUNCTION supacloud_commands.enqueue_execution_recovery()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $recovery$\nDECLARE submission jsonb;\nBEGIN\n PERFORM pg_advisory_xact_lock(hashtextextended(NEW.dispatch_key::text,0));\n SELECT supacloud_commands.snapshot(NEW.dispatch_key,false) INTO submission;\n IF submission IS NOT NULL THEN\n IF submission->>'commandType' IS DISTINCT FROM NEW.command\n OR submission->>'actorId' IS DISTINCT FROM NEW.actor_id\n OR submission->>'tenantId' IS DISTINCT FROM NEW.tenant_id\n OR NEW.operation_key <> NEW.dispatch_key::text THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_IDENTITY_CONFLICT';\n END IF;\n RETURN NEW;\n END IF;\n IF NEW.kind = 'external' AND (NEW.status <> 'confirmed' OR NEW.audit_state <> 'complete') THEN\n PERFORM supacloud_workflows.start_run(\n NEW.dispatch_key, 'supacloud.command.reconcile', '1', 'reconcile',\n jsonb_build_object('commandId', NEW.dispatch_key, 'tenantId', NEW.tenant_id,\n 'actorId', NEW.actor_id, 'command', NEW.command, 'operationId', NEW.operation_key),\n 20\n );\n END IF;\n RETURN NEW;\nEND\n$recovery$;\nCREATE OR REPLACE TRIGGER execution_recovery_enqueue\nAFTER INSERT ON supacloud_commands.execution_receipts\nFOR EACH ROW EXECUTE FUNCTION supacloud_commands.enqueue_execution_recovery();\n\nCREATE OR REPLACE FUNCTION supacloud_commands.execution_status(request jsonb)\nRETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $status$\n SELECT jsonb_build_object('kind','execution','commandId',r.dispatch_key,\n 'execution',jsonb_build_object('tenantId',r.tenant_id,'actorId',r.actor_id,\n 'command',r.command,'operationId',r.operation_key,'dispatchKey',r.dispatch_key,\n 'status',r.status,'audit',r.audit_state)\n || CASE WHEN r.status='confirmed' THEN jsonb_build_object('result',r.result) ELSE '{}'::jsonb END,\n 'workflow',CASE WHEN w.id IS NULL THEN NULL ELSE jsonb_build_object('runId',w.id,'status',w.status) END)\n FROM supacloud_commands.execution_receipts r\n LEFT JOIN supacloud_workflows.runs w ON w.id=r.dispatch_key\n WHERE CASE WHEN request ? 'commandId' THEN r.dispatch_key::text=request->>'commandId'\n ELSE r.tenant_id=request->>'tenantId' AND r.actor_id=request->>'actorId'\n AND r.command=request->>'command' AND r.operation_key=request->>'operationId' END\n$status$;\nREVOKE ALL ON FUNCTION supacloud_commands.execution_status(jsonb) FROM PUBLIC;\n";
2
+ export declare const COMMAND_PERSISTENCE_SQL = "\nDO $runtime$\nBEGIN\n IF to_regprocedure('supacloud_workflows.start_run(uuid,text,text,text,jsonb,integer)') IS NULL\n OR to_regprocedure('supacloud_commands.status(jsonb)') IS NULL THEN\n RAISE EXCEPTION 'Install the SupaCloud Commands/Workflow/PGMQ runtime before command persistence';\n END IF;\nEND\n$runtime$;\nCREATE SCHEMA IF NOT EXISTS supacloud_commands;\nREVOKE ALL ON SCHEMA supacloud_commands FROM PUBLIC;\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_receipts (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n kind text NOT NULL CHECK (kind IN ('transactional', 'external')),\n input_fingerprint text NOT NULL CHECK (input_fingerprint ~ '^[a-f0-9]{64}$'),\n input_payload text,\n dispatch_key uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE,\n status text NOT NULL CHECK (status IN ('pending', 'unknown', 'confirmed', 'rejected')),\n audit_state text NOT NULL CHECK (audit_state IN ('pending', 'complete')),\n result jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n CHECK ((status = 'confirmed') = (result IS NOT NULL)),\n CONSTRAINT execution_receipts_audit_terminal_check CHECK (\n (audit_state <> 'complete' OR status IN ('confirmed', 'rejected'))\n AND (status <> 'rejected' OR audit_state = 'complete')),\n CONSTRAINT execution_receipts_transactional_check CHECK (\n kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete'))\n);\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_audit (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n event text NOT NULL,\n details jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n FOREIGN KEY (tenant_id, actor_id, command, operation_key)\n REFERENCES supacloud_commands.execution_receipts (tenant_id, actor_id, command, operation_key)\n);\nREVOKE ALL ON supacloud_commands.execution_receipts, supacloud_commands.execution_audit FROM PUBLIC;\nCREATE OR REPLACE FUNCTION supacloud_commands.protect_terminal_execution()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $terminal$\nBEGIN\n IF OLD.status IN ('confirmed','rejected') AND (\n NEW.status IS DISTINCT FROM OLD.status OR NEW.result IS DISTINCT FROM OLD.result\n OR (OLD.audit_state = 'complete' AND NEW.audit_state IS DISTINCT FROM OLD.audit_state)) THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_TERMINAL_RECEIPT';\n END IF;\n RETURN NEW;\nEND\n$terminal$;\nCREATE OR REPLACE TRIGGER execution_terminal_guard\nBEFORE UPDATE ON supacloud_commands.execution_receipts\nFOR EACH ROW EXECUTE FUNCTION supacloud_commands.protect_terminal_execution();\n\nCREATE OR REPLACE FUNCTION supacloud_commands.require_rejection_audit()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $rejection$\nBEGIN\n IF NEW.status = 'rejected' AND NOT EXISTS (\n SELECT FROM supacloud_commands.execution_audit a\n WHERE a.tenant_id=NEW.tenant_id AND a.actor_id=NEW.actor_id\n AND a.command=NEW.command AND a.operation_key=NEW.operation_key\n ) THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_REJECTION_AUDIT_REQUIRED';\n END IF;\n RETURN NEW;\nEND\n$rejection$;\nDROP TRIGGER IF EXISTS execution_rejection_audit ON supacloud_commands.execution_receipts;\nCREATE CONSTRAINT TRIGGER execution_rejection_audit\nAFTER INSERT OR UPDATE ON supacloud_commands.execution_receipts\nDEFERRABLE INITIALLY DEFERRED\nFOR EACH ROW WHEN (NEW.status = 'rejected')\nEXECUTE FUNCTION supacloud_commands.require_rejection_audit();\nCREATE OR REPLACE FUNCTION supacloud_commands.enqueue_execution_recovery()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $recovery$\nDECLARE submission jsonb;\nBEGIN\n PERFORM pg_advisory_xact_lock(hashtextextended(NEW.dispatch_key::text,0));\n SELECT supacloud_commands.snapshot(NEW.dispatch_key,false) INTO submission;\n IF submission IS NOT NULL THEN\n IF submission->>'commandType' IS DISTINCT FROM NEW.command\n OR submission->>'actorId' IS DISTINCT FROM NEW.actor_id\n OR submission->>'tenantId' IS DISTINCT FROM NEW.tenant_id\n OR NEW.operation_key <> NEW.dispatch_key::text THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_IDENTITY_CONFLICT';\n END IF;\n RETURN NEW;\n END IF;\n IF NEW.kind = 'external' AND NEW.status <> 'rejected'\n AND (NEW.status <> 'confirmed' OR NEW.audit_state <> 'complete') THEN\n PERFORM supacloud_workflows.start_run(\n NEW.dispatch_key, 'supacloud.command.reconcile', '1', 'reconcile',\n jsonb_build_object('commandId', NEW.dispatch_key, 'tenantId', NEW.tenant_id,\n 'actorId', NEW.actor_id, 'command', NEW.command, 'operationId', NEW.operation_key),\n 20\n );\n END IF;\n RETURN NEW;\nEND\n$recovery$;\nCREATE OR REPLACE TRIGGER execution_recovery_enqueue\nAFTER INSERT ON supacloud_commands.execution_receipts\nFOR EACH ROW EXECUTE FUNCTION supacloud_commands.enqueue_execution_recovery();\n\nCREATE OR REPLACE FUNCTION supacloud_commands.execution_status(request jsonb)\nRETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $status$\n SELECT jsonb_build_object('kind','execution','commandId',r.dispatch_key,\n 'execution',jsonb_build_object('tenantId',r.tenant_id,'actorId',r.actor_id,\n 'command',r.command,'operationId',r.operation_key,'dispatchKey',r.dispatch_key,\n 'status',r.status,'audit',r.audit_state)\n || CASE WHEN r.status='confirmed' THEN jsonb_build_object('result',r.result) ELSE '{}'::jsonb END,\n 'workflow',CASE WHEN w.id IS NULL THEN NULL ELSE jsonb_build_object('runId',w.id,'status',w.status) END)\n FROM supacloud_commands.execution_receipts r\n LEFT JOIN supacloud_workflows.runs w ON w.id=r.dispatch_key\n WHERE CASE WHEN request ? 'commandId' THEN r.dispatch_key::text=request->>'commandId'\n ELSE r.tenant_id=request->>'tenantId' AND r.actor_id=request->>'actorId'\n AND r.command=request->>'command' AND r.operation_key=request->>'operationId' END\n$status$;\nREVOKE ALL ON FUNCTION supacloud_commands.execution_status(jsonb) FROM PUBLIC;\n";
3
3
  /** Explicit migration from the unreleased v1 prototype. Never discard operation keys. */
4
- export declare const COMMAND_PERSISTENCE_UPGRADE_SQL = "\nALTER TABLE supacloud_commands.execution_receipts\n ADD COLUMN IF NOT EXISTS input_fingerprint text,\n ADD COLUMN IF NOT EXISTS input_payload text;\nDO $migration$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='supacloud_commands'\n AND table_name='execution_receipts' AND column_name='input_key') THEN\n EXECUTE 'UPDATE supacloud_commands.execution_receipts\n SET input_fingerprint=encode(sha256(convert_to(input_key,''UTF8'')),''hex''),input_payload=input_key\n WHERE input_fingerprint IS NULL';\n ALTER TABLE supacloud_commands.execution_receipts DROP COLUMN input_key;\n END IF;\nEND\n$migration$;\nALTER TABLE supacloud_commands.execution_receipts ALTER COLUMN input_fingerprint SET NOT NULL;\nDO $constraint$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint\n WHERE conrelid='supacloud_commands.execution_receipts'::regclass\n AND conname='execution_receipts_input_fingerprint_check') THEN\n ALTER TABLE supacloud_commands.execution_receipts\n ADD CONSTRAINT execution_receipts_input_fingerprint_check CHECK (input_fingerprint ~ '^[a-f0-9]{64}$');\n END IF;\nEND\n$constraint$;\n\nDO $runtime$\nBEGIN\n IF to_regprocedure('supacloud_workflows.start_run(uuid,text,text,text,jsonb,integer)') IS NULL\n OR to_regprocedure('supacloud_commands.status(jsonb)') IS NULL THEN\n RAISE EXCEPTION 'Install the SupaCloud Commands/Workflow/PGMQ runtime before command persistence';\n END IF;\nEND\n$runtime$;\nCREATE SCHEMA IF NOT EXISTS supacloud_commands;\nREVOKE ALL ON SCHEMA supacloud_commands FROM PUBLIC;\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_receipts (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n kind text NOT NULL CHECK (kind IN ('transactional', 'external')),\n input_fingerprint text NOT NULL CHECK (input_fingerprint ~ '^[a-f0-9]{64}$'),\n input_payload text,\n dispatch_key uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE,\n status text NOT NULL CHECK (status IN ('pending', 'unknown', 'confirmed')),\n audit_state text NOT NULL CHECK (audit_state IN ('pending', 'complete')),\n result jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n CHECK ((status = 'confirmed') = (result IS NOT NULL)),\n CHECK (audit_state <> 'complete' OR status = 'confirmed'),\n CHECK (kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete'))\n);\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_audit (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n event text NOT NULL,\n details jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n FOREIGN KEY (tenant_id, actor_id, command, operation_key)\n REFERENCES supacloud_commands.execution_receipts (tenant_id, actor_id, command, operation_key)\n);\nREVOKE ALL ON supacloud_commands.execution_receipts, supacloud_commands.execution_audit FROM PUBLIC;\nCREATE OR REPLACE FUNCTION supacloud_commands.enqueue_execution_recovery()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $recovery$\nDECLARE submission jsonb;\nBEGIN\n PERFORM pg_advisory_xact_lock(hashtextextended(NEW.dispatch_key::text,0));\n SELECT supacloud_commands.snapshot(NEW.dispatch_key,false) INTO submission;\n IF submission IS NOT NULL THEN\n IF submission->>'commandType' IS DISTINCT FROM NEW.command\n OR submission->>'actorId' IS DISTINCT FROM NEW.actor_id\n OR submission->>'tenantId' IS DISTINCT FROM NEW.tenant_id\n OR NEW.operation_key <> NEW.dispatch_key::text THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_IDENTITY_CONFLICT';\n END IF;\n RETURN NEW;\n END IF;\n IF NEW.kind = 'external' AND (NEW.status <> 'confirmed' OR NEW.audit_state <> 'complete') THEN\n PERFORM supacloud_workflows.start_run(\n NEW.dispatch_key, 'supacloud.command.reconcile', '1', 'reconcile',\n jsonb_build_object('commandId', NEW.dispatch_key, 'tenantId', NEW.tenant_id,\n 'actorId', NEW.actor_id, 'command', NEW.command, 'operationId', NEW.operation_key),\n 20\n );\n END IF;\n RETURN NEW;\nEND\n$recovery$;\nCREATE OR REPLACE TRIGGER execution_recovery_enqueue\nAFTER INSERT ON supacloud_commands.execution_receipts\nFOR EACH ROW EXECUTE FUNCTION supacloud_commands.enqueue_execution_recovery();\n\nCREATE OR REPLACE FUNCTION supacloud_commands.execution_status(request jsonb)\nRETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $status$\n SELECT jsonb_build_object('kind','execution','commandId',r.dispatch_key,\n 'execution',jsonb_build_object('tenantId',r.tenant_id,'actorId',r.actor_id,\n 'command',r.command,'operationId',r.operation_key,'dispatchKey',r.dispatch_key,\n 'status',r.status,'audit',r.audit_state)\n || CASE WHEN r.status='confirmed' THEN jsonb_build_object('result',r.result) ELSE '{}'::jsonb END,\n 'workflow',CASE WHEN w.id IS NULL THEN NULL ELSE jsonb_build_object('runId',w.id,'status',w.status) END)\n FROM supacloud_commands.execution_receipts r\n LEFT JOIN supacloud_workflows.runs w ON w.id=r.dispatch_key\n WHERE CASE WHEN request ? 'commandId' THEN r.dispatch_key::text=request->>'commandId'\n ELSE r.tenant_id=request->>'tenantId' AND r.actor_id=request->>'actorId'\n AND r.command=request->>'command' AND r.operation_key=request->>'operationId' END\n$status$;\nREVOKE ALL ON FUNCTION supacloud_commands.execution_status(jsonb) FROM PUBLIC;\n\nDO $backfill$\nDECLARE r record;\nBEGIN\n FOR r IN SELECT * FROM supacloud_commands.execution_receipts\n WHERE kind='external' AND (status<>'confirmed' OR audit_state<>'complete')\n AND NOT EXISTS(SELECT FROM supacloud_workflows.runs w WHERE w.id=dispatch_key)\n LOOP\n PERFORM supacloud_workflows.start_run(\n r.dispatch_key,'supacloud.command.reconcile','1','reconcile',\n jsonb_build_object('commandId',r.dispatch_key,'tenantId',r.tenant_id,\n 'actorId',r.actor_id,'command',r.command,'operationId',r.operation_key),20\n );\n END LOOP;\nEND\n$backfill$;\nDROP INDEX IF EXISTS supacloud_commands.execution_pending_recovery;\nALTER TABLE supacloud_commands.execution_receipts\n DROP COLUMN IF EXISTS lease_id,\n DROP COLUMN IF EXISTS lease_until,\n DROP COLUMN IF EXISTS next_attempt_at,\n DROP COLUMN IF EXISTS recovery_attempts;\n";
4
+ export declare const COMMAND_PERSISTENCE_UPGRADE_SQL = "\nALTER TABLE supacloud_commands.execution_receipts\n ADD COLUMN IF NOT EXISTS input_fingerprint text,\n ADD COLUMN IF NOT EXISTS input_payload text;\nDO $migration$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='supacloud_commands'\n AND table_name='execution_receipts' AND column_name='input_key') THEN\n EXECUTE 'UPDATE supacloud_commands.execution_receipts\n SET input_fingerprint=encode(sha256(convert_to(input_key,''UTF8'')),''hex''),input_payload=input_key\n WHERE input_fingerprint IS NULL';\n ALTER TABLE supacloud_commands.execution_receipts DROP COLUMN input_key;\n END IF;\nEND\n$migration$;\nALTER TABLE supacloud_commands.execution_receipts ALTER COLUMN input_fingerprint SET NOT NULL;\nALTER TABLE supacloud_commands.execution_receipts\n DROP CONSTRAINT IF EXISTS execution_receipts_status_check,\n DROP CONSTRAINT IF EXISTS execution_receipts_check1,\n DROP CONSTRAINT IF EXISTS execution_receipts_transactional_check,\n DROP CONSTRAINT IF EXISTS execution_receipts_audit_terminal_check;\nALTER TABLE supacloud_commands.execution_receipts\n ADD CONSTRAINT execution_receipts_status_check CHECK (status IN ('pending','unknown','confirmed','rejected')),\n ADD CONSTRAINT execution_receipts_transactional_check CHECK (\n kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete')),\n ADD CONSTRAINT execution_receipts_audit_terminal_check CHECK (\n (audit_state <> 'complete' OR status IN ('confirmed','rejected'))\n AND (status <> 'rejected' OR audit_state = 'complete'));\nDO $constraint$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint\n WHERE conrelid='supacloud_commands.execution_receipts'::regclass\n AND conname='execution_receipts_input_fingerprint_check') THEN\n ALTER TABLE supacloud_commands.execution_receipts\n ADD CONSTRAINT execution_receipts_input_fingerprint_check CHECK (input_fingerprint ~ '^[a-f0-9]{64}$');\n END IF;\nEND\n$constraint$;\n\nDO $runtime$\nBEGIN\n IF to_regprocedure('supacloud_workflows.start_run(uuid,text,text,text,jsonb,integer)') IS NULL\n OR to_regprocedure('supacloud_commands.status(jsonb)') IS NULL THEN\n RAISE EXCEPTION 'Install the SupaCloud Commands/Workflow/PGMQ runtime before command persistence';\n END IF;\nEND\n$runtime$;\nCREATE SCHEMA IF NOT EXISTS supacloud_commands;\nREVOKE ALL ON SCHEMA supacloud_commands FROM PUBLIC;\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_receipts (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n kind text NOT NULL CHECK (kind IN ('transactional', 'external')),\n input_fingerprint text NOT NULL CHECK (input_fingerprint ~ '^[a-f0-9]{64}$'),\n input_payload text,\n dispatch_key uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE,\n status text NOT NULL CHECK (status IN ('pending', 'unknown', 'confirmed', 'rejected')),\n audit_state text NOT NULL CHECK (audit_state IN ('pending', 'complete')),\n result jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n CHECK ((status = 'confirmed') = (result IS NOT NULL)),\n CONSTRAINT execution_receipts_audit_terminal_check CHECK (\n (audit_state <> 'complete' OR status IN ('confirmed', 'rejected'))\n AND (status <> 'rejected' OR audit_state = 'complete')),\n CONSTRAINT execution_receipts_transactional_check CHECK (\n kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete'))\n);\nCREATE TABLE IF NOT EXISTS supacloud_commands.execution_audit (\n tenant_id text NOT NULL,\n actor_id text NOT NULL,\n command text NOT NULL,\n operation_key text NOT NULL,\n event text NOT NULL,\n details jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY (tenant_id, actor_id, command, operation_key),\n FOREIGN KEY (tenant_id, actor_id, command, operation_key)\n REFERENCES supacloud_commands.execution_receipts (tenant_id, actor_id, command, operation_key)\n);\nREVOKE ALL ON supacloud_commands.execution_receipts, supacloud_commands.execution_audit FROM PUBLIC;\nCREATE OR REPLACE FUNCTION supacloud_commands.protect_terminal_execution()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $terminal$\nBEGIN\n IF OLD.status IN ('confirmed','rejected') AND (\n NEW.status IS DISTINCT FROM OLD.status OR NEW.result IS DISTINCT FROM OLD.result\n OR (OLD.audit_state = 'complete' AND NEW.audit_state IS DISTINCT FROM OLD.audit_state)) THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_TERMINAL_RECEIPT';\n END IF;\n RETURN NEW;\nEND\n$terminal$;\nCREATE OR REPLACE TRIGGER execution_terminal_guard\nBEFORE UPDATE ON supacloud_commands.execution_receipts\nFOR EACH ROW EXECUTE FUNCTION supacloud_commands.protect_terminal_execution();\n\nCREATE OR REPLACE FUNCTION supacloud_commands.require_rejection_audit()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $rejection$\nBEGIN\n IF NEW.status = 'rejected' AND NOT EXISTS (\n SELECT FROM supacloud_commands.execution_audit a\n WHERE a.tenant_id=NEW.tenant_id AND a.actor_id=NEW.actor_id\n AND a.command=NEW.command AND a.operation_key=NEW.operation_key\n ) THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_REJECTION_AUDIT_REQUIRED';\n END IF;\n RETURN NEW;\nEND\n$rejection$;\nDROP TRIGGER IF EXISTS execution_rejection_audit ON supacloud_commands.execution_receipts;\nCREATE CONSTRAINT TRIGGER execution_rejection_audit\nAFTER INSERT OR UPDATE ON supacloud_commands.execution_receipts\nDEFERRABLE INITIALLY DEFERRED\nFOR EACH ROW WHEN (NEW.status = 'rejected')\nEXECUTE FUNCTION supacloud_commands.require_rejection_audit();\nCREATE OR REPLACE FUNCTION supacloud_commands.enqueue_execution_recovery()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $recovery$\nDECLARE submission jsonb;\nBEGIN\n PERFORM pg_advisory_xact_lock(hashtextextended(NEW.dispatch_key::text,0));\n SELECT supacloud_commands.snapshot(NEW.dispatch_key,false) INTO submission;\n IF submission IS NOT NULL THEN\n IF submission->>'commandType' IS DISTINCT FROM NEW.command\n OR submission->>'actorId' IS DISTINCT FROM NEW.actor_id\n OR submission->>'tenantId' IS DISTINCT FROM NEW.tenant_id\n OR NEW.operation_key <> NEW.dispatch_key::text THEN\n RAISE EXCEPTION 'SUPACLOUD_COMMAND_IDENTITY_CONFLICT';\n END IF;\n RETURN NEW;\n END IF;\n IF NEW.kind = 'external' AND NEW.status <> 'rejected'\n AND (NEW.status <> 'confirmed' OR NEW.audit_state <> 'complete') THEN\n PERFORM supacloud_workflows.start_run(\n NEW.dispatch_key, 'supacloud.command.reconcile', '1', 'reconcile',\n jsonb_build_object('commandId', NEW.dispatch_key, 'tenantId', NEW.tenant_id,\n 'actorId', NEW.actor_id, 'command', NEW.command, 'operationId', NEW.operation_key),\n 20\n );\n END IF;\n RETURN NEW;\nEND\n$recovery$;\nCREATE OR REPLACE TRIGGER execution_recovery_enqueue\nAFTER INSERT ON supacloud_commands.execution_receipts\nFOR EACH ROW EXECUTE FUNCTION supacloud_commands.enqueue_execution_recovery();\n\nCREATE OR REPLACE FUNCTION supacloud_commands.execution_status(request jsonb)\nRETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $status$\n SELECT jsonb_build_object('kind','execution','commandId',r.dispatch_key,\n 'execution',jsonb_build_object('tenantId',r.tenant_id,'actorId',r.actor_id,\n 'command',r.command,'operationId',r.operation_key,'dispatchKey',r.dispatch_key,\n 'status',r.status,'audit',r.audit_state)\n || CASE WHEN r.status='confirmed' THEN jsonb_build_object('result',r.result) ELSE '{}'::jsonb END,\n 'workflow',CASE WHEN w.id IS NULL THEN NULL ELSE jsonb_build_object('runId',w.id,'status',w.status) END)\n FROM supacloud_commands.execution_receipts r\n LEFT JOIN supacloud_workflows.runs w ON w.id=r.dispatch_key\n WHERE CASE WHEN request ? 'commandId' THEN r.dispatch_key::text=request->>'commandId'\n ELSE r.tenant_id=request->>'tenantId' AND r.actor_id=request->>'actorId'\n AND r.command=request->>'command' AND r.operation_key=request->>'operationId' END\n$status$;\nREVOKE ALL ON FUNCTION supacloud_commands.execution_status(jsonb) FROM PUBLIC;\n\nDO $backfill$\nDECLARE r record;\nBEGIN\n FOR r IN SELECT * FROM supacloud_commands.execution_receipts\n WHERE kind='external' AND status<>'rejected' AND (status<>'confirmed' OR audit_state<>'complete')\n AND NOT EXISTS(SELECT FROM supacloud_workflows.runs w WHERE w.id=dispatch_key)\n LOOP\n PERFORM supacloud_workflows.start_run(\n r.dispatch_key,'supacloud.command.reconcile','1','reconcile',\n jsonb_build_object('commandId',r.dispatch_key,'tenantId',r.tenant_id,\n 'actorId',r.actor_id,'command',r.command,'operationId',r.operation_key),20\n );\n END LOOP;\nEND\n$backfill$;\nDROP INDEX IF EXISTS supacloud_commands.execution_pending_recovery;\nALTER TABLE supacloud_commands.execution_receipts\n DROP COLUMN IF EXISTS lease_id,\n DROP COLUMN IF EXISTS lease_until,\n DROP COLUMN IF EXISTS next_attempt_at,\n DROP COLUMN IF EXISTS recovery_attempts;\n";
package/dist/index.js CHANGED
@@ -900,15 +900,18 @@ CREATE TABLE IF NOT EXISTS supacloud_commands.execution_receipts (
900
900
  input_fingerprint text NOT NULL CHECK (input_fingerprint ~ '^[a-f0-9]{64}$'),
901
901
  input_payload text,
902
902
  dispatch_key uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE,
903
- status text NOT NULL CHECK (status IN ('pending', 'unknown', 'confirmed')),
903
+ status text NOT NULL CHECK (status IN ('pending', 'unknown', 'confirmed', 'rejected')),
904
904
  audit_state text NOT NULL CHECK (audit_state IN ('pending', 'complete')),
905
905
  result jsonb,
906
906
  created_at timestamptz NOT NULL DEFAULT now(),
907
907
  updated_at timestamptz NOT NULL DEFAULT now(),
908
908
  PRIMARY KEY (tenant_id, actor_id, command, operation_key),
909
909
  CHECK ((status = 'confirmed') = (result IS NOT NULL)),
910
- CHECK (audit_state <> 'complete' OR status = 'confirmed'),
911
- CHECK (kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete'))
910
+ CONSTRAINT execution_receipts_audit_terminal_check CHECK (
911
+ (audit_state <> 'complete' OR status IN ('confirmed', 'rejected'))
912
+ AND (status <> 'rejected' OR audit_state = 'complete')),
913
+ CONSTRAINT execution_receipts_transactional_check CHECK (
914
+ kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete'))
912
915
  );
913
916
  CREATE TABLE IF NOT EXISTS supacloud_commands.execution_audit (
914
917
  tenant_id text NOT NULL,
@@ -923,6 +926,40 @@ CREATE TABLE IF NOT EXISTS supacloud_commands.execution_audit (
923
926
  REFERENCES supacloud_commands.execution_receipts (tenant_id, actor_id, command, operation_key)
924
927
  );
925
928
  REVOKE ALL ON supacloud_commands.execution_receipts, supacloud_commands.execution_audit FROM PUBLIC;
929
+ CREATE OR REPLACE FUNCTION supacloud_commands.protect_terminal_execution()
930
+ RETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $terminal$
931
+ BEGIN
932
+ IF OLD.status IN ('confirmed','rejected') AND (
933
+ NEW.status IS DISTINCT FROM OLD.status OR NEW.result IS DISTINCT FROM OLD.result
934
+ OR (OLD.audit_state = 'complete' AND NEW.audit_state IS DISTINCT FROM OLD.audit_state)) THEN
935
+ RAISE EXCEPTION 'SUPACLOUD_COMMAND_TERMINAL_RECEIPT';
936
+ END IF;
937
+ RETURN NEW;
938
+ END
939
+ $terminal$;
940
+ CREATE OR REPLACE TRIGGER execution_terminal_guard
941
+ BEFORE UPDATE ON supacloud_commands.execution_receipts
942
+ FOR EACH ROW EXECUTE FUNCTION supacloud_commands.protect_terminal_execution();
943
+
944
+ CREATE OR REPLACE FUNCTION supacloud_commands.require_rejection_audit()
945
+ RETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $rejection$
946
+ BEGIN
947
+ IF NEW.status = 'rejected' AND NOT EXISTS (
948
+ SELECT FROM supacloud_commands.execution_audit a
949
+ WHERE a.tenant_id=NEW.tenant_id AND a.actor_id=NEW.actor_id
950
+ AND a.command=NEW.command AND a.operation_key=NEW.operation_key
951
+ ) THEN
952
+ RAISE EXCEPTION 'SUPACLOUD_COMMAND_REJECTION_AUDIT_REQUIRED';
953
+ END IF;
954
+ RETURN NEW;
955
+ END
956
+ $rejection$;
957
+ DROP TRIGGER IF EXISTS execution_rejection_audit ON supacloud_commands.execution_receipts;
958
+ CREATE CONSTRAINT TRIGGER execution_rejection_audit
959
+ AFTER INSERT OR UPDATE ON supacloud_commands.execution_receipts
960
+ DEFERRABLE INITIALLY DEFERRED
961
+ FOR EACH ROW WHEN (NEW.status = 'rejected')
962
+ EXECUTE FUNCTION supacloud_commands.require_rejection_audit();
926
963
  CREATE OR REPLACE FUNCTION supacloud_commands.enqueue_execution_recovery()
927
964
  RETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $recovery$
928
965
  DECLARE submission jsonb;
@@ -938,7 +975,8 @@ BEGIN
938
975
  END IF;
939
976
  RETURN NEW;
940
977
  END IF;
941
- IF NEW.kind = 'external' AND (NEW.status <> 'confirmed' OR NEW.audit_state <> 'complete') THEN
978
+ IF NEW.kind = 'external' AND NEW.status <> 'rejected'
979
+ AND (NEW.status <> 'confirmed' OR NEW.audit_state <> 'complete') THEN
942
980
  PERFORM supacloud_workflows.start_run(
943
981
  NEW.dispatch_key, 'supacloud.command.reconcile', '1', 'reconcile',
944
982
  jsonb_build_object('commandId', NEW.dispatch_key, 'tenantId', NEW.tenant_id,
@@ -985,6 +1023,18 @@ BEGIN
985
1023
  END
986
1024
  $migration$;
987
1025
  ALTER TABLE supacloud_commands.execution_receipts ALTER COLUMN input_fingerprint SET NOT NULL;
1026
+ ALTER TABLE supacloud_commands.execution_receipts
1027
+ DROP CONSTRAINT IF EXISTS execution_receipts_status_check,
1028
+ DROP CONSTRAINT IF EXISTS execution_receipts_check1,
1029
+ DROP CONSTRAINT IF EXISTS execution_receipts_transactional_check,
1030
+ DROP CONSTRAINT IF EXISTS execution_receipts_audit_terminal_check;
1031
+ ALTER TABLE supacloud_commands.execution_receipts
1032
+ ADD CONSTRAINT execution_receipts_status_check CHECK (status IN ('pending','unknown','confirmed','rejected')),
1033
+ ADD CONSTRAINT execution_receipts_transactional_check CHECK (
1034
+ kind <> 'transactional' OR (status = 'confirmed' AND audit_state = 'complete')),
1035
+ ADD CONSTRAINT execution_receipts_audit_terminal_check CHECK (
1036
+ (audit_state <> 'complete' OR status IN ('confirmed','rejected'))
1037
+ AND (status <> 'rejected' OR audit_state = 'complete'));
988
1038
  DO $constraint$
989
1039
  BEGIN
990
1040
  IF NOT EXISTS (SELECT 1 FROM pg_constraint
@@ -1000,7 +1050,7 @@ DO $backfill$
1000
1050
  DECLARE r record;
1001
1051
  BEGIN
1002
1052
  FOR r IN SELECT * FROM supacloud_commands.execution_receipts
1003
- WHERE kind='external' AND (status<>'confirmed' OR audit_state<>'complete')
1053
+ WHERE kind='external' AND status<>'rejected' AND (status<>'confirmed' OR audit_state<>'complete')
1004
1054
  AND NOT EXISTS(SELECT FROM supacloud_workflows.runs w WHERE w.id=dispatch_key)
1005
1055
  LOOP
1006
1056
  PERFORM supacloud_workflows.start_run(
@@ -1192,7 +1242,7 @@ function createPostgresCommandStore(database, options = {}) {
1192
1242
  if (submission !== undefined) {
1193
1243
  const attempt = { stepId: submission.stepId, messageId: submission.messageId, attempt: submission.attempt, workerId: submission.workerId };
1194
1244
  const commandId = submission.commandId;
1195
- if (record.kind === "external") {
1245
+ if (record.kind === "external" && receipt.status !== "rejected") {
1196
1246
  await tx.query("SELECT public.supacloud_workflow_advance($1::text::jsonb)", [JSON.stringify({
1197
1247
  ...attempt,
1198
1248
  output: { commandId, status: "intent-recorded" },
@@ -1201,18 +1251,22 @@ function createPostgresCommandStore(database, options = {}) {
1201
1251
  nextMaxAttempts: 20
1202
1252
  })]);
1203
1253
  } else {
1204
- const output = { commandId, status: "confirmed", audit: "complete" };
1254
+ const output = { commandId, status: receipt.status, audit: "complete" };
1205
1255
  await tx.query("SELECT public.supacloud_workflow_complete($1::text::jsonb)", [JSON.stringify({ ...attempt, stepOutput: output, runOutput: output })]);
1206
1256
  }
1207
1257
  }
1208
1258
  },
1209
1259
  async confirm(ref, result) {
1210
1260
  await tx.query(`UPDATE supacloud_commands.execution_receipts SET status='confirmed',result=$5::text::jsonb,updated_at=now()
1211
- WHERE ${where} AND status<>'confirmed'`, [...keys2(ref), canonicalCommandJson(result)]);
1261
+ WHERE ${where} AND status IN ('pending','unknown')`, [...keys2(ref), canonicalCommandJson(result)]);
1212
1262
  },
1213
1263
  async markUnknown(ref) {
1214
1264
  await tx.query(`UPDATE supacloud_commands.execution_receipts SET status='unknown',updated_at=now()
1215
- WHERE ${where} AND status<>'confirmed'`, keys2(ref));
1265
+ WHERE ${where} AND status IN ('pending','unknown')`, keys2(ref));
1266
+ },
1267
+ async reject(ref) {
1268
+ await tx.query(`UPDATE supacloud_commands.execution_receipts SET status='rejected',audit_state='complete',updated_at=now()
1269
+ WHERE ${where} AND kind='external' AND status IN ('pending','unknown')`, keys2(ref));
1216
1270
  },
1217
1271
  async audit(ref, event, details) {
1218
1272
  await tx.query(`INSERT INTO supacloud_commands.execution_audit
@@ -1239,7 +1293,7 @@ function createPostgresCommandStore(database, options = {}) {
1239
1293
  async redactCompleted(options) {
1240
1294
  return transaction(async (tx) => rows(await tx.query(`WITH candidates AS (
1241
1295
  SELECT tenant_id,actor_id,command,operation_key FROM supacloud_commands.execution_receipts
1242
- WHERE ${selected} AND status='confirmed' AND audit_state='complete' AND input_payload IS NOT NULL
1296
+ WHERE ${selected} AND status IN ('confirmed','rejected') AND audit_state='complete' AND input_payload IS NOT NULL
1243
1297
  AND updated_at<to_timestamp($3::double precision/1000)
1244
1298
  ORDER BY updated_at LIMIT $4 FOR UPDATE SKIP LOCKED
1245
1299
  ) UPDATE supacloud_commands.execution_receipts r SET input_payload=NULL FROM candidates c
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/db",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "Database governance layer for SupaCloud: RLS policies, RPC functions and grants as first-class resources, with manifest/catalog reconciliation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "libpg-query": "18.1.4",
75
- "@supacloud/contracts": "0.5.1"
75
+ "@supacloud/contracts": "0.6.0"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "drizzle-orm": "1.0.0-rc.4"
@@ -83,6 +83,6 @@
83
83
  }
84
84
  },
85
85
  "overrides": {
86
- "@supacloud/contracts": "0.5.1"
86
+ "@supacloud/contracts": "0.6.0"
87
87
  }
88
88
  }