@ixo/decision-oracle 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +794 -2
- package/dist/act.d.ts +87 -0
- package/dist/act.d.ts.map +1 -0
- package/dist/act.js +20 -0
- package/dist/act.js.map +1 -0
- package/dist/app.d.ts +22 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +128 -0
- package/dist/app.js.map +1 -0
- package/dist/c2pa.wasm +0 -0
- package/dist/cli/commands/api.d.ts +50 -0
- package/dist/cli/commands/api.d.ts.map +1 -0
- package/dist/cli/commands/api.js +737 -0
- package/dist/cli/commands/api.js.map +1 -0
- package/dist/cli/commands/create-collection.d.ts +40 -0
- package/dist/cli/commands/create-collection.d.ts.map +1 -0
- package/dist/cli/commands/create-collection.js +318 -0
- package/dist/cli/commands/create-collection.js.map +1 -0
- package/dist/cli/commands/create-deed.d.ts +31 -0
- package/dist/cli/commands/create-deed.d.ts.map +1 -0
- package/dist/cli/commands/create-deed.js +208 -0
- package/dist/cli/commands/create-deed.js.map +1 -0
- package/dist/cli/commands/delegation.d.ts +26 -0
- package/dist/cli/commands/delegation.d.ts.map +1 -0
- package/dist/cli/commands/delegation.js +162 -0
- package/dist/cli/commands/delegation.js.map +1 -0
- package/dist/cli/commands/derive.d.ts +22 -0
- package/dist/cli/commands/derive.d.ts.map +1 -0
- package/dist/cli/commands/derive.js +53 -0
- package/dist/cli/commands/derive.js.map +1 -0
- package/dist/cli/commands/engine.d.ts +25 -0
- package/dist/cli/commands/engine.d.ts.map +1 -0
- package/dist/cli/commands/engine.js +107 -0
- package/dist/cli/commands/engine.js.map +1 -0
- package/dist/cli/commands/erase.d.ts +17 -0
- package/dist/cli/commands/erase.d.ts.map +1 -0
- package/dist/cli/commands/erase.js +117 -0
- package/dist/cli/commands/erase.js.map +1 -0
- package/dist/cli/commands/facts-run.d.ts +30 -0
- package/dist/cli/commands/facts-run.d.ts.map +1 -0
- package/dist/cli/commands/facts-run.js +409 -0
- package/dist/cli/commands/facts-run.js.map +1 -0
- package/dist/cli/commands/facts-scaffold.d.ts +22 -0
- package/dist/cli/commands/facts-scaffold.d.ts.map +1 -0
- package/dist/cli/commands/facts-scaffold.js +208 -0
- package/dist/cli/commands/facts-scaffold.js.map +1 -0
- package/dist/cli/commands/init.d.ts +18 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +34 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/login.d.ts +9 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/login.js +16 -0
- package/dist/cli/commands/login.js.map +1 -0
- package/dist/cli/commands/logout.d.ts +10 -0
- package/dist/cli/commands/logout.d.ts.map +1 -0
- package/dist/cli/commands/logout.js +28 -0
- package/dist/cli/commands/logout.js.map +1 -0
- package/dist/cli/commands/manifest.d.ts +12 -0
- package/dist/cli/commands/manifest.d.ts.map +1 -0
- package/dist/cli/commands/manifest.js +48 -0
- package/dist/cli/commands/manifest.js.map +1 -0
- package/dist/cli/commands/oracle-init.d.ts +48 -0
- package/dist/cli/commands/oracle-init.d.ts.map +1 -0
- package/dist/cli/commands/oracle-init.js +1122 -0
- package/dist/cli/commands/oracle-init.js.map +1 -0
- package/dist/cli/commands/org.d.ts +28 -0
- package/dist/cli/commands/org.d.ts.map +1 -0
- package/dist/cli/commands/org.js +309 -0
- package/dist/cli/commands/org.js.map +1 -0
- package/dist/cli/commands/protocol-review.d.ts +20 -0
- package/dist/cli/commands/protocol-review.d.ts.map +1 -0
- package/dist/cli/commands/protocol-review.js +162 -0
- package/dist/cli/commands/protocol-review.js.map +1 -0
- package/dist/cli/commands/publish-protocol.d.ts +43 -0
- package/dist/cli/commands/publish-protocol.d.ts.map +1 -0
- package/dist/cli/commands/publish-protocol.js +345 -0
- package/dist/cli/commands/publish-protocol.js.map +1 -0
- package/dist/cli/commands/register.d.ts +16 -0
- package/dist/cli/commands/register.d.ts.map +1 -0
- package/dist/cli/commands/register.js +54 -0
- package/dist/cli/commands/register.js.map +1 -0
- package/dist/cli/commands/relink.d.ts +11 -0
- package/dist/cli/commands/relink.d.ts.map +1 -0
- package/dist/cli/commands/relink.js +36 -0
- package/dist/cli/commands/relink.js.map +1 -0
- package/dist/cli/commands/rubric-fetch-form.d.ts +16 -0
- package/dist/cli/commands/rubric-fetch-form.d.ts.map +1 -0
- package/dist/cli/commands/rubric-fetch-form.js +83 -0
- package/dist/cli/commands/rubric-fetch-form.js.map +1 -0
- package/dist/cli/commands/rubric-validate.d.ts +72 -0
- package/dist/cli/commands/rubric-validate.d.ts.map +1 -0
- package/dist/cli/commands/rubric-validate.js +163 -0
- package/dist/cli/commands/rubric-validate.js.map +1 -0
- package/dist/cli/commands/scan.d.ts +13 -0
- package/dist/cli/commands/scan.d.ts.map +1 -0
- package/dist/cli/commands/scan.js +39 -0
- package/dist/cli/commands/scan.js.map +1 -0
- package/dist/cli/commands/skills.d.ts +11 -0
- package/dist/cli/commands/skills.d.ts.map +1 -0
- package/dist/cli/commands/skills.js +19 -0
- package/dist/cli/commands/skills.js.map +1 -0
- package/dist/cli/commands/submit-claim.d.ts +25 -0
- package/dist/cli/commands/submit-claim.d.ts.map +1 -0
- package/dist/cli/commands/submit-claim.js +155 -0
- package/dist/cli/commands/submit-claim.js.map +1 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +206 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/lib/agent-card-schema.d.ts +8 -0
- package/dist/cli/lib/agent-card-schema.d.ts.map +1 -0
- package/dist/cli/lib/agent-card-schema.js +169 -0
- package/dist/cli/lib/agent-card-schema.js.map +1 -0
- package/dist/cli/lib/ai-rest.d.ts +12 -0
- package/dist/cli/lib/ai-rest.d.ts.map +1 -0
- package/dist/cli/lib/ai-rest.js +36 -0
- package/dist/cli/lib/ai-rest.js.map +1 -0
- package/dist/cli/lib/args.d.ts +33 -0
- package/dist/cli/lib/args.d.ts.map +1 -0
- package/dist/cli/lib/args.js +24 -0
- package/dist/cli/lib/args.js.map +1 -0
- package/dist/cli/lib/authhub.d.ts +7 -0
- package/dist/cli/lib/authhub.d.ts.map +1 -0
- package/dist/cli/lib/authhub.js +210 -0
- package/dist/cli/lib/authhub.js.map +1 -0
- package/dist/cli/lib/chain.d.ts +264 -0
- package/dist/cli/lib/chain.d.ts.map +1 -0
- package/dist/cli/lib/chain.js +584 -0
- package/dist/cli/lib/chain.js.map +1 -0
- package/dist/cli/lib/devvars.d.ts +59 -0
- package/dist/cli/lib/devvars.d.ts.map +1 -0
- package/dist/cli/lib/devvars.js +206 -0
- package/dist/cli/lib/devvars.js.map +1 -0
- package/dist/cli/lib/engine.d.ts +54 -0
- package/dist/cli/lib/engine.d.ts.map +1 -0
- package/dist/cli/lib/engine.js +112 -0
- package/dist/cli/lib/engine.js.map +1 -0
- package/dist/cli/lib/identity-cards.d.ts +188 -0
- package/dist/cli/lib/identity-cards.d.ts.map +1 -0
- package/dist/cli/lib/identity-cards.js +261 -0
- package/dist/cli/lib/identity-cards.js.map +1 -0
- package/dist/cli/lib/matrix-account.d.ts +79 -0
- package/dist/cli/lib/matrix-account.d.ts.map +1 -0
- package/dist/cli/lib/matrix-account.js +228 -0
- package/dist/cli/lib/matrix-account.js.map +1 -0
- package/dist/cli/lib/oracle-account.d.ts +108 -0
- package/dist/cli/lib/oracle-account.d.ts.map +1 -0
- package/dist/cli/lib/oracle-account.js +207 -0
- package/dist/cli/lib/oracle-account.js.map +1 -0
- package/dist/cli/lib/project.d.ts +22 -0
- package/dist/cli/lib/project.d.ts.map +1 -0
- package/dist/cli/lib/project.js +62 -0
- package/dist/cli/lib/project.js.map +1 -0
- package/dist/cli/lib/session.d.ts +109 -0
- package/dist/cli/lib/session.d.ts.map +1 -0
- package/dist/cli/lib/session.js +354 -0
- package/dist/cli/lib/session.js.map +1 -0
- package/dist/cli/lib/workorder.d.ts +57 -0
- package/dist/cli/lib/workorder.d.ts.map +1 -0
- package/dist/cli/lib/workorder.js +101 -0
- package/dist/cli/lib/workorder.js.map +1 -0
- package/dist/config.d.ts +221 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +431 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +88 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +9 -0
- package/dist/context.js.map +1 -0
- package/dist/contracts/api.d.ts +3367 -0
- package/dist/contracts/api.d.ts.map +1 -0
- package/dist/contracts/api.js +1303 -0
- package/dist/contracts/api.js.map +1 -0
- package/dist/contracts/capabilities.d.ts +126 -0
- package/dist/contracts/capabilities.d.ts.map +1 -0
- package/dist/contracts/capabilities.js +164 -0
- package/dist/contracts/capabilities.js.map +1 -0
- package/dist/contracts/claim-source.d.ts +98 -0
- package/dist/contracts/claim-source.d.ts.map +1 -0
- package/dist/contracts/claim-source.js +17 -0
- package/dist/contracts/claim-source.js.map +1 -0
- package/dist/contracts/errors.d.ts +150 -0
- package/dist/contracts/errors.d.ts.map +1 -0
- package/dist/contracts/errors.js +121 -0
- package/dist/contracts/errors.js.map +1 -0
- package/dist/contracts/index.d.ts +15 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +11 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/payment-gate.d.ts +129 -0
- package/dist/contracts/payment-gate.d.ts.map +1 -0
- package/dist/contracts/payment-gate.js +24 -0
- package/dist/contracts/payment-gate.js.map +1 -0
- package/dist/contracts/start-api-claim.d.ts +90 -0
- package/dist/contracts/start-api-claim.d.ts.map +1 -0
- package/dist/contracts/start-api-claim.js +22 -0
- package/dist/contracts/start-api-claim.js.map +1 -0
- package/dist/contracts/webhooks.d.ts +1487 -0
- package/dist/contracts/webhooks.d.ts.map +1 -0
- package/dist/contracts/webhooks.js +71 -0
- package/dist/contracts/webhooks.js.map +1 -0
- package/dist/contracts/work-order.d.ts +29 -0
- package/dist/contracts/work-order.d.ts.map +1 -0
- package/dist/contracts/work-order.js +12 -0
- package/dist/contracts/work-order.js.map +1 -0
- package/dist/cron/ai-cost.d.ts +29 -0
- package/dist/cron/ai-cost.d.ts.map +1 -0
- package/dist/cron/ai-cost.js +80 -0
- package/dist/cron/ai-cost.js.map +1 -0
- package/dist/cron/api-lane.d.ts +39 -0
- package/dist/cron/api-lane.d.ts.map +1 -0
- package/dist/cron/api-lane.js +203 -0
- package/dist/cron/api-lane.js.map +1 -0
- package/dist/cron/backlog.d.ts +50 -0
- package/dist/cron/backlog.d.ts.map +1 -0
- package/dist/cron/backlog.js +115 -0
- package/dist/cron/backlog.js.map +1 -0
- package/dist/cron/billing.d.ts +11 -0
- package/dist/cron/billing.d.ts.map +1 -0
- package/dist/cron/billing.js +69 -0
- package/dist/cron/billing.js.map +1 -0
- package/dist/cron/collection.d.ts +50 -0
- package/dist/cron/collection.d.ts.map +1 -0
- package/dist/cron/collection.js +118 -0
- package/dist/cron/collection.js.map +1 -0
- package/dist/cron/funding.d.ts +16 -0
- package/dist/cron/funding.d.ts.map +1 -0
- package/dist/cron/funding.js +262 -0
- package/dist/cron/funding.js.map +1 -0
- package/dist/cron/payer-billing.d.ts +38 -0
- package/dist/cron/payer-billing.d.ts.map +1 -0
- package/dist/cron/payer-billing.js +119 -0
- package/dist/cron/payer-billing.js.map +1 -0
- package/dist/cron/scan.d.ts +43 -0
- package/dist/cron/scan.d.ts.map +1 -0
- package/dist/cron/scan.js +250 -0
- package/dist/cron/scan.js.map +1 -0
- package/dist/db/client.d.ts +14 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +14 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/index.d.ts +7 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +7 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +6738 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +1433 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/define-oracle.d.ts +32 -0
- package/dist/define-oracle.d.ts.map +1 -0
- package/dist/define-oracle.js +80 -0
- package/dist/define-oracle.js.map +1 -0
- package/dist/dev-oracle.d.ts +9 -0
- package/dist/dev-oracle.d.ts.map +1 -0
- package/dist/dev-oracle.js +19 -0
- package/dist/dev-oracle.js.map +1 -0
- package/dist/dev-worker.d.ts +10 -0
- package/dist/dev-worker.d.ts.map +1 -0
- package/dist/dev-worker.js +12 -0
- package/dist/dev-worker.js.map +1 -0
- package/dist/env.d.ts +146 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +10 -0
- package/dist/env.js.map +1 -0
- package/dist/facts/exif.d.ts +43 -0
- package/dist/facts/exif.d.ts.map +1 -0
- package/dist/facts/exif.js +224 -0
- package/dist/facts/exif.js.map +1 -0
- package/dist/facts/fact.d.ts +62 -0
- package/dist/facts/fact.d.ts.map +1 -0
- package/dist/facts/fact.js +105 -0
- package/dist/facts/fact.js.map +1 -0
- package/dist/facts/geo.d.ts +55 -0
- package/dist/facts/geo.d.ts.map +1 -0
- package/dist/facts/geo.js +267 -0
- package/dist/facts/geo.js.map +1 -0
- package/dist/facts/index.d.ts +31 -0
- package/dist/facts/index.d.ts.map +1 -0
- package/dist/facts/index.js +27 -0
- package/dist/facts/index.js.map +1 -0
- package/dist/facts/linked-doc.d.ts +60 -0
- package/dist/facts/linked-doc.d.ts.map +1 -0
- package/dist/facts/linked-doc.js +101 -0
- package/dist/facts/linked-doc.js.map +1 -0
- package/dist/facts/types.d.ts +278 -0
- package/dist/facts/types.d.ts.map +1 -0
- package/dist/facts/types.js +19 -0
- package/dist/facts/types.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-lane/accept.d.ts +29 -0
- package/dist/lib/api-lane/accept.d.ts.map +1 -0
- package/dist/lib/api-lane/accept.js +218 -0
- package/dist/lib/api-lane/accept.js.map +1 -0
- package/dist/lib/api-lane/claim-list.d.ts +44 -0
- package/dist/lib/api-lane/claim-list.d.ts.map +1 -0
- package/dist/lib/api-lane/claim-list.js +92 -0
- package/dist/lib/api-lane/claim-list.js.map +1 -0
- package/dist/lib/api-lane/company.d.ts +56 -0
- package/dist/lib/api-lane/company.d.ts.map +1 -0
- package/dist/lib/api-lane/company.js +103 -0
- package/dist/lib/api-lane/company.js.map +1 -0
- package/dist/lib/api-lane/events.d.ts +21 -0
- package/dist/lib/api-lane/events.d.ts.map +1 -0
- package/dist/lib/api-lane/events.js +111 -0
- package/dist/lib/api-lane/events.js.map +1 -0
- package/dist/lib/api-lane/ids.d.ts +39 -0
- package/dist/lib/api-lane/ids.d.ts.map +1 -0
- package/dist/lib/api-lane/ids.js +78 -0
- package/dist/lib/api-lane/ids.js.map +1 -0
- package/dist/lib/api-lane/index.d.ts +16 -0
- package/dist/lib/api-lane/index.d.ts.map +1 -0
- package/dist/lib/api-lane/index.js +16 -0
- package/dist/lib/api-lane/index.js.map +1 -0
- package/dist/lib/api-lane/linked.d.ts +264 -0
- package/dist/lib/api-lane/linked.d.ts.map +1 -0
- package/dist/lib/api-lane/linked.js +272 -0
- package/dist/lib/api-lane/linked.js.map +1 -0
- package/dist/lib/api-lane/media-type.d.ts +15 -0
- package/dist/lib/api-lane/media-type.d.ts.map +1 -0
- package/dist/lib/api-lane/media-type.js +73 -0
- package/dist/lib/api-lane/media-type.js.map +1 -0
- package/dist/lib/api-lane/member-emails.d.ts +83 -0
- package/dist/lib/api-lane/member-emails.d.ts.map +1 -0
- package/dist/lib/api-lane/member-emails.js +213 -0
- package/dist/lib/api-lane/member-emails.js.map +1 -0
- package/dist/lib/api-lane/members.d.ts +42 -0
- package/dist/lib/api-lane/members.d.ts.map +1 -0
- package/dist/lib/api-lane/members.js +75 -0
- package/dist/lib/api-lane/members.js.map +1 -0
- package/dist/lib/api-lane/notify.d.ts +47 -0
- package/dist/lib/api-lane/notify.d.ts.map +1 -0
- package/dist/lib/api-lane/notify.js +240 -0
- package/dist/lib/api-lane/notify.js.map +1 -0
- package/dist/lib/api-lane/pause.d.ts +41 -0
- package/dist/lib/api-lane/pause.d.ts.map +1 -0
- package/dist/lib/api-lane/pause.js +155 -0
- package/dist/lib/api-lane/pause.js.map +1 -0
- package/dist/lib/api-lane/record.d.ts +76 -0
- package/dist/lib/api-lane/record.d.ts.map +1 -0
- package/dist/lib/api-lane/record.js +337 -0
- package/dist/lib/api-lane/record.js.map +1 -0
- package/dist/lib/api-lane/retention.d.ts +43 -0
- package/dist/lib/api-lane/retention.d.ts.map +1 -0
- package/dist/lib/api-lane/retention.js +176 -0
- package/dist/lib/api-lane/retention.js.map +1 -0
- package/dist/lib/api-lane/review.d.ts +76 -0
- package/dist/lib/api-lane/review.d.ts.map +1 -0
- package/dist/lib/api-lane/review.js +355 -0
- package/dist/lib/api-lane/review.js.map +1 -0
- package/dist/lib/api-lane/reviewers.d.ts +109 -0
- package/dist/lib/api-lane/reviewers.d.ts.map +1 -0
- package/dist/lib/api-lane/reviewers.js +755 -0
- package/dist/lib/api-lane/reviewers.js.map +1 -0
- package/dist/lib/api-lane/source-delete.d.ts +16 -0
- package/dist/lib/api-lane/source-delete.d.ts.map +1 -0
- package/dist/lib/api-lane/source-delete.js +50 -0
- package/dist/lib/api-lane/source-delete.js.map +1 -0
- package/dist/lib/api-lane/source.d.ts +19 -0
- package/dist/lib/api-lane/source.d.ts.map +1 -0
- package/dist/lib/api-lane/source.js +226 -0
- package/dist/lib/api-lane/source.js.map +1 -0
- package/dist/lib/api-lane/submitter.d.ts +22 -0
- package/dist/lib/api-lane/submitter.d.ts.map +1 -0
- package/dist/lib/api-lane/submitter.js +34 -0
- package/dist/lib/api-lane/submitter.js.map +1 -0
- package/dist/lib/api-lane/timeline.d.ts +20 -0
- package/dist/lib/api-lane/timeline.d.ts.map +1 -0
- package/dist/lib/api-lane/timeline.js +23 -0
- package/dist/lib/api-lane/timeline.js.map +1 -0
- package/dist/lib/api-lane/webhook-crypto.d.ts +44 -0
- package/dist/lib/api-lane/webhook-crypto.d.ts.map +1 -0
- package/dist/lib/api-lane/webhook-crypto.js +103 -0
- package/dist/lib/api-lane/webhook-crypto.js.map +1 -0
- package/dist/lib/api-lane/webhooks.d.ts +117 -0
- package/dist/lib/api-lane/webhooks.d.ts.map +1 -0
- package/dist/lib/api-lane/webhooks.js +503 -0
- package/dist/lib/api-lane/webhooks.js.map +1 -0
- package/dist/lib/archive.d.ts +64 -0
- package/dist/lib/archive.d.ts.map +1 -0
- package/dist/lib/archive.js +305 -0
- package/dist/lib/archive.js.map +1 -0
- package/dist/lib/bech32.d.ts +8 -0
- package/dist/lib/bech32.d.ts.map +1 -0
- package/dist/lib/bech32.js +39 -0
- package/dist/lib/bech32.js.map +1 -0
- package/dist/lib/claim-erase.d.ts +22 -0
- package/dist/lib/claim-erase.d.ts.map +1 -0
- package/dist/lib/claim-erase.js +44 -0
- package/dist/lib/claim-erase.js.map +1 -0
- package/dist/lib/cursor.d.ts +11 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +20 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/email/send.d.ts +43 -0
- package/dist/lib/email/send.d.ts.map +1 -0
- package/dist/lib/email/send.js +71 -0
- package/dist/lib/email/send.js.map +1 -0
- package/dist/lib/email/template.d.ts +217 -0
- package/dist/lib/email/template.d.ts.map +1 -0
- package/dist/lib/email/template.js +713 -0
- package/dist/lib/email/template.js.map +1 -0
- package/dist/lib/engine/adr36.d.ts +56 -0
- package/dist/lib/engine/adr36.d.ts.map +1 -0
- package/dist/lib/engine/adr36.js +76 -0
- package/dist/lib/engine/adr36.js.map +1 -0
- package/dist/lib/engine/client.d.ts +162 -0
- package/dist/lib/engine/client.d.ts.map +1 -0
- package/dist/lib/engine/client.js +473 -0
- package/dist/lib/engine/client.js.map +1 -0
- package/dist/lib/engine/types.d.ts +1356 -0
- package/dist/lib/engine/types.d.ts.map +1 -0
- package/dist/lib/engine/types.js +562 -0
- package/dist/lib/engine/types.js.map +1 -0
- package/dist/lib/errors.d.ts +73 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +96 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/facts/builder.d.ts +88 -0
- package/dist/lib/facts/builder.d.ts.map +1 -0
- package/dist/lib/facts/builder.js +239 -0
- package/dist/lib/facts/builder.js.map +1 -0
- package/dist/lib/facts/ctx.d.ts +34 -0
- package/dist/lib/facts/ctx.d.ts.map +1 -0
- package/dist/lib/facts/ctx.js +51 -0
- package/dist/lib/facts/ctx.js.map +1 -0
- package/dist/lib/facts/expected.d.ts +23 -0
- package/dist/lib/facts/expected.d.ts.map +1 -0
- package/dist/lib/facts/expected.js +16 -0
- package/dist/lib/facts/expected.js.map +1 -0
- package/dist/lib/facts/fact-cache.d.ts +469 -0
- package/dist/lib/facts/fact-cache.d.ts.map +1 -0
- package/dist/lib/facts/fact-cache.js +52 -0
- package/dist/lib/facts/fact-cache.js.map +1 -0
- package/dist/lib/facts/factset.d.ts +608 -0
- package/dist/lib/facts/factset.d.ts.map +1 -0
- package/dist/lib/facts/factset.js +226 -0
- package/dist/lib/facts/factset.js.map +1 -0
- package/dist/lib/facts/producer.d.ts +190 -0
- package/dist/lib/facts/producer.d.ts.map +1 -0
- package/dist/lib/facts/producer.js +15 -0
- package/dist/lib/facts/producer.js.map +1 -0
- package/dist/lib/facts/runner.d.ts +111 -0
- package/dist/lib/facts/runner.d.ts.map +1 -0
- package/dist/lib/facts/runner.js +438 -0
- package/dist/lib/facts/runner.js.map +1 -0
- package/dist/lib/facts/stock/ai-check.d.ts +100 -0
- package/dist/lib/facts/stock/ai-check.d.ts.map +1 -0
- package/dist/lib/facts/stock/ai-check.js +526 -0
- package/dist/lib/facts/stock/ai-check.js.map +1 -0
- package/dist/lib/facts/stock/ai-inputs.d.ts +104 -0
- package/dist/lib/facts/stock/ai-inputs.d.ts.map +1 -0
- package/dist/lib/facts/stock/ai-inputs.js +332 -0
- package/dist/lib/facts/stock/ai-inputs.js.map +1 -0
- package/dist/lib/facts/stock/ai-provider.d.ts +105 -0
- package/dist/lib/facts/stock/ai-provider.d.ts.map +1 -0
- package/dist/lib/facts/stock/ai-provider.js +250 -0
- package/dist/lib/facts/stock/ai-provider.js.map +1 -0
- package/dist/lib/facts/stock/ai-unique.d.ts +85 -0
- package/dist/lib/facts/stock/ai-unique.d.ts.map +1 -0
- package/dist/lib/facts/stock/ai-unique.js +208 -0
- package/dist/lib/facts/stock/ai-unique.js.map +1 -0
- package/dist/lib/facts/stock/archive.d.ts +63 -0
- package/dist/lib/facts/stock/archive.d.ts.map +1 -0
- package/dist/lib/facts/stock/archive.js +349 -0
- package/dist/lib/facts/stock/archive.js.map +1 -0
- package/dist/lib/facts/stock/c2pa-trust-list.d.ts +16 -0
- package/dist/lib/facts/stock/c2pa-trust-list.d.ts.map +1 -0
- package/dist/lib/facts/stock/c2pa-trust-list.js +637 -0
- package/dist/lib/facts/stock/c2pa-trust-list.js.map +1 -0
- package/dist/lib/facts/stock/c2pa.d.ts +56 -0
- package/dist/lib/facts/stock/c2pa.d.ts.map +1 -0
- package/dist/lib/facts/stock/c2pa.js +234 -0
- package/dist/lib/facts/stock/c2pa.js.map +1 -0
- package/dist/lib/facts/stock/call.d.ts +91 -0
- package/dist/lib/facts/stock/call.d.ts.map +1 -0
- package/dist/lib/facts/stock/call.js +281 -0
- package/dist/lib/facts/stock/call.js.map +1 -0
- package/dist/lib/facts/stock/capability.d.ts +39 -0
- package/dist/lib/facts/stock/capability.d.ts.map +1 -0
- package/dist/lib/facts/stock/capability.js +59 -0
- package/dist/lib/facts/stock/capability.js.map +1 -0
- package/dist/lib/facts/stock/ext-source.d.ts +51 -0
- package/dist/lib/facts/stock/ext-source.d.ts.map +1 -0
- package/dist/lib/facts/stock/ext-source.js +201 -0
- package/dist/lib/facts/stock/ext-source.js.map +1 -0
- package/dist/lib/facts/stock/frequency-fact.d.ts +59 -0
- package/dist/lib/facts/stock/frequency-fact.d.ts.map +1 -0
- package/dist/lib/facts/stock/frequency-fact.js +86 -0
- package/dist/lib/facts/stock/frequency-fact.js.map +1 -0
- package/dist/lib/facts/stock/frequency.d.ts +32 -0
- package/dist/lib/facts/stock/frequency.d.ts.map +1 -0
- package/dist/lib/facts/stock/frequency.js +48 -0
- package/dist/lib/facts/stock/frequency.js.map +1 -0
- package/dist/lib/facts/stock/index.d.ts +27 -0
- package/dist/lib/facts/stock/index.d.ts.map +1 -0
- package/dist/lib/facts/stock/index.js +28 -0
- package/dist/lib/facts/stock/index.js.map +1 -0
- package/dist/lib/facts/stock/normalize.d.ts +45 -0
- package/dist/lib/facts/stock/normalize.d.ts.map +1 -0
- package/dist/lib/facts/stock/normalize.js +135 -0
- package/dist/lib/facts/stock/normalize.js.map +1 -0
- package/dist/lib/facts/stock/phash.d.ts +55 -0
- package/dist/lib/facts/stock/phash.d.ts.map +1 -0
- package/dist/lib/facts/stock/phash.js +256 -0
- package/dist/lib/facts/stock/phash.js.map +1 -0
- package/dist/lib/facts/stock/rule-defaults.d.ts +72 -0
- package/dist/lib/facts/stock/rule-defaults.d.ts.map +1 -0
- package/dist/lib/facts/stock/rule-defaults.js +55 -0
- package/dist/lib/facts/stock/rule-defaults.js.map +1 -0
- package/dist/lib/facts/stock/send.d.ts +52 -0
- package/dist/lib/facts/stock/send.d.ts.map +1 -0
- package/dist/lib/facts/stock/send.js +148 -0
- package/dist/lib/facts/stock/send.js.map +1 -0
- package/dist/lib/facts/stock/unique-score.d.ts +138 -0
- package/dist/lib/facts/stock/unique-score.d.ts.map +1 -0
- package/dist/lib/facts/stock/unique-score.js +257 -0
- package/dist/lib/facts/stock/unique-score.js.map +1 -0
- package/dist/lib/facts/stock/unique-store.d.ts +420 -0
- package/dist/lib/facts/stock/unique-store.d.ts.map +1 -0
- package/dist/lib/facts/stock/unique-store.js +328 -0
- package/dist/lib/facts/stock/unique-store.js.map +1 -0
- package/dist/lib/facts/stock/unique.d.ts +35 -0
- package/dist/lib/facts/stock/unique.d.ts.map +1 -0
- package/dist/lib/facts/stock/unique.js +327 -0
- package/dist/lib/facts/stock/unique.js.map +1 -0
- package/dist/lib/facts/tools.d.ts +57 -0
- package/dist/lib/facts/tools.d.ts.map +1 -0
- package/dist/lib/facts/tools.js +325 -0
- package/dist/lib/facts/tools.js.map +1 -0
- package/dist/lib/facts/validate.d.ts +33 -0
- package/dist/lib/facts/validate.d.ts.map +1 -0
- package/dist/lib/facts/validate.js +137 -0
- package/dist/lib/facts/validate.js.map +1 -0
- package/dist/lib/hash.d.ts +44 -0
- package/dist/lib/hash.d.ts.map +1 -0
- package/dist/lib/hash.js +80 -0
- package/dist/lib/hash.js.map +1 -0
- package/dist/lib/http/client.d.ts +113 -0
- package/dist/lib/http/client.d.ts.map +1 -0
- package/dist/lib/http/client.js +330 -0
- package/dist/lib/http/client.js.map +1 -0
- package/dist/lib/ids.d.ts +17 -0
- package/dist/lib/ids.d.ts.map +1 -0
- package/dist/lib/ids.js +26 -0
- package/dist/lib/ids.js.map +1 -0
- package/dist/lib/ixo/attachments.d.ts +116 -0
- package/dist/lib/ixo/attachments.d.ts.map +1 -0
- package/dist/lib/ixo/attachments.js +290 -0
- package/dist/lib/ixo/attachments.js.map +1 -0
- package/dist/lib/ixo/authz.d.ts +40 -0
- package/dist/lib/ixo/authz.d.ts.map +1 -0
- package/dist/lib/ixo/authz.js +113 -0
- package/dist/lib/ixo/authz.js.map +1 -0
- package/dist/lib/ixo/blocksync/index.d.ts +90 -0
- package/dist/lib/ixo/blocksync/index.d.ts.map +1 -0
- package/dist/lib/ixo/blocksync/index.js +251 -0
- package/dist/lib/ixo/blocksync/index.js.map +1 -0
- package/dist/lib/ixo/blocksync/queries.d.ts +15 -0
- package/dist/lib/ixo/blocksync/queries.d.ts.map +1 -0
- package/dist/lib/ixo/blocksync/queries.js +144 -0
- package/dist/lib/ixo/blocksync/queries.js.map +1 -0
- package/dist/lib/ixo/blocksync/types.d.ts +184 -0
- package/dist/lib/ixo/blocksync/types.d.ts.map +1 -0
- package/dist/lib/ixo/blocksync/types.js +108 -0
- package/dist/lib/ixo/blocksync/types.js.map +1 -0
- package/dist/lib/ixo/cellnode.d.ts +35 -0
- package/dist/lib/ixo/cellnode.d.ts.map +1 -0
- package/dist/lib/ixo/cellnode.js +43 -0
- package/dist/lib/ixo/cellnode.js.map +1 -0
- package/dist/lib/ixo/chain-write.d.ts +130 -0
- package/dist/lib/ixo/chain-write.d.ts.map +1 -0
- package/dist/lib/ixo/chain-write.js +460 -0
- package/dist/lib/ixo/chain-write.js.map +1 -0
- package/dist/lib/ixo/chain.d.ts +1046 -0
- package/dist/lib/ixo/chain.d.ts.map +1 -0
- package/dist/lib/ixo/chain.js +279 -0
- package/dist/lib/ixo/chain.js.map +1 -0
- package/dist/lib/ixo/claim-bot.d.ts +49 -0
- package/dist/lib/ixo/claim-bot.d.ts.map +1 -0
- package/dist/lib/ixo/claim-bot.js +141 -0
- package/dist/lib/ixo/claim-bot.js.map +1 -0
- package/dist/lib/ixo/delegation-verify.d.ts +44 -0
- package/dist/lib/ixo/delegation-verify.d.ts.map +1 -0
- package/dist/lib/ixo/delegation-verify.js +101 -0
- package/dist/lib/ixo/delegation-verify.js.map +1 -0
- package/dist/lib/ixo/did.d.ts +13 -0
- package/dist/lib/ixo/did.d.ts.map +1 -0
- package/dist/lib/ixo/did.js +85 -0
- package/dist/lib/ixo/did.js.map +1 -0
- package/dist/lib/ixo/grant-chain.d.ts +55 -0
- package/dist/lib/ixo/grant-chain.d.ts.map +1 -0
- package/dist/lib/ixo/grant-chain.js +185 -0
- package/dist/lib/ixo/grant-chain.js.map +1 -0
- package/dist/lib/ixo/identity.d.ts +32 -0
- package/dist/lib/ixo/identity.d.ts.map +1 -0
- package/dist/lib/ixo/identity.js +104 -0
- package/dist/lib/ixo/identity.js.map +1 -0
- package/dist/lib/ixo/index.d.ts +118 -0
- package/dist/lib/ixo/index.d.ts.map +1 -0
- package/dist/lib/ixo/index.js +395 -0
- package/dist/lib/ixo/index.js.map +1 -0
- package/dist/lib/ixo/payment.d.ts +104 -0
- package/dist/lib/ixo/payment.d.ts.map +1 -0
- package/dist/lib/ixo/payment.js +136 -0
- package/dist/lib/ixo/payment.js.map +1 -0
- package/dist/lib/ixo/ucan-store.d.ts +30 -0
- package/dist/lib/ixo/ucan-store.d.ts.map +1 -0
- package/dist/lib/ixo/ucan-store.js +134 -0
- package/dist/lib/ixo/ucan-store.js.map +1 -0
- package/dist/lib/ixo/ucan.d.ts +96 -0
- package/dist/lib/ixo/ucan.d.ts.map +1 -0
- package/dist/lib/ixo/ucan.js +216 -0
- package/dist/lib/ixo/ucan.js.map +1 -0
- package/dist/lib/ixo/verified-read.d.ts +43 -0
- package/dist/lib/ixo/verified-read.d.ts.map +1 -0
- package/dist/lib/ixo/verified-read.js +73 -0
- package/dist/lib/ixo/verified-read.js.map +1 -0
- package/dist/lib/ixo/vfs.d.ts +27 -0
- package/dist/lib/ixo/vfs.d.ts.map +1 -0
- package/dist/lib/ixo/vfs.js +42 -0
- package/dist/lib/ixo/vfs.js.map +1 -0
- package/dist/lib/ixo/web-did.d.ts +7 -0
- package/dist/lib/ixo/web-did.d.ts.map +1 -0
- package/dist/lib/ixo/web-did.js +9 -0
- package/dist/lib/ixo/web-did.js.map +1 -0
- package/dist/lib/logger.d.ts +34 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +126 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/matrix/api.d.ts +57 -0
- package/dist/lib/matrix/api.d.ts.map +1 -0
- package/dist/lib/matrix/api.js +58 -0
- package/dist/lib/matrix/api.js.map +1 -0
- package/dist/lib/matrix/client.d.ts +41 -0
- package/dist/lib/matrix/client.d.ts.map +1 -0
- package/dist/lib/matrix/client.js +104 -0
- package/dist/lib/matrix/client.js.map +1 -0
- package/dist/lib/matrix/deliver.d.ts +224 -0
- package/dist/lib/matrix/deliver.d.ts.map +1 -0
- package/dist/lib/matrix/deliver.js +788 -0
- package/dist/lib/matrix/deliver.js.map +1 -0
- package/dist/lib/matrix/events.d.ts +114 -0
- package/dist/lib/matrix/events.d.ts.map +1 -0
- package/dist/lib/matrix/events.js +143 -0
- package/dist/lib/matrix/events.js.map +1 -0
- package/dist/lib/matrix/mxid.d.ts +24 -0
- package/dist/lib/matrix/mxid.d.ts.map +1 -0
- package/dist/lib/matrix/mxid.js +47 -0
- package/dist/lib/matrix/mxid.js.map +1 -0
- package/dist/lib/metrics.d.ts +105 -0
- package/dist/lib/metrics.d.ts.map +1 -0
- package/dist/lib/metrics.js +204 -0
- package/dist/lib/metrics.js.map +1 -0
- package/dist/lib/oauth/approvals.d.ts +160 -0
- package/dist/lib/oauth/approvals.d.ts.map +1 -0
- package/dist/lib/oauth/approvals.js +273 -0
- package/dist/lib/oauth/approvals.js.map +1 -0
- package/dist/lib/oauth/standing.d.ts +152 -0
- package/dist/lib/oauth/standing.d.ts.map +1 -0
- package/dist/lib/oauth/standing.js +299 -0
- package/dist/lib/oauth/standing.js.map +1 -0
- package/dist/lib/oauth/token.d.ts +60 -0
- package/dist/lib/oauth/token.d.ts.map +1 -0
- package/dist/lib/oauth/token.js +129 -0
- package/dist/lib/oauth/token.js.map +1 -0
- package/dist/lib/payments/extend.d.ts +42 -0
- package/dist/lib/payments/extend.d.ts.map +1 -0
- package/dist/lib/payments/extend.js +98 -0
- package/dist/lib/payments/extend.js.map +1 -0
- package/dist/lib/payments/facilitator.d.ts +220 -0
- package/dist/lib/payments/facilitator.d.ts.map +1 -0
- package/dist/lib/payments/facilitator.js +451 -0
- package/dist/lib/payments/facilitator.js.map +1 -0
- package/dist/lib/payments/gate.d.ts +207 -0
- package/dist/lib/payments/gate.d.ts.map +1 -0
- package/dist/lib/payments/gate.js +481 -0
- package/dist/lib/payments/gate.js.map +1 -0
- package/dist/lib/payments/header-seal.d.ts +33 -0
- package/dist/lib/payments/header-seal.d.ts.map +1 -0
- package/dist/lib/payments/header-seal.js +76 -0
- package/dist/lib/payments/header-seal.js.map +1 -0
- package/dist/lib/payments/index.d.ts +12 -0
- package/dist/lib/payments/index.d.ts.map +1 -0
- package/dist/lib/payments/index.js +11 -0
- package/dist/lib/payments/index.js.map +1 -0
- package/dist/lib/payments/price.d.ts +25 -0
- package/dist/lib/payments/price.d.ts.map +1 -0
- package/dist/lib/payments/price.js +43 -0
- package/dist/lib/payments/price.js.map +1 -0
- package/dist/lib/payments/reconcile.d.ts +77 -0
- package/dist/lib/payments/reconcile.d.ts.map +1 -0
- package/dist/lib/payments/reconcile.js +317 -0
- package/dist/lib/payments/reconcile.js.map +1 -0
- package/dist/lib/payments/refund.d.ts +34 -0
- package/dist/lib/payments/refund.d.ts.map +1 -0
- package/dist/lib/payments/refund.js +123 -0
- package/dist/lib/payments/refund.js.map +1 -0
- package/dist/lib/payments/review-billing.d.ts +222 -0
- package/dist/lib/payments/review-billing.d.ts.map +1 -0
- package/dist/lib/payments/review-billing.js +609 -0
- package/dist/lib/payments/review-billing.js.map +1 -0
- package/dist/lib/payments/settle.d.ts +44 -0
- package/dist/lib/payments/settle.d.ts.map +1 -0
- package/dist/lib/payments/settle.js +306 -0
- package/dist/lib/payments/settle.js.map +1 -0
- package/dist/lib/payments/terms.d.ts +27 -0
- package/dist/lib/payments/terms.d.ts.map +1 -0
- package/dist/lib/payments/terms.js +21 -0
- package/dist/lib/payments/terms.js.map +1 -0
- package/dist/lib/payouts.d.ts +20 -0
- package/dist/lib/payouts.d.ts.map +1 -0
- package/dist/lib/payouts.js +30 -0
- package/dist/lib/payouts.js.map +1 -0
- package/dist/lib/readiness.d.ts +42 -0
- package/dist/lib/readiness.d.ts.map +1 -0
- package/dist/lib/readiness.js +130 -0
- package/dist/lib/readiness.js.map +1 -0
- package/dist/lib/redact.d.ts +23 -0
- package/dist/lib/redact.d.ts.map +1 -0
- package/dist/lib/redact.js +67 -0
- package/dist/lib/redact.js.map +1 -0
- package/dist/lib/register.d.ts +85 -0
- package/dist/lib/register.d.ts.map +1 -0
- package/dist/lib/register.js +390 -0
- package/dist/lib/register.js.map +1 -0
- package/dist/lib/review/attestation.d.ts +92 -0
- package/dist/lib/review/attestation.d.ts.map +1 -0
- package/dist/lib/review/attestation.js +264 -0
- package/dist/lib/review/attestation.js.map +1 -0
- package/dist/lib/review/reviewer-grant.d.ts +146 -0
- package/dist/lib/review/reviewer-grant.d.ts.map +1 -0
- package/dist/lib/review/reviewer-grant.js +359 -0
- package/dist/lib/review/reviewer-grant.js.map +1 -0
- package/dist/lib/review/tasks.d.ts +18 -0
- package/dist/lib/review/tasks.d.ts.map +1 -0
- package/dist/lib/review/tasks.js +36 -0
- package/dist/lib/review/tasks.js.map +1 -0
- package/dist/lib/sentry.d.ts +89 -0
- package/dist/lib/sentry.d.ts.map +1 -0
- package/dist/lib/sentry.js +284 -0
- package/dist/lib/sentry.js.map +1 -0
- package/dist/lib/spans.d.ts +14 -0
- package/dist/lib/spans.d.ts.map +1 -0
- package/dist/lib/spans.js +28 -0
- package/dist/lib/spans.js.map +1 -0
- package/dist/lib/tracing.d.ts +31 -0
- package/dist/lib/tracing.d.ts.map +1 -0
- package/dist/lib/tracing.js +66 -0
- package/dist/lib/tracing.js.map +1 -0
- package/dist/lib/ttl-cache.d.ts +26 -0
- package/dist/lib/ttl-cache.d.ts.map +1 -0
- package/dist/lib/ttl-cache.js +61 -0
- package/dist/lib/ttl-cache.js.map +1 -0
- package/dist/lib/validator.d.ts +19 -0
- package/dist/lib/validator.d.ts.map +1 -0
- package/dist/lib/validator.js +32 -0
- package/dist/lib/validator.js.map +1 -0
- package/dist/lib/work-order/form.d.ts +40 -0
- package/dist/lib/work-order/form.d.ts.map +1 -0
- package/dist/lib/work-order/form.js +316 -0
- package/dist/lib/work-order/form.js.map +1 -0
- package/dist/lib/work-order/index.d.ts +20 -0
- package/dist/lib/work-order/index.d.ts.map +1 -0
- package/dist/lib/work-order/index.js +66 -0
- package/dist/lib/work-order/index.js.map +1 -0
- package/dist/middleware/api/audit.d.ts +9 -0
- package/dist/middleware/api/audit.d.ts.map +1 -0
- package/dist/middleware/api/audit.js +38 -0
- package/dist/middleware/api/audit.js.map +1 -0
- package/dist/middleware/api/auth.d.ts +29 -0
- package/dist/middleware/api/auth.d.ts.map +1 -0
- package/dist/middleware/api/auth.js +105 -0
- package/dist/middleware/api/auth.js.map +1 -0
- package/dist/middleware/api/console.d.ts +92 -0
- package/dist/middleware/api/console.d.ts.map +1 -0
- package/dist/middleware/api/console.js +446 -0
- package/dist/middleware/api/console.js.map +1 -0
- package/dist/middleware/api/errors.d.ts +48 -0
- package/dist/middleware/api/errors.d.ts.map +1 -0
- package/dist/middleware/api/errors.js +133 -0
- package/dist/middleware/api/errors.js.map +1 -0
- package/dist/middleware/api/idempotency.d.ts +23 -0
- package/dist/middleware/api/idempotency.d.ts.map +1 -0
- package/dist/middleware/api/idempotency.js +158 -0
- package/dist/middleware/api/idempotency.js.map +1 -0
- package/dist/middleware/api/keys.d.ts +14 -0
- package/dist/middleware/api/keys.d.ts.map +1 -0
- package/dist/middleware/api/keys.js +66 -0
- package/dist/middleware/api/keys.js.map +1 -0
- package/dist/middleware/api/membership.d.ts +32 -0
- package/dist/middleware/api/membership.d.ts.map +1 -0
- package/dist/middleware/api/membership.js +48 -0
- package/dist/middleware/api/membership.js.map +1 -0
- package/dist/middleware/api/oauth.d.ts +28 -0
- package/dist/middleware/api/oauth.d.ts.map +1 -0
- package/dist/middleware/api/oauth.js +109 -0
- package/dist/middleware/api/oauth.js.map +1 -0
- package/dist/middleware/api/rate-limit.d.ts +23 -0
- package/dist/middleware/api/rate-limit.d.ts.map +1 -0
- package/dist/middleware/api/rate-limit.js +70 -0
- package/dist/middleware/api/rate-limit.js.map +1 -0
- package/dist/middleware/api/types.d.ts +92 -0
- package/dist/middleware/api/types.d.ts.map +1 -0
- package/dist/middleware/api/types.js +7 -0
- package/dist/middleware/api/types.js.map +1 -0
- package/dist/middleware/api/wait.d.ts +21 -0
- package/dist/middleware/api/wait.d.ts.map +1 -0
- package/dist/middleware/api/wait.js +85 -0
- package/dist/middleware/api/wait.js.map +1 -0
- package/dist/middleware/capability.d.ts +32 -0
- package/dist/middleware/capability.d.ts.map +1 -0
- package/dist/middleware/capability.js +113 -0
- package/dist/middleware/capability.js.map +1 -0
- package/dist/middleware/database.d.ts +14 -0
- package/dist/middleware/database.d.ts.map +1 -0
- package/dist/middleware/database.js +18 -0
- package/dist/middleware/database.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +13 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +127 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/observability.d.ts +32 -0
- package/dist/middleware/observability.d.ts.map +1 -0
- package/dist/middleware/observability.js +134 -0
- package/dist/middleware/observability.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +16 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +56 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/middleware/ucan-auth.d.ts +39 -0
- package/dist/middleware/ucan-auth.d.ts.map +1 -0
- package/dist/middleware/ucan-auth.js +278 -0
- package/dist/middleware/ucan-auth.js.map +1 -0
- package/dist/networks.d.ts +34 -0
- package/dist/networks.d.ts.map +1 -0
- package/dist/networks.js +49 -0
- package/dist/networks.js.map +1 -0
- package/dist/oracle.d.ts +193 -0
- package/dist/oracle.d.ts.map +1 -0
- package/dist/oracle.js +245 -0
- package/dist/oracle.js.map +1 -0
- package/dist/routes/health.d.ts +16 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +29 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/v1/admin.d.ts +18 -0
- package/dist/routes/v1/admin.d.ts.map +1 -0
- package/dist/routes/v1/admin.js +101 -0
- package/dist/routes/v1/admin.js.map +1 -0
- package/dist/routes/v1/api/admin-claims.d.ts +14 -0
- package/dist/routes/v1/api/admin-claims.d.ts.map +1 -0
- package/dist/routes/v1/api/admin-claims.js +82 -0
- package/dist/routes/v1/api/admin-claims.js.map +1 -0
- package/dist/routes/v1/api/admin-facilitator.d.ts +20 -0
- package/dist/routes/v1/api/admin-facilitator.d.ts.map +1 -0
- package/dist/routes/v1/api/admin-facilitator.js +64 -0
- package/dist/routes/v1/api/admin-facilitator.js.map +1 -0
- package/dist/routes/v1/api/admin.d.ts +9 -0
- package/dist/routes/v1/api/admin.d.ts.map +1 -0
- package/dist/routes/v1/api/admin.js +110 -0
- package/dist/routes/v1/api/admin.js.map +1 -0
- package/dist/routes/v1/api/audit.d.ts +8 -0
- package/dist/routes/v1/api/audit.d.ts.map +1 -0
- package/dist/routes/v1/api/audit.js +56 -0
- package/dist/routes/v1/api/audit.js.map +1 -0
- package/dist/routes/v1/api/batch.d.ts +17 -0
- package/dist/routes/v1/api/batch.d.ts.map +1 -0
- package/dist/routes/v1/api/batch.js +192 -0
- package/dist/routes/v1/api/batch.js.map +1 -0
- package/dist/routes/v1/api/claims-read.d.ts +43 -0
- package/dist/routes/v1/api/claims-read.d.ts.map +1 -0
- package/dist/routes/v1/api/claims-read.js +123 -0
- package/dist/routes/v1/api/claims-read.js.map +1 -0
- package/dist/routes/v1/api/claims.d.ts +131 -0
- package/dist/routes/v1/api/claims.d.ts.map +1 -0
- package/dist/routes/v1/api/claims.js +407 -0
- package/dist/routes/v1/api/claims.js.map +1 -0
- package/dist/routes/v1/api/collections-link.d.ts +14 -0
- package/dist/routes/v1/api/collections-link.d.ts.map +1 -0
- package/dist/routes/v1/api/collections-link.js +97 -0
- package/dist/routes/v1/api/collections-link.js.map +1 -0
- package/dist/routes/v1/api/export.d.ts +48 -0
- package/dist/routes/v1/api/export.d.ts.map +1 -0
- package/dist/routes/v1/api/export.js +251 -0
- package/dist/routes/v1/api/export.js.map +1 -0
- package/dist/routes/v1/api/index.d.ts +16 -0
- package/dist/routes/v1/api/index.d.ts.map +1 -0
- package/dist/routes/v1/api/index.js +68 -0
- package/dist/routes/v1/api/index.js.map +1 -0
- package/dist/routes/v1/api/keys.d.ts +9 -0
- package/dist/routes/v1/api/keys.d.ts.map +1 -0
- package/dist/routes/v1/api/keys.js +95 -0
- package/dist/routes/v1/api/keys.js.map +1 -0
- package/dist/routes/v1/api/me.d.ts +21 -0
- package/dist/routes/v1/api/me.d.ts.map +1 -0
- package/dist/routes/v1/api/me.js +122 -0
- package/dist/routes/v1/api/me.js.map +1 -0
- package/dist/routes/v1/api/members.d.ts +17 -0
- package/dist/routes/v1/api/members.d.ts.map +1 -0
- package/dist/routes/v1/api/members.js +406 -0
- package/dist/routes/v1/api/members.js.map +1 -0
- package/dist/routes/v1/api/meta.d.ts +12 -0
- package/dist/routes/v1/api/meta.d.ts.map +1 -0
- package/dist/routes/v1/api/meta.js +59 -0
- package/dist/routes/v1/api/meta.js.map +1 -0
- package/dist/routes/v1/api/openapi.gen.d.ts +2 -0
- package/dist/routes/v1/api/openapi.gen.d.ts.map +1 -0
- package/dist/routes/v1/api/openapi.gen.js +7 -0
- package/dist/routes/v1/api/openapi.gen.js.map +1 -0
- package/dist/routes/v1/api/protocols.d.ts +22 -0
- package/dist/routes/v1/api/protocols.d.ts.map +1 -0
- package/dist/routes/v1/api/protocols.js +153 -0
- package/dist/routes/v1/api/protocols.js.map +1 -0
- package/dist/routes/v1/api/review-billing.d.ts +18 -0
- package/dist/routes/v1/api/review-billing.d.ts.map +1 -0
- package/dist/routes/v1/api/review-billing.js +196 -0
- package/dist/routes/v1/api/review-billing.js.map +1 -0
- package/dist/routes/v1/api/review.d.ts +30 -0
- package/dist/routes/v1/api/review.d.ts.map +1 -0
- package/dist/routes/v1/api/review.js +302 -0
- package/dist/routes/v1/api/review.js.map +1 -0
- package/dist/routes/v1/api/sources.d.ts +10 -0
- package/dist/routes/v1/api/sources.d.ts.map +1 -0
- package/dist/routes/v1/api/sources.js +293 -0
- package/dist/routes/v1/api/sources.js.map +1 -0
- package/dist/routes/v1/api/uploads.d.ts +37 -0
- package/dist/routes/v1/api/uploads.d.ts.map +1 -0
- package/dist/routes/v1/api/uploads.js +414 -0
- package/dist/routes/v1/api/uploads.js.map +1 -0
- package/dist/routes/v1/api/views.d.ts +18 -0
- package/dist/routes/v1/api/views.d.ts.map +1 -0
- package/dist/routes/v1/api/views.js +95 -0
- package/dist/routes/v1/api/views.js.map +1 -0
- package/dist/routes/v1/api/webhooks.d.ts +14 -0
- package/dist/routes/v1/api/webhooks.d.ts.map +1 -0
- package/dist/routes/v1/api/webhooks.js +282 -0
- package/dist/routes/v1/api/webhooks.js.map +1 -0
- package/dist/routes/v1/api/work-orders.d.ts +45 -0
- package/dist/routes/v1/api/work-orders.d.ts.map +1 -0
- package/dist/routes/v1/api/work-orders.js +171 -0
- package/dist/routes/v1/api/work-orders.js.map +1 -0
- package/dist/routes/v1/claims.d.ts +21 -0
- package/dist/routes/v1/claims.d.ts.map +1 -0
- package/dist/routes/v1/claims.js +153 -0
- package/dist/routes/v1/claims.js.map +1 -0
- package/dist/routes/v1/collections.d.ts +45 -0
- package/dist/routes/v1/collections.d.ts.map +1 -0
- package/dist/routes/v1/collections.js +201 -0
- package/dist/routes/v1/collections.js.map +1 -0
- package/dist/routes/v1/index.d.ts +13 -0
- package/dist/routes/v1/index.d.ts.map +1 -0
- package/dist/routes/v1/index.js +41 -0
- package/dist/routes/v1/index.js.map +1 -0
- package/dist/routes/v1/info.d.ts +14 -0
- package/dist/routes/v1/info.d.ts.map +1 -0
- package/dist/routes/v1/info.js +75 -0
- package/dist/routes/v1/info.js.map +1 -0
- package/dist/routes/v1/mcp/index.d.ts +33 -0
- package/dist/routes/v1/mcp/index.d.ts.map +1 -0
- package/dist/routes/v1/mcp/index.js +252 -0
- package/dist/routes/v1/mcp/index.js.map +1 -0
- package/dist/routes/v1/mcp/oauth.d.ts +27 -0
- package/dist/routes/v1/mcp/oauth.d.ts.map +1 -0
- package/dist/routes/v1/mcp/oauth.js +500 -0
- package/dist/routes/v1/mcp/oauth.js.map +1 -0
- package/dist/routes/v1/mcp/tools.d.ts +71 -0
- package/dist/routes/v1/mcp/tools.d.ts.map +1 -0
- package/dist/routes/v1/mcp/tools.js +432 -0
- package/dist/routes/v1/mcp/tools.js.map +1 -0
- package/dist/routes/v1/mcp/ui.d.ts +45 -0
- package/dist/routes/v1/mcp/ui.d.ts.map +1 -0
- package/dist/routes/v1/mcp/ui.js +454 -0
- package/dist/routes/v1/mcp/ui.js.map +1 -0
- package/dist/routes/v1/oauth.d.ts +29 -0
- package/dist/routes/v1/oauth.d.ts.map +1 -0
- package/dist/routes/v1/oauth.js +256 -0
- package/dist/routes/v1/oauth.js.map +1 -0
- package/dist/routes/v1/reviewers.d.ts +22 -0
- package/dist/routes/v1/reviewers.d.ts.map +1 -0
- package/dist/routes/v1/reviewers.js +165 -0
- package/dist/routes/v1/reviewers.js.map +1 -0
- package/dist/routes/v1/reviews.d.ts +38 -0
- package/dist/routes/v1/reviews.d.ts.map +1 -0
- package/dist/routes/v1/reviews.js +234 -0
- package/dist/routes/v1/reviews.js.map +1 -0
- package/dist/routes/v1/shared.d.ts +586 -0
- package/dist/routes/v1/shared.d.ts.map +1 -0
- package/dist/routes/v1/shared.js +229 -0
- package/dist/routes/v1/shared.js.map +1 -0
- package/dist/routes/well-known.d.ts +15 -0
- package/dist/routes/well-known.d.ts.map +1 -0
- package/dist/routes/well-known.js +35 -0
- package/dist/routes/well-known.js.map +1 -0
- package/dist/runtime.d.ts +100 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +144 -0
- package/dist/runtime.js.map +1 -0
- package/dist/testing/fake-tools.d.ts +104 -0
- package/dist/testing/fake-tools.d.ts.map +1 -0
- package/dist/testing/fake-tools.js +213 -0
- package/dist/testing/fake-tools.js.map +1 -0
- package/dist/testing/index.d.ts +54 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +104 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/samples.d.ts +70 -0
- package/dist/testing/samples.d.ts.map +1 -0
- package/dist/testing/samples.js +92 -0
- package/dist/testing/samples.js.map +1 -0
- package/dist/workflows/claim-ingest.d.ts +250 -0
- package/dist/workflows/claim-ingest.d.ts.map +1 -0
- package/dist/workflows/claim-ingest.js +1020 -0
- package/dist/workflows/claim-ingest.js.map +1 -0
- package/dist/workflows/claim-source.d.ts +25 -0
- package/dist/workflows/claim-source.d.ts.map +1 -0
- package/dist/workflows/claim-source.js +107 -0
- package/dist/workflows/claim-source.js.map +1 -0
- package/dist/workflows/review-complete.d.ts +82 -0
- package/dist/workflows/review-complete.d.ts.map +1 -0
- package/dist/workflows/review-complete.js +455 -0
- package/dist/workflows/review-complete.js.map +1 -0
- package/dist/workflows/steps.d.ts +125 -0
- package/dist/workflows/steps.d.ts.map +1 -0
- package/dist/workflows/steps.js +325 -0
- package/dist/workflows/steps.js.map +1 -0
- package/docs/api.md +2595 -0
- package/docs/guide.md +1525 -0
- package/migrations/0000_init.sql +108 -0
- package/migrations/0001_review_attestation.sql +1 -0
- package/migrations/0002_decisions_facts.sql +1 -0
- package/migrations/0003_api_lane.sql +171 -0
- package/migrations/0004_api_v1_1.sql +19 -0
- package/migrations/0005_member_notify.sql +3 -0
- package/migrations/0006_source_collections.sql +16 -0
- package/migrations/0007_api_settlement.sql +27 -0
- package/migrations/0008_review_extend.sql +1 -0
- package/migrations/0009_card_refunds.sql +4 -0
- package/migrations/0010_even_scorpion.sql +16 -0
- package/migrations/0011_mcp_oauth.sql +27 -0
- package/migrations/0012_mcp_standing.sql +21 -0
- package/migrations/0013_unknown_krista_starr.sql +2 -0
- package/migrations/0014_last_carnage.sql +14 -0
- package/migrations/0015_company_authority.sql +26 -0
- package/migrations/0016_owner_only_links.sql +6 -0
- package/migrations/0017_organisations.sql +35 -0
- package/migrations/0018_remove_app_signed.sql +4 -0
- package/migrations/0019_submitted_via.sql +2 -0
- package/migrations/0020_drop_decision_to_pay.sql +4 -0
- package/migrations/0021_manual_erase.sql +25 -0
- package/migrations/0022_errored_facts.sql +1 -0
- package/migrations/0023_review_billing.sql +20 -0
- package/migrations/0024_pending_task_details.sql +1 -0
- package/migrations/meta/0000_snapshot.json +707 -0
- package/migrations/meta/0001_snapshot.json +714 -0
- package/migrations/meta/0002_snapshot.json +721 -0
- package/migrations/meta/0003_snapshot.json +1845 -0
- package/migrations/meta/0004_snapshot.json +1969 -0
- package/migrations/meta/0005_snapshot.json +1991 -0
- package/migrations/meta/0006_snapshot.json +2097 -0
- package/migrations/meta/0007_snapshot.json +2128 -0
- package/migrations/meta/0008_snapshot.json +2133 -0
- package/migrations/meta/0009_snapshot.json +2161 -0
- package/migrations/meta/0010_snapshot.json +2265 -0
- package/migrations/meta/0011_snapshot.json +2448 -0
- package/migrations/meta/0012_snapshot.json +2577 -0
- package/migrations/meta/0013_snapshot.json +2594 -0
- package/migrations/meta/0014_snapshot.json +2602 -0
- package/migrations/meta/0015_snapshot.json +2778 -0
- package/migrations/meta/0016_snapshot.json +2778 -0
- package/migrations/meta/0017_snapshot.json +2792 -0
- package/migrations/meta/0018_snapshot.json +2778 -0
- package/migrations/meta/0019_snapshot.json +2792 -0
- package/migrations/meta/0020_snapshot.json +2785 -0
- package/migrations/meta/0021_snapshot.json +2762 -0
- package/migrations/meta/0022_snapshot.json +2769 -0
- package/migrations/meta/0023_snapshot.json +2900 -0
- package/migrations/meta/0024_snapshot.json +2907 -0
- package/migrations/meta/_journal.json +181 -0
- package/openapi/decision-api.yaml +12204 -0
- package/package.json +121 -4
- package/skills/README.md +19 -0
- package/skills/add-openhands-support/SKILL.md +113 -0
- package/skills/create-collection/SKILL.md +199 -0
- package/skills/create-collection/reference/claims-stack.md +106 -0
- package/skills/create-collection/reference/collection.md +111 -0
- package/skills/create-oracle/SKILL.md +400 -0
- package/skills/create-rubric/SKILL.md +130 -0
- package/skills/create-rubric/reference/format-cheatsheet.md +186 -0
- package/skills/create-rubric/templates/claim-form.example.json +60 -0
- package/skills/decision-api-client/SKILL.md +236 -0
- package/skills/decision-api-oracle/SKILL.md +336 -0
- package/skills/publish-protocol/SKILL.md +151 -0
- package/skills/publish-protocol/reference/publishing.md +116 -0
- package/skills/reference/engine-contract.md +222 -0
- package/skills/write-facts/SKILL.md +221 -0
- package/skills/write-facts/reference/examples/http-vendor.ts +88 -0
- package/skills/write-facts/reference/examples/price-matches-agreement.ts +67 -0
- package/skills/write-facts/reference/facts-api.md +232 -0
- package/templates/project/.dev.vars.example +93 -0
- package/templates/project/.editorconfig +9 -0
- package/templates/project/CLAUDE.md +45 -0
- package/templates/project/README.md +199 -0
- package/templates/project/biome.json +37 -0
- package/templates/project/gitignore +29 -0
- package/templates/project/package.json +32 -0
- package/templates/project/src/facts/index.ts +19 -0
- package/templates/project/src/index.ts +25 -0
- package/templates/project/test/api-lane.test.ts +57 -0
- package/templates/project/test/facts.test.ts +14 -0
- package/templates/project/tsconfig.json +25 -0
- package/templates/project/vitest.config.ts +13 -0
- package/templates/project/wrangler.jsonc +446 -0
|
@@ -0,0 +1,1433 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database schema — the source of truth. Edit here → `bun run db:generate` → `bun run db:migrate`.
|
|
3
|
+
*
|
|
4
|
+
* Cloudflare D1 (SQLite): tables are `sqliteTable` from `drizzle-orm/sqlite-core`; timestamps are
|
|
5
|
+
* `integer({ mode: "timestamp_ms" })`, booleans `integer({ mode: "boolean" })`, JSON columns
|
|
6
|
+
* `text({ mode: "json" })`. Columns are written snake_case from camelCase field names (the
|
|
7
|
+
* `casing` option in drizzle.config.ts and db/client.ts). Enums are `text({ enum })` — SQLite has
|
|
8
|
+
* no enum type, so the allowed values are enforced by the type and the app, not the database.
|
|
9
|
+
*
|
|
10
|
+
* Timestamps default app-side (`$defaultFn` / `$onUpdate`): every write goes through Drizzle, and
|
|
11
|
+
* a JS `Date` keeps millisecond precision without depending on which SQLite `unixepoch()` variant
|
|
12
|
+
* the D1 build carries.
|
|
13
|
+
*
|
|
14
|
+
* D1 has NO documented transaction atomicity through `db.transaction()` (each statement auto-commits);
|
|
15
|
+
* a multi-statement write that must be atomic goes through `db.batch([...])`. Every write in this
|
|
16
|
+
* schema is designed as ONE statement (`onConflictDoNothing` / `onConflictDoUpdate`), so nothing
|
|
17
|
+
* here needs a transaction at all.
|
|
18
|
+
*/
|
|
19
|
+
import { sql } from "drizzle-orm";
|
|
20
|
+
import { index, integer, primaryKey, sqliteTable, text, uniqueIndex, } from "drizzle-orm/sqlite-core";
|
|
21
|
+
/**
|
|
22
|
+
* Collections this oracle has been hired to evaluate (README "How a claim flows" step 1). Upserted on
|
|
23
|
+
* `collectionId` by `POST /v1/collections/register`: `ownerDid` is the CHAIN owner (who deposits
|
|
24
|
+
* the owner→oracle delegation in the UCAN Store), `enrolledByDid` whoever passed the register
|
|
25
|
+
* gates. This is the poll-set the cron scans, and the authority the read path trusts for the
|
|
26
|
+
* delegation root.
|
|
27
|
+
*/
|
|
28
|
+
export const watchedCollections = sqliteTable("watched_collections", {
|
|
29
|
+
collectionId: text().primaryKey(),
|
|
30
|
+
/**
|
|
31
|
+
* The CHAIN owner's wallet DID (`entity.owner` of the collection's deed entity) — who pays the
|
|
32
|
+
* evaluation fees, and the delegation root we look up when reading this collection's claims.
|
|
33
|
+
* Always the chain's answer, never the enroller's.
|
|
34
|
+
*/
|
|
35
|
+
ownerDid: text().notNull(),
|
|
36
|
+
/**
|
|
37
|
+
* Who registered it — the principal that signed the register: the owner, or a holder of an
|
|
38
|
+
* active evaluate grant for the collection. Admitted by the read gate beside the owner; NEVER
|
|
39
|
+
* the delegation root (that stays the owner's, above — the Matrix delegation is theirs).
|
|
40
|
+
*/
|
|
41
|
+
enrolledByDid: text().notNull(),
|
|
42
|
+
/**
|
|
43
|
+
* The collection's on-chain evaluation payment as accepted at (re-)register — what this
|
|
44
|
+
* collection pays per `MsgEvaluateClaim` (the chain splits it 80/10/10 to the oracle). Checked
|
|
45
|
+
* against the oracle config's `pricing` on every register; recorded so the dashboard can show it.
|
|
46
|
+
*/
|
|
47
|
+
evaluationDenom: text(),
|
|
48
|
+
evaluationAmount: text(),
|
|
49
|
+
/** Protocol entity DID backing the collection (blocksync `collection.protocol`) — where `#rub` is anchored. */
|
|
50
|
+
protocolDid: text(),
|
|
51
|
+
/**
|
|
52
|
+
* The pinned rubric: sha256 of its stored bytes, which IS its id and the on-chain
|
|
53
|
+
* LinkedResource `proof`. Pinned by the workflow's evaluate step on first sight; the chain is the
|
|
54
|
+
* authority. Null until
|
|
55
|
+
* resolved.
|
|
56
|
+
*/
|
|
57
|
+
rubricId: text(),
|
|
58
|
+
/**
|
|
59
|
+
* The owner→oracle delegation (base64 CAR), persisted at register time so the read path makes
|
|
60
|
+
* ZERO UCAN-Store round trips. Refreshed from the store when missing/expired (the portal still
|
|
61
|
+
* deposits there — the store stays the fleet registry and our refresh source).
|
|
62
|
+
*/
|
|
63
|
+
delegationCar: text(),
|
|
64
|
+
/** When the stored delegation expires (null = it declares no expiry). */
|
|
65
|
+
delegationExpiresAt: integer({ mode: "timestamp_ms" }),
|
|
66
|
+
/** Where the commissioner is reached (review requests, pauses). Captured at register. */
|
|
67
|
+
contactEmail: text(),
|
|
68
|
+
/**
|
|
69
|
+
* `paused` stops the scan enqueuing anything for this collection — the engine answering 402
|
|
70
|
+
* (credits exhausted) or 403 (not hired) flips it, an operator flips it back. The row and its
|
|
71
|
+
* delegation stand.
|
|
72
|
+
*/
|
|
73
|
+
status: text({ enum: ["active", "paused"] })
|
|
74
|
+
.notNull()
|
|
75
|
+
.default("active"),
|
|
76
|
+
/**
|
|
77
|
+
* WHY the engine paused it, for the operator and the dashboard: `engine-credits` (402 — every
|
|
78
|
+
* active collection pauses, resume after the top-up), `engine-no-grant` (403 — this oracle
|
|
79
|
+
* lost the collection's `EvaluateClaimAuthorization`; re-register once re-granted) or
|
|
80
|
+
* `rubric-unusable` (the engine's rubric manifest is `unusable`, or a 200 `decision.status:
|
|
81
|
+
* "unusable"` — the engine cannot resolve/bind the protocol's rubric to its form / the facts;
|
|
82
|
+
* every claim would be refused the same way, so the broken catalog entry is paid for at most
|
|
83
|
+
* once; resume once `#rub`/`#vct` are fixed) or `admin-unfunded` (the chain refused our
|
|
84
|
+
* `MsgEvaluateClaim` with "insufficient funds: payment withdrawal failed" — the collection's
|
|
85
|
+
* admin account cannot pay the evaluation leg, and every further decision would be billed by
|
|
86
|
+
* the engine and then parked the same way; `cron/funding.ts` resumes it and re-delivers the
|
|
87
|
+
* parked decisions once the account covers `evaluationAmount`), or — per-review billing
|
|
88
|
+
* (`billingSourceId` set) — `payer-credits` (the facilitator refused the reservation for want of
|
|
89
|
+
* the paying organisation's credits: a top-up fixes it) or `payer-delegation` (no usable
|
|
90
|
+
* review-billing delegation: none, expired, cap used up, its signer no longer the
|
|
91
|
+
* organisation's owner, the company disputed, no published price — a new delegation in the
|
|
92
|
+
* Console fixes it), or `oracle-plan` (the facilitator says IXO's plan does not let this
|
|
93
|
+
* oracle bill reviews: IXO's to fix, paged, the owner not told); `cron/payer-billing.ts`
|
|
94
|
+
* resumes all three. Null on an
|
|
95
|
+
* operator pause; cleared on resume/re-register. A TEXT column: the enum is type-only (SQLite),
|
|
96
|
+
* so a new value needs no migration.
|
|
97
|
+
*/
|
|
98
|
+
pausedReason: text({
|
|
99
|
+
enum: [
|
|
100
|
+
"engine-credits",
|
|
101
|
+
"engine-no-grant",
|
|
102
|
+
"rubric-unusable",
|
|
103
|
+
"admin-unfunded",
|
|
104
|
+
"payer-credits",
|
|
105
|
+
"payer-delegation",
|
|
106
|
+
"oracle-plan",
|
|
107
|
+
],
|
|
108
|
+
}),
|
|
109
|
+
/**
|
|
110
|
+
* Per-review checker billing (IXO's plan for the oracle, payments/review-billing.ts): the
|
|
111
|
+
* Decision API source whose stored delegation pays for each of this collection's claims over
|
|
112
|
+
* x402 — set at register when the collection's company (the engine's answer) holds one, so the
|
|
113
|
+
* collection registered with an empty evaluation leg. Null = the chain's evaluation payment pays
|
|
114
|
+
* (today's model; never both). Re-resolved on every claim's reservation, and written again if
|
|
115
|
+
* the organisation's paying source changed.
|
|
116
|
+
*/
|
|
117
|
+
billingSourceId: text(),
|
|
118
|
+
/**
|
|
119
|
+
* The cron scan watermark: the newest claim `submissionDate` we've enqueued for this
|
|
120
|
+
* collection. Null = never scanned, so the next tick sweeps the collection from the beginning.
|
|
121
|
+
* Scans are inclusive (`>=`) so claims sharing a timestamp are never skipped; `claim_ingests`
|
|
122
|
+
* is the forever dedup that stops the boundary claim being re-pulled.
|
|
123
|
+
*/
|
|
124
|
+
cursor: text(),
|
|
125
|
+
/**
|
|
126
|
+
* The cron rotation clock: stamped on EVERY visit (found claims, found nothing, or failed).
|
|
127
|
+
* Ticks pick the least-recently-scanned collections first, so a bounded per-tick batch still
|
|
128
|
+
* covers every watched collection fairly. Null = never scanned → front of the queue.
|
|
129
|
+
*/
|
|
130
|
+
lastScannedAt: integer({ mode: "timestamp_ms" }),
|
|
131
|
+
/**
|
|
132
|
+
* Whether the act seam's on-chain amount may stand (company authority D7, F6): `off` — the
|
|
133
|
+
* default, the owner never said yes — ignores it for the lane's default and logs it. Set by the
|
|
134
|
+
* collection OWNER only (`PATCH /v1/collections/:id/settings`), enforced by the act lane
|
|
135
|
+
* (chain-write.ts). A TEXT column: the enum is type-only (SQLite).
|
|
136
|
+
*/
|
|
137
|
+
operatorAmounts: text({ enum: ["off", "allowed"] })
|
|
138
|
+
.notNull()
|
|
139
|
+
.default("off"),
|
|
140
|
+
/**
|
|
141
|
+
* Who set `operatorAmounts` — the chain owner's address as the settings route checked it. The
|
|
142
|
+
* act lane honours `allowed` only while this is STILL the collection's live owner, so a yes
|
|
143
|
+
* never outlives an ownership transfer: the new owner has to say it again (D7).
|
|
144
|
+
*/
|
|
145
|
+
operatorAmountsBy: text(),
|
|
146
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
147
|
+
.notNull()
|
|
148
|
+
.$defaultFn(() => new Date()),
|
|
149
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
150
|
+
.notNull()
|
|
151
|
+
.$defaultFn(() => new Date())
|
|
152
|
+
.$onUpdate(() => new Date()),
|
|
153
|
+
}, (t) => [
|
|
154
|
+
// The cron's rotation read: active rows, least recently scanned first.
|
|
155
|
+
index("watched_collections_status_last_scanned_idx").on(t.status, t.lastScannedAt),
|
|
156
|
+
]);
|
|
157
|
+
/**
|
|
158
|
+
* The ingestion ledger: one row per claim we've ever accepted, and where it got to.
|
|
159
|
+
*
|
|
160
|
+
* This — not the existence of a Workflow instance — is the source of truth for "have we got this
|
|
161
|
+
* claim already?", because instances are retained only 3–30 days; after that the runtime would
|
|
162
|
+
* happily accept the same id again and we'd silently re-ingest forever.
|
|
163
|
+
*
|
|
164
|
+
* The workflow owns its row for its whole lifecycle (record-queued → … → mark-processed); the
|
|
165
|
+
* cron never writes it. The cron's only dedupe is "row exists → already started", plus the
|
|
166
|
+
* workflow instance id's own idempotency. The claim is taken by INSERTing here with
|
|
167
|
+
* `onConflictDoNothing()` — one statement, so the primary key is the mutex: no select-then-insert
|
|
168
|
+
* race, and no matching on error strings.
|
|
169
|
+
*/
|
|
170
|
+
export const claimIngests = sqliteTable("claim_ingests", {
|
|
171
|
+
claimId: text().primaryKey(),
|
|
172
|
+
collectionId: text().notNull(),
|
|
173
|
+
status: text({ enum: ["queued", "processing", "processed", "failed", "skipped"] })
|
|
174
|
+
.notNull()
|
|
175
|
+
.default("queued"),
|
|
176
|
+
/**
|
|
177
|
+
* How the claim arrived (Go Prod §7.1): `chain` (the cron scan) or `api` (`POST /v1/api/claims`,
|
|
178
|
+
* `collectionId` = the scope id `api:<sourceId>:<protocolDid>`). `ReviewComplete` reads it to
|
|
179
|
+
* pick the `ClaimSource` its re-pull goes through. Defaulted, so every pre-existing row and every
|
|
180
|
+
* cron insert that never names it stays `chain`.
|
|
181
|
+
*/
|
|
182
|
+
lane: text({ enum: ["chain", "api"] })
|
|
183
|
+
.notNull()
|
|
184
|
+
.default("chain"),
|
|
185
|
+
/** The Workflow instance id (the claimId, or its sha256 — lib/ids.ts), to follow it while it lives. */
|
|
186
|
+
instanceId: text(),
|
|
187
|
+
/** The terminal failure's message, for the claim read and the operator — null unless `failed`. */
|
|
188
|
+
error: text(),
|
|
189
|
+
/**
|
|
190
|
+
* When the collection's owner erased this CHAIN claim's answer copies (company authority F14,
|
|
191
|
+
* `DELETE /v1/claims/:claimId/body`, lib/claim-erase.ts): the fact transcripts on
|
|
192
|
+
* `decisions.facts` and the registry's `normalizedText`. Null = never erased — the oracle never
|
|
193
|
+
* erases chain-lane data on its own. The body itself was never stored here (it lives on the
|
|
194
|
+
* claim's own store). Never set on an `api` row — that lane's marker is `api_claims.bodyErasedAt`.
|
|
195
|
+
*/
|
|
196
|
+
erasedAt: integer({ mode: "timestamp_ms" }),
|
|
197
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
198
|
+
.notNull()
|
|
199
|
+
.$defaultFn(() => new Date()),
|
|
200
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
201
|
+
.notNull()
|
|
202
|
+
.$defaultFn(() => new Date())
|
|
203
|
+
.$onUpdate(() => new Date()),
|
|
204
|
+
}, (t) => [
|
|
205
|
+
// Covers the hot list query (`GET /v1/claims`, routes/v1/claims.ts): filtered by collectionId,
|
|
206
|
+
// ordered by (createdAt, claimId) desc for keyset pagination. Same leading column as the
|
|
207
|
+
// single-column index this replaces, so it serves an equality-only lookup on collectionId
|
|
208
|
+
// too (e.g. a future one) — no need to keep both.
|
|
209
|
+
index("claim_ingests_collection_created_claim_idx").on(t.collectionId, t.createdAt, t.claimId),
|
|
210
|
+
// The operator's claim list (`GET /v1/api/admin/claims`, lib/api-lane/claim-list.ts): the
|
|
211
|
+
// chain branch over EVERY watched collection is `lane = 'chain'` ordered by (createdAt,
|
|
212
|
+
// claimId) desc — without it that page is a full scan and sort of the ledger.
|
|
213
|
+
index("claim_ingests_lane_created_claim_idx").on(t.lane, t.createdAt, t.claimId),
|
|
214
|
+
]);
|
|
215
|
+
/**
|
|
216
|
+
* The engine's decision as returned to THIS oracle (`POST /v1/decisions`, README "How a claim flows" step 5),
|
|
217
|
+
* cached once per claim. The engine's ledger is the authority — this row exists so the act lane,
|
|
218
|
+
* the review fold and the claim read never re-ask for a decision already made. `claimId` PK +
|
|
219
|
+
* `onConflictDoNothing` is the decided-once guard on our side, matching the engine's own
|
|
220
|
+
* evaluated-once mutex. Written once by the evaluate step; changed only by the review fold (the
|
|
221
|
+
* SAME decision with the answers folded in — never a second evaluation) and by delivery state
|
|
222
|
+
* (`chainStatus`/`txHash`/`chainError`).
|
|
223
|
+
*
|
|
224
|
+
* A claim the facts lane could not build for — `unusable` (the engine's rubric manifest says the
|
|
225
|
+
* protocol's rubric cannot be resolved or bound: no `#rub`, swapped bytes, a drifted `#vct` — its
|
|
226
|
+
* issues verbatim), `invalid_facts` (the producer's answer doesn't match the rubric's work order —
|
|
227
|
+
* our/the provider's bug) — gets a row too, with the engine never asked to decide (nothing to
|
|
228
|
+
* decide, nothing charged): `status` names the reason, `explanation` the issues, and every
|
|
229
|
+
* engine-owned column (`rubricId` where unknown, `factsDigest`, `verdict`, `resultDigest`,
|
|
230
|
+
* `decision`) is null. A decide-time `unusable` (the engine's fact-coverage check) is a real
|
|
231
|
+
* decision row (receipt and all); both pause the collection (`watched_collections.pausedReason`).
|
|
232
|
+
*/
|
|
233
|
+
export const decisions = sqliteTable("decisions", {
|
|
234
|
+
claimId: text().primaryKey(),
|
|
235
|
+
collectionId: text().notNull(),
|
|
236
|
+
/** The rubric the engine judged against — pinned per claim, so a later re-anchor changes nothing here. */
|
|
237
|
+
rubricId: text(),
|
|
238
|
+
/** sha256(canonicalJson(FactSet)) — what we sent; binds this decision to the facts we produced. */
|
|
239
|
+
factsDigest: text(),
|
|
240
|
+
/** The engine's verdict (approve · partial · reject · review); null on a facts-lane outcome. */
|
|
241
|
+
verdict: text(),
|
|
242
|
+
/**
|
|
243
|
+
* `decided` · `pending_review` · `unusable` from the engine; the facts lane's `unusable` ·
|
|
244
|
+
* `invalid_facts`; or the engine's refusal of the claim's content (company authority) —
|
|
245
|
+
* `content_mismatch` · `payload_too_large`, recorded like a facts-lane outcome (no engine
|
|
246
|
+
* columns, `skipped`). Type-only enum: a new value needs no migration.
|
|
247
|
+
*/
|
|
248
|
+
status: text().notNull(),
|
|
249
|
+
/** The engine's `resultDigest` — what a review answer is folded against (`answeredAgainst`). */
|
|
250
|
+
resultDigest: text(),
|
|
251
|
+
/** The engine's signed receipt CID — what `MsgEvaluateClaim.verification_proof` carries. */
|
|
252
|
+
receiptCid: text(),
|
|
253
|
+
/**
|
|
254
|
+
* The receipt itself — the engine's Ed25519 compact JWS (codes, scores, identifiers; never
|
|
255
|
+
* answer values). The receipt is the engine's product and the artifact this oracle acted on,
|
|
256
|
+
* so the oracle holds it: `GET /v1/claims/:claimId` serves it, and a Matrix republish of the
|
|
257
|
+
* CID (a follow-up) needs the bytes. Written together with `receiptCid`, always.
|
|
258
|
+
*/
|
|
259
|
+
receiptJws: text(),
|
|
260
|
+
/** The engine's decision object verbatim (codes, scores, outcomes — never answer values). */
|
|
261
|
+
decision: text({ mode: "json" }).$type(),
|
|
262
|
+
/** The engine's plain-English narrative, display-only. */
|
|
263
|
+
explanation: text(),
|
|
264
|
+
/**
|
|
265
|
+
* The `ext`/`ai` facts this decision was made on, frozen exactly as they went to the engine
|
|
266
|
+
* (never `answers`/`attachments` — this row outlives the claim's erasable surface). The act
|
|
267
|
+
* policy (act.ts) reads them by name at signing time, which is why they cannot live in the
|
|
268
|
+
* connector cache: that dies in the same batch that writes this row (claim-ingest.ts `record`).
|
|
269
|
+
* Null ONLY on a row the engine never decided — a facts-lane `unusable`/`invalid_facts`, which
|
|
270
|
+
* is `skipped` from the start; a `decided` row without them is an ingest contract violation and
|
|
271
|
+
* the act lane parks it rather than sign blind.
|
|
272
|
+
*/
|
|
273
|
+
facts: text({ mode: "json" }).$type(),
|
|
274
|
+
/**
|
|
275
|
+
* The engine's `erroredFacts` (engine/types.ts `ErroredFact`): each errored fact's lane-prefixed
|
|
276
|
+
* name and its own error text, each detail capped — WHY a claim was held, which the engine's
|
|
277
|
+
* hashed reason line never says. Only the derived list, never facts or answers; written in the
|
|
278
|
+
* decision's own statement (and replaced by a fold that carries one). Null when nothing errored
|
|
279
|
+
* or the engine sent none (an older engine).
|
|
280
|
+
*/
|
|
281
|
+
erroredFacts: text({ mode: "json" }).$type(),
|
|
282
|
+
/**
|
|
283
|
+
* The engine's `pendingTaskDetails` (engine/types.ts `PendingTaskDetail`): per pending
|
|
284
|
+
* `unique:<ruleId>` task, the duplicate score and the prior claim's id — what the review view's
|
|
285
|
+
* `duplicates` is built from. Written with the decision only (a fold always answers `{}`:
|
|
286
|
+
* nothing pends after it). Null when none pends or the engine sent none (an older engine).
|
|
287
|
+
*/
|
|
288
|
+
pendingTaskDetails: text({ mode: "json" }).$type(),
|
|
289
|
+
/**
|
|
290
|
+
* Where the verdict got to on chain: `pending` (not yet acted on) → `submitted` (our tx) /
|
|
291
|
+
* `blocked` (broadcast failed, retryable) / `skipped` (AUTO_SIGN off, or a non-terminal
|
|
292
|
+
* verdict) / `held` (the oracle's act policy is keeping it back for a later `signEvaluation` —
|
|
293
|
+
* NOT a delivered state) / `owner_submitted` (someone else evaluated it first — the chain locks
|
|
294
|
+
* a claim on its first terminal evaluation). A TEXT column: the enum is type-only (SQLite), so a
|
|
295
|
+
* new value needs no migration.
|
|
296
|
+
*/
|
|
297
|
+
chainStatus: text({
|
|
298
|
+
enum: ["pending", "submitted", "blocked", "skipped", "held", "owner_submitted"],
|
|
299
|
+
})
|
|
300
|
+
.notNull()
|
|
301
|
+
.default("pending"),
|
|
302
|
+
txHash: text(),
|
|
303
|
+
/** The last delivery failure (a `blocked` reason, or the broadcast error the step is retrying); null once submitted. */
|
|
304
|
+
chainError: text(),
|
|
305
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
306
|
+
.notNull()
|
|
307
|
+
.$defaultFn(() => new Date()),
|
|
308
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
309
|
+
.notNull()
|
|
310
|
+
.$defaultFn(() => new Date())
|
|
311
|
+
.$onUpdate(() => new Date()),
|
|
312
|
+
}, (t) => [
|
|
313
|
+
// The review-reminder sweep (Go Prod §10.4: 3 and 14 days) and the operator's pending list:
|
|
314
|
+
// rows in one status, oldest first.
|
|
315
|
+
index("decisions_status_created_idx").on(t.status, t.createdAt),
|
|
316
|
+
// The funding cron's parked decisions of one collection (cron/funding.ts `redeliverParked`:
|
|
317
|
+
// collection + `chainStatus in (pending, blocked)`, oldest first) — without it every resume
|
|
318
|
+
// walked the whole table.
|
|
319
|
+
index("dec_collection_chain").on(t.collectionId, t.chainStatus, t.createdAt),
|
|
320
|
+
]);
|
|
321
|
+
/**
|
|
322
|
+
* Human-review answers + their fold (README "How a claim flows" step 6). The decision row stays as the engine
|
|
323
|
+
* returned it — the fold is recorded BESIDE it. `claimId` PK = the answered-once mutex
|
|
324
|
+
* (`onConflictDoNothing`): the POST is idempotent until folded, then conflicts. `foldedAt` is
|
|
325
|
+
* written once by the `ReviewComplete` workflow when the engine has folded the answers.
|
|
326
|
+
*/
|
|
327
|
+
export const claimReviews = sqliteTable("claim_reviews", {
|
|
328
|
+
claimId: text().primaryKey(),
|
|
329
|
+
/** `{ [taskId]: boolean | string }` — covers EXACTLY the decision's pending review tasks. */
|
|
330
|
+
answers: text({ mode: "json" }).$type().notNull(),
|
|
331
|
+
/** From the UCAN principal. Our word alone unless `attestationJws` backs it. */
|
|
332
|
+
reviewerDid: text().notNull(),
|
|
333
|
+
/**
|
|
334
|
+
* The reviewer's signed attestation over `answers` (compact JWS, design §B.3) — stored VERBATIM
|
|
335
|
+
* because the signature is over exact bytes; null for a review answered without one (optional
|
|
336
|
+
* this round). Erasable with this row: it is the one place answer VALUES are signed, which is why
|
|
337
|
+
* the receipt and the Matrix card carry only its CID.
|
|
338
|
+
*/
|
|
339
|
+
attestationJws: text(),
|
|
340
|
+
answeredAt: integer({ mode: "timestamp_ms" })
|
|
341
|
+
.notNull()
|
|
342
|
+
.$defaultFn(() => new Date()),
|
|
343
|
+
foldedAt: integer({ mode: "timestamp_ms" }),
|
|
344
|
+
/**
|
|
345
|
+
* Why the fold did not land (the engine's `STALE_REVIEW` — the answers named a digest the engine
|
|
346
|
+
* no longer holds — or a validation refusal), surfaced on `GET /v1/reviews/:claimId` so the
|
|
347
|
+
* reviewer can answer again; a re-POST clears it.
|
|
348
|
+
*/
|
|
349
|
+
foldError: text(),
|
|
350
|
+
/**
|
|
351
|
+
* The reviewer's grant (company authority D2): base64 CAR, one link, controller → reviewer
|
|
352
|
+
* did:ixo, as `ReviewerGrant` in lib/engine/types.ts — the bytes the controller FILED
|
|
353
|
+
* (`collection_reviewers.delegation`), never the reviewer's copy. Stored with the answers so a
|
|
354
|
+
* retried fold forwards the same proof. Erasable with the row.
|
|
355
|
+
*/
|
|
356
|
+
reviewerGrant: text(),
|
|
357
|
+
});
|
|
358
|
+
/**
|
|
359
|
+
* A chain collection's reviewers (company authority D2, F2, F12): each row one signed delegation
|
|
360
|
+
* from a root the engine accepts (`rootDid` — the collection owner or an entity controller) to a
|
|
361
|
+
* member `did:ixo`, kept with what it says (`expiresAt`) so a check needs no CAR parse — as
|
|
362
|
+
* `api_members` keeps a source's grants. The CID is the identity: a re-grant is a new row, and
|
|
363
|
+
* revoking stamps `revokedAt` (a row is never edited otherwise). Read by (collection, member) when a
|
|
364
|
+
* review is answered; enforced from CA-M3.
|
|
365
|
+
*/
|
|
366
|
+
export const collectionReviewers = sqliteTable("collection_reviewers", {
|
|
367
|
+
collectionId: text().notNull(),
|
|
368
|
+
/** The member's `did:ixo` the delegation names as audience. */
|
|
369
|
+
memberDid: text().notNull(),
|
|
370
|
+
/** Who signed it: the root the engine checks against the chain. */
|
|
371
|
+
rootDid: text().notNull(),
|
|
372
|
+
/** Base64 of the delegation CAR. */
|
|
373
|
+
delegation: text().notNull(),
|
|
374
|
+
delegationCid: text().notNull(),
|
|
375
|
+
/** The delegation's expiry, in ms (`exp * 1000`). Required: a reviewer grant never lives forever. */
|
|
376
|
+
expiresAt: integer({ mode: "timestamp_ms" }).notNull(),
|
|
377
|
+
revokedAt: integer({ mode: "timestamp_ms" }),
|
|
378
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
379
|
+
.notNull()
|
|
380
|
+
.$defaultFn(() => new Date()),
|
|
381
|
+
}, (t) => [
|
|
382
|
+
primaryKey({ columns: [t.collectionId, t.delegationCid] }),
|
|
383
|
+
// The review gate: this member's grants on this collection.
|
|
384
|
+
index("collection_reviewers_member_idx").on(t.collectionId, t.memberDid),
|
|
385
|
+
]);
|
|
386
|
+
/**
|
|
387
|
+
* Canonical-body registry for duplicate detection (duplicate spec §9; the registry is
|
|
388
|
+
* oracle-side — docs/ENGINE-CONTRACT.md "Fact coverage + manifest") — one row per
|
|
389
|
+
* (collection, digest, claim), written by the stock producer's resolve phase BEFORE it reads
|
|
390
|
+
* siblings (insert-self-first, spec §3.2): two racing claims each see the other, so neither can
|
|
391
|
+
* slip through the race window. `onConflictDoNothing` on the PK makes the insert idempotent under
|
|
392
|
+
* workflow step retry. The prior-claim scope is every claim THIS oracle ingested for the
|
|
393
|
+
* collection — the D1 is this oracle's, so no oracle column is needed and no other oracle's
|
|
394
|
+
* registry is ever visible.
|
|
395
|
+
*
|
|
396
|
+
* `digest` is the keyed HMAC over the canonical body — matching digests mean matching content,
|
|
397
|
+
* but the digest alone reveals nothing (spec §12.3). `normalizedText` is the near-text lane's
|
|
398
|
+
* haystack and the ONLY column carrying claim-derived text: erasable PII, nullable by design —
|
|
399
|
+
* wiping it degrades fuzzy recall for old rows without touching the exact-match lane.
|
|
400
|
+
* `finalVerdict` is denormalized when the engine's decision lands (workflows, never the producer)
|
|
401
|
+
* so the `countPrior` filter reads one table; NULL means still pending, which counts as blockable.
|
|
402
|
+
*
|
|
403
|
+
* Indexes: the composite PK already serves the (collection, digest) exact lookup (SQLite's
|
|
404
|
+
* autoindex covers a leading prefix); `cbd_recent` serves the near-text pool read (newest rows of
|
|
405
|
+
* a collection first — lib/facts/stock/unique-store.ts, where Postgres had a GIN trigram index);
|
|
406
|
+
* `cbd_claim` serves every read keyed on the claim — the workflows' `finalVerdict` UPDATE (every
|
|
407
|
+
* decided claim), the CID lane's join and the erase routes (`claim_id = ?` alone,
|
|
408
|
+
* hence claimId leading). The PK cannot: `digest` sits between collection and claim, so each of
|
|
409
|
+
* them walked every registry row of the collection, or of the table.
|
|
410
|
+
*/
|
|
411
|
+
export const claimBodyDigests = sqliteTable("claim_body_digests", {
|
|
412
|
+
collectionId: text().notNull(),
|
|
413
|
+
/** HMAC-SHA256 over the canonical body (spec §4.1) — the exact-match lane's key. */
|
|
414
|
+
digest: text().notNull(),
|
|
415
|
+
claimId: text().notNull(),
|
|
416
|
+
agentAddress: text(),
|
|
417
|
+
/** Near-text lane haystack; erasable PII — nullable by design (spec §12.3). */
|
|
418
|
+
normalizedText: text(),
|
|
419
|
+
/** Denormalized at decision time (registry token: approved · rejected · pending_review); NULL = pending, blockable. */
|
|
420
|
+
finalVerdict: text(),
|
|
421
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
422
|
+
.notNull()
|
|
423
|
+
.$defaultFn(() => new Date()),
|
|
424
|
+
}, (t) => [
|
|
425
|
+
primaryKey({ columns: [t.collectionId, t.digest, t.claimId] }),
|
|
426
|
+
index("cbd_recent").on(t.collectionId, t.createdAt),
|
|
427
|
+
index("cbd_claim").on(t.claimId, t.collectionId),
|
|
428
|
+
]);
|
|
429
|
+
/**
|
|
430
|
+
* Attachment-CID registry (duplicate spec §9, §4 L2) — one row per (collection, cid, claim),
|
|
431
|
+
* same insert-self-first + retry-idempotent discipline as `claim_body_digests`. A CID seen on
|
|
432
|
+
* two different claims IS the same bytes (content addressing does the proving) — no fetch
|
|
433
|
+
* needed. `phash` is the perceptual dHash for the near-match lane (§4 L4): nullable because not
|
|
434
|
+
* every attachment decodes (non-image, oversized, undecodable — and every PDF here: the kit has
|
|
435
|
+
* no Browser Run binding, so PDFs are never rendered) and a missing hash only narrows recall,
|
|
436
|
+
* never blocks registration. `cac_recent` serves the bounded pHash pool read (newest first).
|
|
437
|
+
*/
|
|
438
|
+
export const claimAttachmentCids = sqliteTable("claim_attachment_cids", {
|
|
439
|
+
collectionId: text().notNull(),
|
|
440
|
+
cid: text().notNull(),
|
|
441
|
+
claimId: text().notNull(),
|
|
442
|
+
agentAddress: text(),
|
|
443
|
+
/** dHash64 hex (16 chars) of the decoded image; null = not hashable. */
|
|
444
|
+
phash: text(),
|
|
445
|
+
/**
|
|
446
|
+
* The ATTACHMENT's own media type — what `phash` was derived from, which decides how far
|
|
447
|
+
* apart two hashes may sit and still count (unique-score's §5 tiers): a rendered document is
|
|
448
|
+
* deterministic and moves a bit or two, a photo of the same scene moves much more. NULL only
|
|
449
|
+
* on a row written without one: scored with the looser image tiers.
|
|
450
|
+
*/
|
|
451
|
+
mediaType: text(),
|
|
452
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
453
|
+
.notNull()
|
|
454
|
+
.$defaultFn(() => new Date()),
|
|
455
|
+
}, (t) => [
|
|
456
|
+
primaryKey({ columns: [t.collectionId, t.cid, t.claimId] }),
|
|
457
|
+
index("cac_recent").on(t.collectionId, t.createdAt),
|
|
458
|
+
]);
|
|
459
|
+
/**
|
|
460
|
+
* Resolved connector answers, cached per claim while its evaluate step is still in flight — the
|
|
461
|
+
* crash-recovery twin of the engine's decided-once read: `GET /v1/decisions/:claimId` covers a
|
|
462
|
+
* crash AFTER the engine decided, this table covers a crash MID-produce, so a step retry re-runs
|
|
463
|
+
* only the connectors that never answered instead of re-buying every AI/ext call. Written
|
|
464
|
+
* fail-soft by the stock producer as each `ext`/`ai` fact resolves (lib/facts/fact-cache.ts);
|
|
465
|
+
* `unique`/`frequency` are NEVER cached — registry state and calendar windows must be fresh per
|
|
466
|
+
* attempt. The one exception is a `unique-judge` row: the same-event judge's `valid` verdict on ONE
|
|
467
|
+
* (claim, candidate) pair, `name` = the candidate claimId (stock/unique.ts `judgePairs`) — a
|
|
468
|
+
* question about two fixed bodies, so a retry need not pay for it again; the candidate SET is still
|
|
469
|
+
* read fresh. `kind` is a type-only enum on TEXT, so that value needed no migration. Keyed by the
|
|
470
|
+
* manifest's `rubricId` too: an answer is an answer to ONE work order, and a `#rub` re-anchored
|
|
471
|
+
* between two attempts (or the `RUBRIC_PIN_MISMATCH` rebuild, workflows/claim-ingest.ts) is a new
|
|
472
|
+
* one — same-named facts must run again, never come back from the old rubric's sources or
|
|
473
|
+
* instructions. Deleted (every rubric's rows) in the same `db.batch` as the claim's `decisions`
|
|
474
|
+
* row write and on terminal failure: decided or dead, the cache is gone — rows only ever outlive a
|
|
475
|
+
* crashed attempt.
|
|
476
|
+
*/
|
|
477
|
+
export const factCache = sqliteTable("fact_cache", {
|
|
478
|
+
claimId: text().notNull(),
|
|
479
|
+
/** The work order the row answered (the manifest's `rubricId`, canonical lowercase). */
|
|
480
|
+
rubricId: text().notNull(),
|
|
481
|
+
kind: text({ enum: ["ext", "ai", "unique-judge"] }).notNull(),
|
|
482
|
+
/**
|
|
483
|
+
* The `<name>` in `ext.<name>` / `ai.<name>` — the work-order key (lib/facts/expected.ts); for
|
|
484
|
+
* `unique-judge`, the candidate claimId.
|
|
485
|
+
*/
|
|
486
|
+
name: text().notNull(),
|
|
487
|
+
/** The resolved fact (or judgement) verbatim — returned as-is on a retry's hit. */
|
|
488
|
+
fact: text({ mode: "json" }).$type().notNull(),
|
|
489
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
490
|
+
.notNull()
|
|
491
|
+
.$defaultFn(() => new Date()),
|
|
492
|
+
}, (t) => [primaryKey({ columns: [t.claimId, t.rubricId, t.kind, t.name] })]);
|
|
493
|
+
/**
|
|
494
|
+
* The side-effect ledger (the review-notification lane, lib/matrix/deliver.ts; the email notices,
|
|
495
|
+
* workflows/steps.ts + routes/v1/collections.ts). `dedupeKey` is
|
|
496
|
+
* the primary key AND the sent-once mutex: a step/route that re-enters finds a `sent` row and does
|
|
497
|
+
* zero HTTP/email. It is ALSO the review room's reuse index — a `sent` `review_room` row is the
|
|
498
|
+
* answer to "does this room already exist" for a `(collectionId, ownerDid)` pair. Kinds:
|
|
499
|
+
*
|
|
500
|
+
* review_room:{collectionId}:{ownerDid} ← the oracle-owned room, reused across every claim
|
|
501
|
+
* review_request:{claimId} ← the sent v2 review-request Matrix event
|
|
502
|
+
* review_fold:{claimId} ← the `m.replace` edit that completes it
|
|
503
|
+
* notice_review_email:{claimId}:{resultDigest} ← the review-request EMAIL twin (deliver.ts),
|
|
504
|
+
* independent of review_request so one lane's
|
|
505
|
+
* failure never blocks or hides the other's
|
|
506
|
+
* notice_paused:{collectionId} ← the paused-collection email (steps.ts)
|
|
507
|
+
* notice_resumed:{collectionId} ← its alternating twin (steps.ts, collections.ts)
|
|
508
|
+
* review_room:{sourceId} ← an API source's review room (Go Prod §10.1), keyed by
|
|
509
|
+
* the source alone: one room per source on this oracle
|
|
510
|
+
* rvi:{sourceId}:{mxid} ← a person invited to it (`review_invite`; the MXID in
|
|
511
|
+
* `targetUrl` too, so a removed member can still be kicked);
|
|
512
|
+
* keyed by MXID, not memberId, so a member removed and
|
|
513
|
+
* re-added is the same row; `dead` once kicked
|
|
514
|
+
* rvm:{claimId} ← the room's notice for one API claim (`review_notice`)
|
|
515
|
+
* rv:{claimId}:{memberId|contact} ← one recipient's review email for one API claim
|
|
516
|
+
* (`review_email`): `sending` once claimed, `pending` while
|
|
517
|
+
* held for the batch (lib/api-lane/reviewers.ts), then its
|
|
518
|
+
* email's outcome
|
|
519
|
+
* rvw:{sourceId} ← the source contact's 15-minute review-email window
|
|
520
|
+
* (`review_window`): `updatedAt` is its last email
|
|
521
|
+
* rv3|rv14:{claimId}:{memberId|contact} ← one recipient's 3-/14-day reminder (`review_reminder`)
|
|
522
|
+
* notice_review_reminder:{claimId}:{3|14} ← an API claim's unanswered-review reminder done (Go Prod
|
|
523
|
+
* §10.4) — what keeps the hourly pass off the claim
|
|
524
|
+
* notice_review_expired:{claimId} ← a paid API claim's review closed unanswered at its
|
|
525
|
+
* `answerBy`, announced (`review_expired` + webhook)
|
|
526
|
+
* notice_balance_low:{sourceId}:{yyyy-mm-dd} ← the `balance.low` email to the source's contact, once a
|
|
527
|
+
* day at most (§12.4; member-emails.ts) — the webhook is
|
|
528
|
+
* once per crossing, keyed by `balanceLowAt`
|
|
529
|
+
* wh:{eventId}:{endpointId|claim} ← one webhook event to one target (`kind: "webhook"`, §4.5)
|
|
530
|
+
* inv:{memberId}:{tokenHash[0,16]} ← an email invite (`member_invite`, member-emails §2); a
|
|
531
|
+
* re-invite mints a new token, so a new row
|
|
532
|
+
* acc:{memberId} ← "invitation accepted" to the inviter (`member_accepted`, §3)
|
|
533
|
+
* grant:{memberId}:{delegationCid} ← "access granted" to the member (`member_granted`, §4)
|
|
534
|
+
*
|
|
535
|
+
* `notice_paused`/`notice_resumed` alternate PER COLLECTION (not per reason, and not owner-pooled
|
|
536
|
+
* like eval-engine v1's billing notices — this kit has one `status` column and no shared
|
|
537
|
+
* subscription/payout accounts to group): a state is announced only when its own marker is not
|
|
538
|
+
* already the newer of the pair, so a step retry inside one pause re-sends nothing and a pause
|
|
539
|
+
* following a recovery is a fresh notice.
|
|
540
|
+
*
|
|
541
|
+
* `resultDigest` is captured ONLY on the `review_request` row, at send time — the PRE-fold digest
|
|
542
|
+
* "the frozen evaluation the reviewer's answers bind to" (events.ts). `deliverReviewFold` reads it
|
|
543
|
+
* back from HERE, never from `decisions.resultDigest`, which the fold has already overwritten with
|
|
544
|
+
* the NEW (post-fold) digest by the time the edit is built.
|
|
545
|
+
*
|
|
546
|
+
* Rows are mutable (attempts/lastError); nothing here ever influences a decision — delivery only,
|
|
547
|
+
* exactly like the engine's own `decisions.chainStatus` lane.
|
|
548
|
+
*/
|
|
549
|
+
export const matrixDeliveries = sqliteTable("matrix_deliveries", {
|
|
550
|
+
dedupeKey: text().primaryKey(),
|
|
551
|
+
// A TEXT column: the enum is type-only (SQLite, same note as watched_collections.pausedReason
|
|
552
|
+
// above), so adding a kind needs no migration — `db:generate` reports nothing.
|
|
553
|
+
kind: text({
|
|
554
|
+
enum: [
|
|
555
|
+
"review_room",
|
|
556
|
+
"review_request",
|
|
557
|
+
"review_fold",
|
|
558
|
+
"notice_paused",
|
|
559
|
+
"notice_resumed",
|
|
560
|
+
"notice_review_email",
|
|
561
|
+
"notice_review_reminder",
|
|
562
|
+
"notice_review_expired",
|
|
563
|
+
"review_invite",
|
|
564
|
+
"review_notice",
|
|
565
|
+
"review_email",
|
|
566
|
+
"review_reminder",
|
|
567
|
+
"review_window",
|
|
568
|
+
"member_invite",
|
|
569
|
+
"member_accepted",
|
|
570
|
+
"member_granted",
|
|
571
|
+
"notice_balance_low",
|
|
572
|
+
"notice_review_billing_expiring",
|
|
573
|
+
"notice_review_billing_cap",
|
|
574
|
+
"webhook",
|
|
575
|
+
],
|
|
576
|
+
}).notNull(),
|
|
577
|
+
claimId: text(),
|
|
578
|
+
collectionId: text(),
|
|
579
|
+
/** The resolved room id — an alias resolved, or `createRoom`'s answer. */
|
|
580
|
+
roomId: text(),
|
|
581
|
+
/** The sent (or edited) event id. */
|
|
582
|
+
eventId: text(),
|
|
583
|
+
/** The `review_request` row's PRE-fold `resultDigest` — see the table header comment. */
|
|
584
|
+
resultDigest: text(),
|
|
585
|
+
/**
|
|
586
|
+
* `pending` and `dead` are the webhook lane's: queued before the first attempt (enqueue sets
|
|
587
|
+
* `nextAttemptAt = now`, so the retry cron's due read finds it even if the first inline attempt
|
|
588
|
+
* never ran), and out of attempts (8 over 24 h, Go Prod §4.5) — the dead-letter the portal
|
|
589
|
+
* shows and a redeliver re-queues. A `failed` webhook row with a `nextAttemptAt` is due for the
|
|
590
|
+
* retry cron. On the wire (`webhook.status`, the delivery log) `sent` reads `delivered`.
|
|
591
|
+
* `sending` is the review/member emails' claim (lib/api-lane/reviewers.ts `claimRows`): the
|
|
592
|
+
* row is written before the send so two callers never both send; a crash mid-send leaves it.
|
|
593
|
+
*/
|
|
594
|
+
status: text({ enum: ["sent", "failed", "skipped", "pending", "dead", "sending"] })
|
|
595
|
+
.notNull()
|
|
596
|
+
.default("failed"),
|
|
597
|
+
attempts: integer().notNull().default(0),
|
|
598
|
+
lastError: text(),
|
|
599
|
+
// --- `kind: "webhook"` only (Go Prod §4.5, §6.1); null on every Matrix/email row. The row is
|
|
600
|
+
// `wh:<eventId>:<endpointId>` (or `wh:<eventId>:claim` for a per-claim `webhookUrl`) — one
|
|
601
|
+
// row per event per target, so a redeliver re-queues the same row instead of adding one. ---
|
|
602
|
+
sourceId: text(),
|
|
603
|
+
/** The `webhook_endpoints` row, or null for the claim's own `webhookUrl`. */
|
|
604
|
+
endpointId: text(),
|
|
605
|
+
/** Where it is posted — copied at enqueue, so an endpoint edit never retargets a sent event. */
|
|
606
|
+
targetUrl: text(),
|
|
607
|
+
/** The App. B event type (`claim.decided`, …). */
|
|
608
|
+
eventType: text(),
|
|
609
|
+
/**
|
|
610
|
+
* The signed envelope's JSON, frozen at enqueue so every retry posts the same bytes the
|
|
611
|
+
* `Oracle-Event-Id` promises. Carries the record (metadata included — personal data), so the
|
|
612
|
+
* oracle never deletes the row on its own (owner, 2026-10-11); erasing a claim nulls `payload` and
|
|
613
|
+
* `targetUrl` on its rows too.
|
|
614
|
+
*/
|
|
615
|
+
payload: text({ mode: "json" }).$type(),
|
|
616
|
+
/** When the retry cron may attempt it next; null once delivered or dead. */
|
|
617
|
+
nextAttemptAt: integer({ mode: "timestamp_ms" }),
|
|
618
|
+
/** The receiver's last HTTP status (null on a network failure) — the delivery log's column. */
|
|
619
|
+
lastStatusCode: integer(),
|
|
620
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
621
|
+
.notNull()
|
|
622
|
+
.$defaultFn(() => new Date()),
|
|
623
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
624
|
+
.notNull()
|
|
625
|
+
.$defaultFn(() => new Date())
|
|
626
|
+
.$onUpdate(() => new Date()),
|
|
627
|
+
}, (t) => [
|
|
628
|
+
index("matrix_deliveries_claim_idx").on(t.claimId),
|
|
629
|
+
// The webhook-retry cron's read: due rows of one kind, oldest due first.
|
|
630
|
+
index("matrix_deliveries_due_idx").on(t.kind, t.status, t.nextAttemptAt),
|
|
631
|
+
// The delivery log (`GET /v1/api/webhooks/deliveries`): one source's rows, newest first.
|
|
632
|
+
index("matrix_deliveries_source_created_idx").on(t.sourceId, t.createdAt),
|
|
633
|
+
// A kind's rows oldest first (the review batch flush, reviewers.ts) without a full scan.
|
|
634
|
+
index("matrix_deliveries_kind_created_idx").on(t.kind, t.createdAt),
|
|
635
|
+
]);
|
|
636
|
+
// ------------------------------------------------------------------------------------------------
|
|
637
|
+
// The Decision API lane (Go Prod §3, §6.1). Every table below is written only when `API_LANE` is on;
|
|
638
|
+
// with it off they exist empty. An API claim reuses `claim_ingests` / `decisions` / the registries
|
|
639
|
+
// under the scope id `api:<sourceId>:<protocolDid>` in their `collectionId`, so nothing above changes
|
|
640
|
+
// meaning. `sourceId` scopes every read: across sources a row does not exist (404, never 403, §14).
|
|
641
|
+
// ------------------------------------------------------------------------------------------------
|
|
642
|
+
/**
|
|
643
|
+
* One organisation's account with this oracle (Go Prod §3.2) — the API lane's `watched_collections`.
|
|
644
|
+
* `ownerDid` is the IXO account whose deed pays; members and keys hang off `sourceId`.
|
|
645
|
+
*/
|
|
646
|
+
export const apiSources = sqliteTable("api_sources", {
|
|
647
|
+
/** `src_<ULID>`. */
|
|
648
|
+
sourceId: text().primaryKey(),
|
|
649
|
+
name: text().notNull(),
|
|
650
|
+
/** The paying IXO account (`did:ixo`) — the root of its members' payment delegations. */
|
|
651
|
+
ownerDid: text().notNull(),
|
|
652
|
+
/**
|
|
653
|
+
* Protocol DIDs this source may submit against (§17). EMPTY = NONE — unlike the chain lane's
|
|
654
|
+
* `supportedProtocols`, where empty means "no restriction": a source can only ever be narrowed to
|
|
655
|
+
* nothing, never opened to everything by an empty list. Sign-up copies the oracle's catalogue.
|
|
656
|
+
*/
|
|
657
|
+
allowedProtocols: text({ mode: "json" }).$type().notNull().default([]),
|
|
658
|
+
/**
|
|
659
|
+
* UNUSED since contracts v1.1: there are no per-source prices — every source pays the oracle's
|
|
660
|
+
* published price (payments spec §3.1), and a partner who should not pay gets `billingMode:
|
|
661
|
+
* none`. Kept only because dropping a column is a table rebuild in SQLite.
|
|
662
|
+
*/
|
|
663
|
+
priceOverrides: text({ mode: "json" }).$type(),
|
|
664
|
+
/**
|
|
665
|
+
* How the source pays (§3.2): `x402` — an outside customer pays per decision (§11) — or `none` —
|
|
666
|
+
* the operator's own organisation or an unbilled partner: no 402, no `api_charges` row. Set by the
|
|
667
|
+
* oracle's operator only, never by a member: it is a commercial term.
|
|
668
|
+
*/
|
|
669
|
+
billingMode: text({ enum: ["x402", "none"] })
|
|
670
|
+
.notNull()
|
|
671
|
+
.default("x402"),
|
|
672
|
+
/** The `balance.low` floor (§12.4), whole cents; null = no alert. */
|
|
673
|
+
refillFloorCents: integer(),
|
|
674
|
+
/**
|
|
675
|
+
* When the balance watch last saw the balance cross BELOW the floor; cleared when it recovers.
|
|
676
|
+
* The watch runs every 15 min — this is what keeps it to one `balance.low` per crossing.
|
|
677
|
+
*/
|
|
678
|
+
balanceLowAt: integer({ mode: "timestamp_ms" }),
|
|
679
|
+
/** Default target for claims that name no `webhookUrl` and no endpoint subscribes. */
|
|
680
|
+
webhookUrl: text(),
|
|
681
|
+
/**
|
|
682
|
+
* The source's ONE signing secret for deliveries to a claim's own `webhookUrl` and to the default
|
|
683
|
+
* `webhookUrl` above (§4.5) — encrypted exactly like `webhook_endpoints.secretCiphertext`
|
|
684
|
+
* (`v1:<ciphertext>`), created with the source and shown once. Null for a source created before
|
|
685
|
+
* contracts v1.1: those deliveries then stay `dead` ("no signing secret") until an owner rotates.
|
|
686
|
+
*/
|
|
687
|
+
webhookSecretCiphertext: text(),
|
|
688
|
+
/** The secret a rotation replaced, still signing beside the new one for 24 h — as an endpoint's. */
|
|
689
|
+
previousWebhookSecretCiphertext: text(),
|
|
690
|
+
previousWebhookSecretExpiresAt: integer({ mode: "timestamp_ms" }),
|
|
691
|
+
/**
|
|
692
|
+
* D10: a source starts `pending-link` and turns `active` when the company sync reads its
|
|
693
|
+
* organisation's link from the engine; a link for another entity (or the engine's `disputed`)
|
|
694
|
+
* makes it `disputed`. Neither takes claims, keys, invites or webhooks (`409
|
|
695
|
+
* SOURCE_PENDING_LINK` / `SOURCE_DISPUTED`). `paused` answers new submits `503 SOURCE_PAUSED`
|
|
696
|
+
* (App. A); in-flight claims finish. Reasons (paused only) as App. A's `details.reason`:
|
|
697
|
+
* `rubric-unusable`, `engine-credits`, `payments-disabled`, and `operator` for a hand pause from
|
|
698
|
+
* the operator view. TEXT with a type-only enum (no migration), like
|
|
699
|
+
* `watched_collections.pausedReason`.
|
|
700
|
+
*/
|
|
701
|
+
status: text({ enum: ["pending-link", "active", "paused", "disputed"] })
|
|
702
|
+
.notNull()
|
|
703
|
+
.default("active"),
|
|
704
|
+
/**
|
|
705
|
+
* The first time the company sync made the source `active`; set once, never cleared (a later
|
|
706
|
+
* `disputed` keeps it). Null ⇒ the source was never active, so its id has never left its
|
|
707
|
+
* organisation's controllers: logs hash it (`sourceLogId`) and only their listing shows it (never
|
|
708
|
+
* the operator's). On the wire as `Source.activatedAt` (1.17.0).
|
|
709
|
+
*/
|
|
710
|
+
activatedAt: integer({ mode: "timestamp_ms" }),
|
|
711
|
+
pausedReason: text({
|
|
712
|
+
enum: ["rubric-unusable", "engine-credits", "payments-disabled", "operator"],
|
|
713
|
+
}),
|
|
714
|
+
contactEmail: text(),
|
|
715
|
+
/** Operator-only free text (the operator view); never shown to the source. */
|
|
716
|
+
notes: text(),
|
|
717
|
+
/**
|
|
718
|
+
* The organisation (its on-chain entity) this source belongs to (company authority D1, D10): set
|
|
719
|
+
* at insert by the controller who adds the oracle, never changed. Its CURRENT controllers are the
|
|
720
|
+
* source's roots (`lib/api-lane/company.ts` `sourceRoots`). Nullable in SQL only — a table rebuild
|
|
721
|
+
* to say NOT NULL is not worth its risk: every insert sets it, migration 0017 deleted the rows
|
|
722
|
+
* made before D10, and `sourceView` refuses a null.
|
|
723
|
+
*/
|
|
724
|
+
companyEntityDid: text(),
|
|
725
|
+
/**
|
|
726
|
+
* A COPY of the controller-signed `SourceCompanyLink` JWS the engine holds (owner: the engine is
|
|
727
|
+
* the link's single home — the Console PUTs it there, this oracle reads it with `company/read` and
|
|
728
|
+
* never verifies or forwards it). Kept verbatim so a reader can check what the mirror came from.
|
|
729
|
+
*/
|
|
730
|
+
companyLink: text(),
|
|
731
|
+
/** The engine's link `issuedAt` as last read — a sync that reads an older one is stale. */
|
|
732
|
+
companyLinkIssuedAt: integer({ mode: "timestamp_ms" }),
|
|
733
|
+
/** A copy of the link's `credentialSubject.payeeField` (D3), for reads; the JWS is the truth. */
|
|
734
|
+
payeeField: text(),
|
|
735
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
736
|
+
.notNull()
|
|
737
|
+
.$defaultFn(() => new Date()),
|
|
738
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
739
|
+
.notNull()
|
|
740
|
+
.$defaultFn(() => new Date())
|
|
741
|
+
.$onUpdate(() => new Date()),
|
|
742
|
+
});
|
|
743
|
+
/**
|
|
744
|
+
* API keys (Go Prod §3.2, §3.3): `eo_live_<prefix>_<secret>` / `eo_test_…`. The prefix is the lookup
|
|
745
|
+
* (PK), the sha256 of the whole key the proof — the key itself is shown once and never stored.
|
|
746
|
+
* Revoked rows stay a year for the audit trail. Rotation (§3.3) sets the old key's `revokedAt` in
|
|
747
|
+
* the FUTURE (up to 30 days), so auth admits a key while `revokedAt IS NULL OR revokedAt > now`.
|
|
748
|
+
*/
|
|
749
|
+
export const apiKeys = sqliteTable("api_keys", {
|
|
750
|
+
/** The 8-char prefix — unique, the lookup, and what the masked form shows. */
|
|
751
|
+
prefix: text().primaryKey(),
|
|
752
|
+
/** Lowercase hex sha256 of the full key string. */
|
|
753
|
+
keyHash: text().notNull(),
|
|
754
|
+
sourceId: text().notNull(),
|
|
755
|
+
/** A label for the Keys page. */
|
|
756
|
+
name: text(),
|
|
757
|
+
/** `eo_live_` (mainnet) or `eo_test_` (the testnet sandbox, §3.2). */
|
|
758
|
+
environment: text({ enum: ["live", "test"] }).notNull(),
|
|
759
|
+
scopes: text({ mode: "json" })
|
|
760
|
+
.$type()
|
|
761
|
+
.notNull(),
|
|
762
|
+
/** Daily spend cap, whole cents (§4.1 `402 SPEND_CAP`); null = no cap beyond the delegation's. */
|
|
763
|
+
maxSpendCentsPerDay: integer(),
|
|
764
|
+
/** Who created it (a member's `did:ixo`, or the operator). */
|
|
765
|
+
createdBy: text(),
|
|
766
|
+
lastUsedAt: integer({ mode: "timestamp_ms" }),
|
|
767
|
+
revokedAt: integer({ mode: "timestamp_ms" }),
|
|
768
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
769
|
+
.notNull()
|
|
770
|
+
.$defaultFn(() => new Date()),
|
|
771
|
+
}, (t) => [index("api_keys_source_idx").on(t.sourceId)]);
|
|
772
|
+
/**
|
|
773
|
+
* People on a source (Go Prod §3.2): an IXO account, a role, and the `did:key` their review answers
|
|
774
|
+
* are signed with (§10). Invited by email, bound to a DID on accept — so `did` is null until then.
|
|
775
|
+
* One DID once per source (the unique index; SQLite admits many NULLs). Removed on request.
|
|
776
|
+
*
|
|
777
|
+
* A role is a UCAN delegation (§3.4, contracts v1.1): the owner signs, in their browser, a grant of
|
|
778
|
+
* the role's preset (`ROLE_CAPABILITIES`) over the source's resource to the member's DID, and the
|
|
779
|
+
* row keeps it (`delegation` + `delegationCid`) with what it says (`nbProtocols`, `expiresAt`) so
|
|
780
|
+
* a check needs no CAR parse. `role` is the preset's label, nothing more. The owner row is the root
|
|
781
|
+
* and carries no grant. A member without a stored grant can call nothing. Revoking stamps
|
|
782
|
+
* `revokedAt` AND lists the CID in `api_revocations`; a role change is a revoke plus a new grant.
|
|
783
|
+
*/
|
|
784
|
+
export const apiMembers = sqliteTable("api_members", {
|
|
785
|
+
/** `mem_<ULID>`. */
|
|
786
|
+
memberId: text().primaryKey(),
|
|
787
|
+
sourceId: text().notNull(),
|
|
788
|
+
/** The member's `did:ixo` (AuthHub); null while the invite is open. */
|
|
789
|
+
did: text(),
|
|
790
|
+
email: text(),
|
|
791
|
+
role: text({ enum: ["owner", "developer", "reviewer", "viewer", "submitter"] }).notNull(),
|
|
792
|
+
/** The owner's signed grant, base64 of the delegation CAR; null until uploaded (and for the owner). */
|
|
793
|
+
delegation: text(),
|
|
794
|
+
/** The grant's CID — what a revocation lists and what `api_revocations` is checked against. */
|
|
795
|
+
delegationCid: text(),
|
|
796
|
+
/** The grant's `nb.protocols`: the protocols its `claims/*` are narrowed to; null = all. */
|
|
797
|
+
nbProtocols: text({ mode: "json" }).$type(),
|
|
798
|
+
/** The grant's expiry, in ms — a UCAN `exp` is in SECONDS, so `exp * 1000`; null = none. */
|
|
799
|
+
expiresAt: integer({ mode: "timestamp_ms" }),
|
|
800
|
+
revokedAt: integer({ mode: "timestamp_ms" }),
|
|
801
|
+
/**
|
|
802
|
+
* Lowercase hex sha256 of an email invite's one-time `inviteToken` (shown once, never stored);
|
|
803
|
+
* cleared on accept. Unique, so accept is one indexed lookup.
|
|
804
|
+
*/
|
|
805
|
+
inviteTokenHash: text(),
|
|
806
|
+
/**
|
|
807
|
+
* When the email invite (`inviteTokenHash`) stops working — 7 days after it was sent (§3.4
|
|
808
|
+
* step 2); null for a member invited by DID, and once accepted.
|
|
809
|
+
*/
|
|
810
|
+
inviteExpiresAt: integer({ mode: "timestamp_ms" }),
|
|
811
|
+
/** The Ed25519 `did:key` generated in their browser; a review answer's issuer must be one of these. */
|
|
812
|
+
reviewerDid: text(),
|
|
813
|
+
/**
|
|
814
|
+
* The member's own link to `reviewerDid` (company authority D2, F1): base64 CAR of the member
|
|
815
|
+
* did:ixo → reviewer did:key `claims/review` delegation, signed by the member — the middle of the
|
|
816
|
+
* chain the engine walks to name the member on the fold's receipt. Null until signed.
|
|
817
|
+
*/
|
|
818
|
+
reviewerDelegation: text(),
|
|
819
|
+
/** That delegation's expiry, in ms (`exp * 1000`); null = none or none uploaded. */
|
|
820
|
+
reviewerDelegationExpiresAt: integer({ mode: "timestamp_ms" }),
|
|
821
|
+
/** The member's own switch for review emails (§10.1); Matrix follows the room's mute instead. */
|
|
822
|
+
notifyReviews: integer({ mode: "boolean" }).notNull().default(true),
|
|
823
|
+
/**
|
|
824
|
+
* When this member was last sent a review email for this source — the 15-minute window
|
|
825
|
+
* (§10.1, member-emails §6) opens here, and claims arriving inside it are held for one batch
|
|
826
|
+
* (lib/api-lane/reviewers.ts). Claimed by a conditional UPDATE, so two racing notify steps
|
|
827
|
+
* never both send.
|
|
828
|
+
*/
|
|
829
|
+
reviewEmailAt: integer({ mode: "timestamp_ms" }),
|
|
830
|
+
invitedBy: text(),
|
|
831
|
+
invitedAt: integer({ mode: "timestamp_ms" })
|
|
832
|
+
.notNull()
|
|
833
|
+
.$defaultFn(() => new Date()),
|
|
834
|
+
acceptedAt: integer({ mode: "timestamp_ms" }),
|
|
835
|
+
}, (t) => [
|
|
836
|
+
uniqueIndex("api_members_source_did_idx").on(t.sourceId, t.did),
|
|
837
|
+
// The console's role lookup at sign-in: every source a DID belongs to.
|
|
838
|
+
index("api_members_did_idx").on(t.did),
|
|
839
|
+
// The review gate (§10.2): is this `did:key` a reviewer key of a member of THIS source? One
|
|
840
|
+
// key per member — registering from a second browser replaces it.
|
|
841
|
+
uniqueIndex("api_members_source_reviewer_idx").on(t.sourceId, t.reviewerDid),
|
|
842
|
+
uniqueIndex("api_members_invite_token_idx").on(t.inviteTokenHash),
|
|
843
|
+
]);
|
|
844
|
+
/**
|
|
845
|
+
* A source's revocation list (§3.4): the CIDs of member grants the owner has withdrawn. Revoking
|
|
846
|
+
* adds the CID here and it is effective at once — every grant check reads this list, so a copy of
|
|
847
|
+
* the CAR still held by a browser (or re-uploaded) proves nothing. A grant REPLACED by a new one (a
|
|
848
|
+
* role change is a revoke plus a new grant) lands here too. Rows are never deleted: a CID is
|
|
849
|
+
* revoked for life. The PK is the lookup and the added-once mutex.
|
|
850
|
+
*/
|
|
851
|
+
export const apiRevocations = sqliteTable("api_revocations", {
|
|
852
|
+
sourceId: text().notNull(),
|
|
853
|
+
cid: text().notNull(),
|
|
854
|
+
/** The member's `did:ixo` who revoked it, or the operator. */
|
|
855
|
+
revokedBy: text(),
|
|
856
|
+
revokedAt: integer({ mode: "timestamp_ms" })
|
|
857
|
+
.notNull()
|
|
858
|
+
.$defaultFn(() => new Date()),
|
|
859
|
+
}, (t) => [primaryKey({ columns: [t.sourceId, t.cid] })]);
|
|
860
|
+
/**
|
|
861
|
+
* An API claim's body and envelope (Go Prod §6.1, §6.2) — the D1 store the `api` `ClaimSource` pulls
|
|
862
|
+
* from. `body` is the canonical JSON of the answers; `bodyDigest` its sha256, checked on every pull
|
|
863
|
+
* (a mismatch fails closed, never a retry). Erasure nulls `body` (and `attachments`, `submitter`,
|
|
864
|
+
* `metadata`, `webhookUrl`, `content` — the personal data of §6.3), the claim's webhook rows' `payload` and
|
|
865
|
+
* `targetUrl`, deletes its `api_uploads` objects, and stamps `bodyErasedAt`; the row, the digests
|
|
866
|
+
* and the decision survive. Written in the SAME `db.batch` as the `claim_ingests` row and the
|
|
867
|
+
* `api_charges` row at accept (§4.6).
|
|
868
|
+
*/
|
|
869
|
+
export const apiClaims = sqliteTable("api_claims", {
|
|
870
|
+
/** `apc_…` — also the `claim_ingests` / `decisions` key. */
|
|
871
|
+
claimId: text().primaryKey(),
|
|
872
|
+
sourceId: text().notNull(),
|
|
873
|
+
protocolDid: text().notNull(),
|
|
874
|
+
/** Canonical JSON of `answers`; null once erased. */
|
|
875
|
+
body: text({ mode: "json" }).$type(),
|
|
876
|
+
/** sha256 hex of the canonical body — the pull's integrity check; survives erasure. */
|
|
877
|
+
bodyDigest: text().notNull(),
|
|
878
|
+
/** The request's attachment descriptors (question, name, mediaType, url, cid) — never bytes. */
|
|
879
|
+
attachments: text({ mode: "json" }).$type(),
|
|
880
|
+
/** The org's end-user id, for display; personal data, so erased. */
|
|
881
|
+
submitter: text(),
|
|
882
|
+
/**
|
|
883
|
+
* HMAC-SHA256 (`UNIQUE_HMAC_KEY`) of `sourceId|submitter` — the frequency counter's key (§9),
|
|
884
|
+
* and why it is not `submitter` itself: it SURVIVES erasure, so a claim erased early still
|
|
885
|
+
* counts in its window. Null without a submitter ⇒ the fact is `unresolved`.
|
|
886
|
+
*/
|
|
887
|
+
submitterDigest: text(),
|
|
888
|
+
/** Echoed on every webhook and GET, never evaluated (≤ 4 KB). */
|
|
889
|
+
metadata: text({ mode: "json" }).$type(),
|
|
890
|
+
idempotencyKey: text(),
|
|
891
|
+
/**
|
|
892
|
+
* sha256 of the whole canonical request — what a repeat of the same `Idempotency-Key` is
|
|
893
|
+
* compared against (`409 IDEMPOTENCY_MISMATCH`, §4.1). Null without a key.
|
|
894
|
+
*/
|
|
895
|
+
requestDigest: text(),
|
|
896
|
+
webhookUrl: text(),
|
|
897
|
+
/**
|
|
898
|
+
* How the claim came in when not by an API key or the console: `oauth:<client_id>` for an AI
|
|
899
|
+
* app connected to `/v1/mcp` over OAuth (S7). Stamped on its `accepted` event; null otherwise.
|
|
900
|
+
*/
|
|
901
|
+
via: text(),
|
|
902
|
+
/** The x402 offer to pay IF approved (§11.10). UNUSED at GA (contracts v1.1: no decision-to-pay,
|
|
903
|
+
* a submit carries no `payment`); always null, kept so the feature can return without a migration. */
|
|
904
|
+
payment: text({ mode: "json" }).$type(),
|
|
905
|
+
receivedAt: integer({ mode: "timestamp_ms" })
|
|
906
|
+
.notNull()
|
|
907
|
+
.$defaultFn(() => new Date()),
|
|
908
|
+
/** When the organisation erased the body (`DELETE /v1/api/claims/:claimId/body`) — never on a clock. */
|
|
909
|
+
bodyErasedAt: integer({ mode: "timestamp_ms" }),
|
|
910
|
+
/**
|
|
911
|
+
* `contentDigest(content)` (lib/hash.ts, `sha256:<hex>`) — the claim's content id, which the
|
|
912
|
+
* receipt carries and the SDK recomputes from what the app sent (company authority D3, A8).
|
|
913
|
+
* Survives erasure, like `bodyDigest`. Null for a claim accepted before contracts v1.7.
|
|
914
|
+
*/
|
|
915
|
+
contentDigest: text(),
|
|
916
|
+
/**
|
|
917
|
+
* The claim CONTENT exactly as digested (`ApiClaimContent`): the submit body minus transport,
|
|
918
|
+
* with the resolved `protocolDid`, the caller's explicit `submitter` only and the attachments
|
|
919
|
+
* as SENT (before media-type detection rewrites `attachments` above). Kept apart from `body` so
|
|
920
|
+
* the engine can recompute the digest; it holds the answers, so it is erased with them.
|
|
921
|
+
*/
|
|
922
|
+
content: text({ mode: "json" }).$type(),
|
|
923
|
+
/** Who SENT the claim, set server-side from the caller, never from the content: the OAuth
|
|
924
|
+
* user's DID (hosted MCP); null for an API key or a console submit, and before contracts v1.7.
|
|
925
|
+
* Not who the claim is about — that is `submitter`. */
|
|
926
|
+
submittedBy: text(),
|
|
927
|
+
/** WHICH AI app sent it (contracts v1.12.0 `submittedVia.name`): the OAuth client's registered
|
|
928
|
+
* name (`caller.clientName`, the AuthHub token's `client_name`), trimmed, ≤ 100 chars; null
|
|
929
|
+
* for an API key, a console submit and a chain claim. Self-declared at dynamic client
|
|
930
|
+
* registration, so a display hint for the console — never an authorisation input. */
|
|
931
|
+
submittedVia: text(),
|
|
932
|
+
/** The token's `verified` at submit (`submittedVia.verified`): AuthHub saw only Claude's or
|
|
933
|
+
* ChatGPT's own callback registered, so the token can only be theirs. Null iff
|
|
934
|
+
* `submittedVia` is. */
|
|
935
|
+
submittedViaVerified: integer({ mode: "boolean" }),
|
|
936
|
+
}, (t) => [
|
|
937
|
+
// The list route's keyset (`GET /v1/api/claims`): one source, newest first.
|
|
938
|
+
index("api_claims_source_received_idx").on(t.sourceId, t.receivedAt, t.claimId),
|
|
939
|
+
// The frequency counter (§9): one D1 count per (source, protocol, submitter, window).
|
|
940
|
+
index("api_claims_frequency_idx").on(t.sourceId, t.protocolDid, t.submitterDigest, t.receivedAt),
|
|
941
|
+
]);
|
|
942
|
+
/**
|
|
943
|
+
* The oracle's pointer to each claim's payment (Go Prod §6.1, §11.3; payments spec §4, §13.4). The
|
|
944
|
+
* facilitator's reservations and settlements are the financial record; this row is for the timeline,
|
|
945
|
+
* support, the reconcile cron and the per-key cap. One row per accepted claim — `claimId` is the
|
|
946
|
+
* charged-once mutex. No refunds (nothing moves without a receipt, payments spec §0 rule 1).
|
|
947
|
+
*
|
|
948
|
+
* Lifecycle (contracts v1.3, standard x402): the row lands `reserved` in the accept batch, AFTER
|
|
949
|
+
* `/verify` reserved the price (the claim starts only then); after the decision row, `/settle` with
|
|
950
|
+
* the engine's receipt answers `settlement_pending` ⇒ `settled` (the receipt is accepted, the
|
|
951
|
+
* minute's transfer has not paid it yet) or `success` ⇒ `paid` with `txHash`; `reservation_released`
|
|
952
|
+
* ⇒ `released` (24 h without a receipt: nothing moved); any other refusal ⇒ `failed`, never retried.
|
|
953
|
+
* The reconcile re-settles `reserved`/`settled` rows of decided claims with the identical body until
|
|
954
|
+
* `paid`, and marks `released` a reservation past the facilitator's 24 h with no receipt — which a
|
|
955
|
+
* late settle the facilitator still accepts overwrites (`reservation_expired_late`). `settlementId` is the facilitator's, one per offer, so a batch's claims share it; `amount`
|
|
956
|
+
* is always THIS claim's price.
|
|
957
|
+
*/
|
|
958
|
+
export const apiCharges = sqliteTable("api_charges", {
|
|
959
|
+
claimId: text().primaryKey(),
|
|
960
|
+
sourceId: text().notNull(),
|
|
961
|
+
/** The facilitator's settlement id (`org.udid.receipt@1` `settlementId`, 64 hex); null until settled. */
|
|
962
|
+
settlementId: text(),
|
|
963
|
+
/** Base units of `asset`, as a string (`"1200000"` = 1.20 PAY). */
|
|
964
|
+
amount: text().notNull(),
|
|
965
|
+
asset: text().notNull().default("upay"),
|
|
966
|
+
/** The facilitator offer (the 402's single-use nonce). */
|
|
967
|
+
offerId: text(),
|
|
968
|
+
/** The account at the root of the payment delegation — who was charged. */
|
|
969
|
+
payerDid: text(),
|
|
970
|
+
/** The API key that submitted — what the per-key daily cap (`402 SPEND_CAP`, §4.1) sums over. */
|
|
971
|
+
keyPrefix: text(),
|
|
972
|
+
/**
|
|
973
|
+
* `oauth:<grant id>` for a claim an AI app submitted over OAuth (S7) — what the per-grant daily
|
|
974
|
+
* cap sums over, as `keyPrefix` is for a key; null for a key or a console submit.
|
|
975
|
+
*/
|
|
976
|
+
via: text(),
|
|
977
|
+
/** `amount` in whole USD cents (1 PAY = 1 USD), so the cap sums integers, never casts upay strings. */
|
|
978
|
+
amountCents: integer().notNull(),
|
|
979
|
+
/** TEXT with a type-only enum: adding a value needs no migration. */
|
|
980
|
+
status: text({
|
|
981
|
+
enum: [
|
|
982
|
+
// A chain claim's offer registered, its `/verify` not answered yet (review-billing.ts): a
|
|
983
|
+
// retry re-verifies the stored header, never re-offers. Never on an API claim.
|
|
984
|
+
"offered",
|
|
985
|
+
"reserved",
|
|
986
|
+
"settled",
|
|
987
|
+
"paid",
|
|
988
|
+
"released",
|
|
989
|
+
"failed",
|
|
990
|
+
// Card only (PAY's transfer is final): the facilitator's refund, read there (refund.ts).
|
|
991
|
+
"refunded",
|
|
992
|
+
"partially_refunded",
|
|
993
|
+
],
|
|
994
|
+
})
|
|
995
|
+
.notNull()
|
|
996
|
+
.default("reserved"),
|
|
997
|
+
/** The transfer that paid it (`/settle`'s `transaction`, a chain tx hash) — only ever real. */
|
|
998
|
+
txHash: text(),
|
|
999
|
+
/** The facilitator's last `/settle` answer, verbatim: a sync 200's `PAYMENT-RESPONSE`. A
|
|
1000
|
+
* pre-v1.3 hold keeps its old id here instead (`{ legacyChargeId }`). */
|
|
1001
|
+
settleResult: text({ mode: "json" }).$type(),
|
|
1002
|
+
/** The verified `PAYMENT-SIGNATURE` every `/settle` of this claim is built from (identical on
|
|
1003
|
+
* every retry), SEALED (`v1:`, payments/header-seal.ts — it embeds the payer's reusable
|
|
1004
|
+
* payment delegation); KV holds a second copy. Null for rows written before contracts v1.3;
|
|
1005
|
+
* in the clear on rows written before 2026-10-14, until the housekeeping sweep seals them. */
|
|
1006
|
+
paymentHeader: text(),
|
|
1007
|
+
/** What the header pays with (`ixo-pay` | `stripe-manual-capture` | `exact`), in the clear so
|
|
1008
|
+
* a claim read never decrypts. Null on rows the sweep has not reached (read off a clear header). */
|
|
1009
|
+
scheme: text({ enum: ["ixo-pay", "stripe-manual-capture", "exact"] }),
|
|
1010
|
+
/**
|
|
1011
|
+
* Per-review checker billing: `chain` for a CHAIN claim's charge (the claim id is the chain's,
|
|
1012
|
+
* `collectionId` its collection) — the two fields the facilitator keys the reservation by
|
|
1013
|
+
* besides the claim (x402-ixo-pay 0.7.0). Null = an API decision.
|
|
1014
|
+
*/
|
|
1015
|
+
lane: text({ enum: ["chain"] }),
|
|
1016
|
+
collectionId: text(),
|
|
1017
|
+
/**
|
|
1018
|
+
* When the facilitator will release the reservation, once a `pending_review` claim's hold was
|
|
1019
|
+
* extended for its human review (`POST /v1/reservations/extend`, payments/extend.ts); null =
|
|
1020
|
+
* the default 24 h from `createdAt`. What the reconcile's expiry arm and a review's deadline read.
|
|
1021
|
+
*/
|
|
1022
|
+
reservationExpiresAt: integer({ mode: "timestamp_ms" }),
|
|
1023
|
+
/**
|
|
1024
|
+
* A card payment's refund, as the facilitator reports it (`GET /v1/card/refunds/:claimId`,
|
|
1025
|
+
* payments/refund.ts) — never on the console's word. Null for PAY and an unrefunded card.
|
|
1026
|
+
*/
|
|
1027
|
+
refundedAt: integer({ mode: "timestamp_ms" }),
|
|
1028
|
+
refundId: text(),
|
|
1029
|
+
refundedAmountCents: integer(),
|
|
1030
|
+
/** When the reconcile last asked the facilitator about this card charge's refund (its turn). */
|
|
1031
|
+
refundCheckedAt: integer({ mode: "timestamp_ms" }),
|
|
1032
|
+
error: text(),
|
|
1033
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1034
|
+
.notNull()
|
|
1035
|
+
.$defaultFn(() => new Date()),
|
|
1036
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
1037
|
+
.notNull()
|
|
1038
|
+
.$defaultFn(() => new Date())
|
|
1039
|
+
.$onUpdate(() => new Date()),
|
|
1040
|
+
}, (t) => [
|
|
1041
|
+
index("api_charges_settlement_idx").on(t.settlementId),
|
|
1042
|
+
// The reconcile: open rows by status, the least recently tried first.
|
|
1043
|
+
index("api_charges_status_updated_idx").on(t.status, t.updatedAt),
|
|
1044
|
+
// The Spend page: one source's charges by day.
|
|
1045
|
+
index("api_charges_source_created_idx").on(t.sourceId, t.createdAt),
|
|
1046
|
+
// The per-key daily cap: today's charges of one key.
|
|
1047
|
+
index("api_charges_key_created_idx").on(t.keyPrefix, t.createdAt),
|
|
1048
|
+
// The per-grant daily cap (S7): today's charges of one OAuth grant.
|
|
1049
|
+
index("api_charges_via_created_idx").on(t.via, t.createdAt),
|
|
1050
|
+
// The daily reconciliation (one day across every source) and the retention trim.
|
|
1051
|
+
index("api_charges_created_idx").on(t.createdAt),
|
|
1052
|
+
]);
|
|
1053
|
+
/**
|
|
1054
|
+
* A source's standing review-billing delegation (per-review checker billing,
|
|
1055
|
+
* active by IXO's plan for the oracle; payments/review-billing.ts): the x402-ixo-pay payment delegation its
|
|
1056
|
+
* organisation's chain OWNER signed — one `billing/pay` to the facilitator, bound to this oracle
|
|
1057
|
+
* alone (`nb.oracles`) — that pays for every chain claim of the organisation's collections. One
|
|
1058
|
+
* row per source, and one source per organisation holding a live one (the PUT route enforces it).
|
|
1059
|
+
*
|
|
1060
|
+
* `delegationCiphertext` is a bearer credential: sealed (`v1:`, webhook-crypto.ts), never logged,
|
|
1061
|
+
* never returned, never a step result. `spentUpay` is this oracle's mirror of what the facilitator
|
|
1062
|
+
* counts against the delegation's `maxAmount` (it exposes no read): raised by ONE conditional
|
|
1063
|
+
* statement per reservation (`spentUpay + price ≤ capUpay`), given back only when `/verify` reserved
|
|
1064
|
+
* nothing — a lapsed reservation keeps counting, as the facilitator's does. With `nb.oracles` =
|
|
1065
|
+
* [this oracle] nobody else can spend the CID, so the mirror is exact. A new CID starts at 0, as
|
|
1066
|
+
* the facilitator's per-CID count does. `capUpay` is `maxAmount` capped to a safe integer (the
|
|
1067
|
+
* comparison is SQL), `maxAmount` the exact string. Deleted with the source, and 30 days past
|
|
1068
|
+
* `expiresAt` by the housekeeping sweep.
|
|
1069
|
+
*/
|
|
1070
|
+
export const reviewBillingDelegations = sqliteTable("review_billing_delegations", {
|
|
1071
|
+
sourceId: text().primaryKey(),
|
|
1072
|
+
/** The delegation's issuer — the organisation's chain owner when stored; who pays. */
|
|
1073
|
+
payerDid: text().notNull(),
|
|
1074
|
+
delegationCid: text().notNull(),
|
|
1075
|
+
/** `nb.maxAmount`, upay base units, exact. */
|
|
1076
|
+
maxAmount: text().notNull(),
|
|
1077
|
+
capUpay: integer().notNull(),
|
|
1078
|
+
spentUpay: integer().notNull().default(0),
|
|
1079
|
+
expiresAt: integer({ mode: "timestamp_ms" }).notNull(),
|
|
1080
|
+
notBefore: integer({ mode: "timestamp_ms" }),
|
|
1081
|
+
delegationCiphertext: text().notNull(),
|
|
1082
|
+
/** The member who stored it (`keys/manage` or a controller) — not necessarily the payer. */
|
|
1083
|
+
createdBy: text().notNull(),
|
|
1084
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1085
|
+
.notNull()
|
|
1086
|
+
.$defaultFn(() => new Date()),
|
|
1087
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
1088
|
+
.notNull()
|
|
1089
|
+
.$defaultFn(() => new Date())
|
|
1090
|
+
.$onUpdate(() => new Date()),
|
|
1091
|
+
}, (t) => [
|
|
1092
|
+
// The expiry reminders and the housekeeping sweep: rows by expiry.
|
|
1093
|
+
index("review_billing_delegations_expires_idx").on(t.expiresAt),
|
|
1094
|
+
]);
|
|
1095
|
+
/**
|
|
1096
|
+
* The per-claim timeline (`GET /v1/api/claims/:claimId/events`, Go Prod §4.2): accepted, paid, facts
|
|
1097
|
+
* produced (names and durations, NEVER values), decided, webhook attempts, review answered, folded,
|
|
1098
|
+
* erased. Append-only, one statement per event; source-level events carry a null `claimId`. Kept a
|
|
1099
|
+
* year (the retention cron trims). The claim index is not source-scoped: a timeline read proves the
|
|
1100
|
+
* claim is the caller's through `api_claims` first (404 otherwise, §14).
|
|
1101
|
+
*/
|
|
1102
|
+
export const apiEvents = sqliteTable("api_events", {
|
|
1103
|
+
/** `evt_<ULID>` — sortable, so the timeline orders by id. */
|
|
1104
|
+
eventId: text().primaryKey(),
|
|
1105
|
+
sourceId: text().notNull(),
|
|
1106
|
+
claimId: text(),
|
|
1107
|
+
type: text().notNull(),
|
|
1108
|
+
/** Small, log-safe detail: fact names + durations, a status code, the engine's issues. Never an answer. */
|
|
1109
|
+
data: text({ mode: "json" }).$type(),
|
|
1110
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1111
|
+
.notNull()
|
|
1112
|
+
.$defaultFn(() => new Date()),
|
|
1113
|
+
}, (t) => [
|
|
1114
|
+
index("api_events_claim_idx").on(t.claimId, t.eventId),
|
|
1115
|
+
index("api_events_source_created_idx").on(t.sourceId, t.createdAt),
|
|
1116
|
+
index("api_events_created_idx").on(t.createdAt),
|
|
1117
|
+
]);
|
|
1118
|
+
/** Every portal, CLI and operator action on a source — who, what, when (Go Prod §6.1; kept 2 years). */
|
|
1119
|
+
export const apiAudit = sqliteTable("api_audit", {
|
|
1120
|
+
/** `aud_<ULID>`. */
|
|
1121
|
+
auditId: text().primaryKey(),
|
|
1122
|
+
/** Null for an operator action not tied to one source. */
|
|
1123
|
+
sourceId: text(),
|
|
1124
|
+
/** Who acted — a member or operator DID, or the API key's prefix. */
|
|
1125
|
+
actor: text().notNull(),
|
|
1126
|
+
/** What `actor` is, so the audit log can show it without guessing from the string. */
|
|
1127
|
+
/**
|
|
1128
|
+
* `system` is the oracle acting on its own schedule (a cron); its `actor` is then
|
|
1129
|
+
* `system:<job>`, e.g. `system:link-recheck`. `oauth` is a user acting through an AI app over
|
|
1130
|
+
* OAuth (S7). TEXT with a type-only enum: a new kind is no migration.
|
|
1131
|
+
*/
|
|
1132
|
+
actorKind: text({ enum: ["member", "key", "operator", "system", "oauth"] }).notNull(),
|
|
1133
|
+
/**
|
|
1134
|
+
* For `actorKind: oauth` (S7) — the user's `did:ixo` is `actor`, and these name the AI app
|
|
1135
|
+
* acting for them, as AuthHub registered it. Null for every other kind.
|
|
1136
|
+
*/
|
|
1137
|
+
clientId: text(),
|
|
1138
|
+
clientName: text(),
|
|
1139
|
+
/** `key.created`, `key.revoked`, `member.invited`, `claim.erased`, `source.paused`, … */
|
|
1140
|
+
action: text().notNull(),
|
|
1141
|
+
/** What it acted on (a key prefix, a member id, a claim id). */
|
|
1142
|
+
target: text(),
|
|
1143
|
+
details: text({ mode: "json" }).$type(),
|
|
1144
|
+
requestId: text(),
|
|
1145
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1146
|
+
.notNull()
|
|
1147
|
+
.$defaultFn(() => new Date()),
|
|
1148
|
+
}, (t) => [
|
|
1149
|
+
index("api_audit_source_created_idx").on(t.sourceId, t.createdAt),
|
|
1150
|
+
index("api_audit_created_idx").on(t.createdAt),
|
|
1151
|
+
]);
|
|
1152
|
+
/**
|
|
1153
|
+
* A source's webhook endpoints (Go Prod §4.5). The signing secret is stored ENCRYPTED with the
|
|
1154
|
+
* deployment's `WEBHOOK_ENCRYPTION_KEY` (§6.1) — it must be recoverable to sign, so a hash will not
|
|
1155
|
+
* do. `events` empty = every event. Deliveries are `matrix_deliveries` rows of `kind: "webhook"`.
|
|
1156
|
+
*/
|
|
1157
|
+
export const webhookEndpoints = sqliteTable("webhook_endpoints", {
|
|
1158
|
+
/** `whe_<ULID>`. */
|
|
1159
|
+
endpointId: text().primaryKey(),
|
|
1160
|
+
sourceId: text().notNull(),
|
|
1161
|
+
url: text().notNull(),
|
|
1162
|
+
/**
|
|
1163
|
+
* The HMAC secret, encrypted at rest; returned in clear once, on create or rotate. Prefixed
|
|
1164
|
+
* with the key version (`v1:<ciphertext>`) so `WEBHOOK_ENCRYPTION_KEY` can be rotated (§14's
|
|
1165
|
+
* compromise runbook) by re-encrypting row by row.
|
|
1166
|
+
*/
|
|
1167
|
+
secretCiphertext: text().notNull(),
|
|
1168
|
+
/**
|
|
1169
|
+
* The secret a rotation replaced, still signing beside the new one until
|
|
1170
|
+
* `previousSecretExpiresAt` (24 h) — the signature header then carries one `v1=` per live
|
|
1171
|
+
* secret, so a receiver can swap without dropping events.
|
|
1172
|
+
*/
|
|
1173
|
+
previousSecretCiphertext: text(),
|
|
1174
|
+
previousSecretExpiresAt: integer({ mode: "timestamp_ms" }),
|
|
1175
|
+
events: text({ mode: "json" }).$type().notNull().default([]),
|
|
1176
|
+
status: text({ enum: ["active", "disabled"] })
|
|
1177
|
+
.notNull()
|
|
1178
|
+
.default("active"),
|
|
1179
|
+
description: text(),
|
|
1180
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1181
|
+
.notNull()
|
|
1182
|
+
.$defaultFn(() => new Date()),
|
|
1183
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
1184
|
+
.notNull()
|
|
1185
|
+
.$defaultFn(() => new Date())
|
|
1186
|
+
.$onUpdate(() => new Date()),
|
|
1187
|
+
}, (t) => [index("webhook_endpoints_source_idx").on(t.sourceId)]);
|
|
1188
|
+
/**
|
|
1189
|
+
* The idempotency store for every POST/PUT that is not a claim submit (Go Prod §4.1): same key +
|
|
1190
|
+
* same request ⇒ the stored answer for 24 h; same key + a different request ⇒ `409
|
|
1191
|
+
* IDEMPOTENCY_MISMATCH`. The INSERT with `onConflictDoNothing` is the in-flight mutex (`status:
|
|
1192
|
+
* in_flight` until the answer lands). A claim submit does not use it: its `claimId` is derived from
|
|
1193
|
+
* the key, so the `claim_ingests` PK is the guard and `api_claims.requestDigest` the mismatch check
|
|
1194
|
+
* — and a repeat answers the claim's CURRENT state, not a stored response (§4.6).
|
|
1195
|
+
*
|
|
1196
|
+
* An `in_flight` row older than 60 s is a request that died: the next attempt reclaims it with one
|
|
1197
|
+
* conditional upsert (`onConflictDoUpdate … where status = 'in_flight' and created_at < now - 60s`),
|
|
1198
|
+
* so a crash never locks a key for the day. A response carrying a one-time secret (a new API key,
|
|
1199
|
+
* a webhook secret) is stored WITHOUT it — the secret field replaced by null — since keys live only
|
|
1200
|
+
* as hashes and secrets only encrypted (§3.2, §6.1); the replay says so, and the caller rotates.
|
|
1201
|
+
*/
|
|
1202
|
+
export const apiIdempotency = sqliteTable("api_idempotency", {
|
|
1203
|
+
sourceId: text().notNull(),
|
|
1204
|
+
idempotencyKey: text().notNull(),
|
|
1205
|
+
/** sha256 of method + path + canonical body. */
|
|
1206
|
+
requestDigest: text().notNull(),
|
|
1207
|
+
status: text({ enum: ["in_flight", "done"] })
|
|
1208
|
+
.notNull()
|
|
1209
|
+
.default("in_flight"),
|
|
1210
|
+
responseStatus: integer(),
|
|
1211
|
+
responseBody: text({ mode: "json" }).$type(),
|
|
1212
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1213
|
+
.notNull()
|
|
1214
|
+
.$defaultFn(() => new Date()),
|
|
1215
|
+
/** createdAt + 24 h; the retention cron deletes past it. */
|
|
1216
|
+
expiresAt: integer({ mode: "timestamp_ms" }).notNull(),
|
|
1217
|
+
}, (t) => [
|
|
1218
|
+
primaryKey({ columns: [t.sourceId, t.idempotencyKey] }),
|
|
1219
|
+
index("api_idempotency_expires_idx").on(t.expiresAt),
|
|
1220
|
+
]);
|
|
1221
|
+
/**
|
|
1222
|
+
* Files uploaded through `PUT /v1/api/uploads` (Go Prod §6.2), and the export bundles: the R2
|
|
1223
|
+
* object's pointer, so an erase or the housekeeping sweep can find every object without reading
|
|
1224
|
+
* erasable claim columns. `claimId` is bound when a submit references the upload, and the claim's
|
|
1225
|
+
* erase deletes it. `deleteAt` is set only by an organisation's own action — an export bundle's one
|
|
1226
|
+
* day, a deleted source's files — and the hourly sweep then deletes the object and the row; null =
|
|
1227
|
+
* kept (the oracle never deletes an organisation's files on its own).
|
|
1228
|
+
*/
|
|
1229
|
+
export const apiUploads = sqliteTable("api_uploads", {
|
|
1230
|
+
/** `upl_<ULID>`. */
|
|
1231
|
+
uploadId: text().primaryKey(),
|
|
1232
|
+
sourceId: text().notNull(),
|
|
1233
|
+
/** `uploads/<sourceId>/<ULID>` in `API_UPLOADS`. */
|
|
1234
|
+
r2Key: text().notNull(),
|
|
1235
|
+
cid: text().notNull(),
|
|
1236
|
+
mediaType: text().notNull(),
|
|
1237
|
+
size: integer().notNull(),
|
|
1238
|
+
claimId: text(),
|
|
1239
|
+
deleteAt: integer({ mode: "timestamp_ms" }),
|
|
1240
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1241
|
+
.notNull()
|
|
1242
|
+
.$defaultFn(() => new Date()),
|
|
1243
|
+
}, (t) => [
|
|
1244
|
+
index("api_uploads_delete_idx").on(t.deleteAt),
|
|
1245
|
+
index("api_uploads_claim_idx").on(t.claimId),
|
|
1246
|
+
]);
|
|
1247
|
+
/**
|
|
1248
|
+
* On-chain collections an organisation (a source) has linked, so its claim reads include that
|
|
1249
|
+
* collection's CHAIN claims (Go Prod S3 M6). Linked by a console member who is, ON CHAIN, the
|
|
1250
|
+
* collection entity's owner (company authority D9); the hourly re-check
|
|
1251
|
+
* (`lib/api-lane/linked.ts`) drops a link whose linker no longer owns it — the link
|
|
1252
|
+
* rides on that one member's standing, never the source's. Billing for these claims stays the
|
|
1253
|
+
* collection owner's on-chain evaluation payment: nothing is charged at the oracle.
|
|
1254
|
+
*
|
|
1255
|
+
* The same collection may be linked to several sources (PK `(sourceId, collectionId)`); the
|
|
1256
|
+
* `collectionId` index serves "which sources see this collection". `checkedAt` rotates the
|
|
1257
|
+
* re-check: least recently checked first, every link each hour up to a hard cap. `verifiedAt` is
|
|
1258
|
+
* the last check that CONFIRMED the linker's standing — a record for operators, never a read
|
|
1259
|
+
* filter: a link is shown while the row exists, and only the re-check's POSITIVE finding deletes it
|
|
1260
|
+
* (lib/api-lane/linked.ts header). An unreadable chain or engine keeps it.
|
|
1261
|
+
*/
|
|
1262
|
+
export const apiSourceCollections = sqliteTable("api_source_collections", {
|
|
1263
|
+
sourceId: text().notNull(),
|
|
1264
|
+
collectionId: text().notNull(),
|
|
1265
|
+
/** The collection's protocol, read off the chain at link time. */
|
|
1266
|
+
protocolDid: text().notNull(),
|
|
1267
|
+
/** The member's `did:ixo` — whose standing the re-check verifies. */
|
|
1268
|
+
linkedBy: text().notNull(),
|
|
1269
|
+
linkedAt: integer({ mode: "timestamp_ms" })
|
|
1270
|
+
.notNull()
|
|
1271
|
+
.$defaultFn(() => new Date()),
|
|
1272
|
+
checkedAt: integer({ mode: "timestamp_ms" })
|
|
1273
|
+
.notNull()
|
|
1274
|
+
.$defaultFn(() => new Date()),
|
|
1275
|
+
/** The last check that confirmed the linker's standing (the link itself is the first). */
|
|
1276
|
+
verifiedAt: integer({ mode: "timestamp_ms" })
|
|
1277
|
+
.notNull()
|
|
1278
|
+
.$defaultFn(() => new Date()),
|
|
1279
|
+
/**
|
|
1280
|
+
* Consecutive re-checks that found no such collection on chain. One is not enough to unlink —
|
|
1281
|
+
* an indexer that lags or re-syncs answers "not found" for a while — so the link goes on the
|
|
1282
|
+
* second in a row; any confirmed check resets it.
|
|
1283
|
+
*/
|
|
1284
|
+
missCount: integer().notNull().default(0),
|
|
1285
|
+
}, (t) => [
|
|
1286
|
+
primaryKey({ columns: [t.sourceId, t.collectionId] }),
|
|
1287
|
+
index("api_source_collections_collection_idx").on(t.collectionId),
|
|
1288
|
+
index("api_source_collections_checked_idx").on(t.checkedAt),
|
|
1289
|
+
]);
|
|
1290
|
+
/**
|
|
1291
|
+
* One AI Gateway call per row (spec 2026-10-02 §6) — the `cloudflare` provider's spend, for
|
|
1292
|
+
* operators and admin apps only: nothing that decides or verifies reads it. Written once per build
|
|
1293
|
+
* by builder.ts (`onConflictDoNothing` on the gateway log id — a replayed write inserts nothing);
|
|
1294
|
+
* the USD lands later from the gateway's own log (cron/ai-cost.ts): `pending` → `ok`, or
|
|
1295
|
+
* `unavailable` (logging off, no price for the model, retention). OpenRouter calls are not here —
|
|
1296
|
+
* their cost is frozen on the FactSet at call time. Trimmed after 90 days by the same job.
|
|
1297
|
+
*/
|
|
1298
|
+
export const aiCalls = sqliteTable("ai_calls", {
|
|
1299
|
+
/** The gateway log id (`cf-aig-log-id`). */
|
|
1300
|
+
callId: text().primaryKey(),
|
|
1301
|
+
claimId: text().notNull(),
|
|
1302
|
+
/** `<name>` of the ai check (or `<name>#n` for a handler's nth judge call), or `unique.judge`. */
|
|
1303
|
+
fact: text().notNull(),
|
|
1304
|
+
model: text().notNull(),
|
|
1305
|
+
promptTokens: integer(),
|
|
1306
|
+
completionTokens: integer(),
|
|
1307
|
+
cachedTokens: integer(),
|
|
1308
|
+
/** USD × 1e6 — integers, the money rule. Null until backfilled. */
|
|
1309
|
+
costMicroUsd: integer(),
|
|
1310
|
+
costStatus: text({ enum: ["pending", "ok", "unavailable"] })
|
|
1311
|
+
.notNull()
|
|
1312
|
+
.default("pending"),
|
|
1313
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1314
|
+
.notNull()
|
|
1315
|
+
.$defaultFn(() => new Date()),
|
|
1316
|
+
costAt: integer({ mode: "timestamp_ms" }),
|
|
1317
|
+
}, (t) => [
|
|
1318
|
+
index("ai_calls_pending_idx").on(t.costStatus, t.createdAt),
|
|
1319
|
+
index("ai_calls_claim_idx").on(t.claimId),
|
|
1320
|
+
]);
|
|
1321
|
+
/**
|
|
1322
|
+
* One per-submit approval of an AI app's claim (MCP over OAuth, spec 2026-10-06; S7). An OAuth
|
|
1323
|
+
* caller's `submit_claim` never pays on the token alone: the first call files this row and answers
|
|
1324
|
+
* `APPROVAL_REQUIRED` with AuthHub's approve link; the user approves THERE (AuthHub reads the row
|
|
1325
|
+
* over the back-channel, `GET /v1/oauth/approvals/:id`, so the page shows the oracle's record, never
|
|
1326
|
+
* the model's words) and AuthHub posts back a one-claim payment delegation. The same request again
|
|
1327
|
+
* finds the row by `(grantId, requestDigest)` and spends it ONCE: a conditional UPDATE
|
|
1328
|
+
* (`approved` → `used`) claims it before anything is paid. A card that wants 3-D Secure parks it
|
|
1329
|
+
* as `awaiting_3ds`, bound to that offer and PaymentIntent, until the resume.
|
|
1330
|
+
*
|
|
1331
|
+
* `delegation` is a bearer credential: never logged, never returned (the GET back-channel omits
|
|
1332
|
+
* it), and NULL again the moment the row is used, declined or expired. The housekeeping sweep deletes
|
|
1333
|
+
* rows past `expiresAt`.
|
|
1334
|
+
*/
|
|
1335
|
+
export const mcpApprovals = sqliteTable("mcp_approvals", {
|
|
1336
|
+
/** 128 random bits, base64url (22 chars) — the approve link's `id`. */
|
|
1337
|
+
id: text().primaryKey(),
|
|
1338
|
+
/** AuthHub's grant (`gid`) the token carried: an approval never moves to another app. */
|
|
1339
|
+
grantId: text().notNull(),
|
|
1340
|
+
/** The user (`sub`, a `did:ixo`) — the delegation's root issuer must be this. */
|
|
1341
|
+
did: text().notNull(),
|
|
1342
|
+
sourceId: text().notNull(),
|
|
1343
|
+
protocolDid: text().notNull(),
|
|
1344
|
+
clientId: text().notNull(),
|
|
1345
|
+
clientName: text().notNull(),
|
|
1346
|
+
/** sha256 over protocol, source, canonical body, attachments and the idempotency key. */
|
|
1347
|
+
requestDigest: text().notNull(),
|
|
1348
|
+
/** The price as the approve page shows it (`$1.20`, or `No charge`). */
|
|
1349
|
+
price: text().notNull(),
|
|
1350
|
+
/** What the delegation must cover, upay (1 PAY = 1 USD = 1 000 000 upay); `0` for `none`. */
|
|
1351
|
+
maxAmountUpay: text().notNull(),
|
|
1352
|
+
/** The source's billing mode when asked: `none` approves without a delegation. */
|
|
1353
|
+
billingMode: text({ enum: ["x402", "none"] }).notNull(),
|
|
1354
|
+
/** TEXT with a type-only enum. */
|
|
1355
|
+
status: text({ enum: ["pending", "approved", "awaiting_3ds", "used", "expired", "declined"] })
|
|
1356
|
+
.notNull()
|
|
1357
|
+
.default("pending"),
|
|
1358
|
+
/** The one-claim payment delegation (base64 CAR); null until approved, and once spent. */
|
|
1359
|
+
delegation: text(),
|
|
1360
|
+
/**
|
|
1361
|
+
* `awaiting_3ds` only: the card offer and PaymentIntent the bank asked to confirm. Only a resume
|
|
1362
|
+
* of exactly that offer, paid by exactly that PaymentIntent, may spend the row again.
|
|
1363
|
+
*/
|
|
1364
|
+
offerId: text(),
|
|
1365
|
+
paymentIntentId: text(),
|
|
1366
|
+
/** 15 min after asking; reset to 15 min after approving, for the retry to use it. */
|
|
1367
|
+
expiresAt: integer({ mode: "timestamp_ms" }).notNull(),
|
|
1368
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1369
|
+
.notNull()
|
|
1370
|
+
.$defaultFn(() => new Date()),
|
|
1371
|
+
}, (t) => [
|
|
1372
|
+
// The retry's lookup, and the find-or-create's mutex: at most ONE live approval per app and
|
|
1373
|
+
// exact request, so two racing first calls file one row (`onConflictDoNothing`).
|
|
1374
|
+
uniqueIndex("mcp_approvals_live_idx")
|
|
1375
|
+
.on(t.grantId, t.requestDigest)
|
|
1376
|
+
.where(sql `status in ('pending', 'approved', 'awaiting_3ds')`),
|
|
1377
|
+
// The housekeeping sweep.
|
|
1378
|
+
index("mcp_approvals_expires_idx").on(t.expiresAt),
|
|
1379
|
+
]);
|
|
1380
|
+
/**
|
|
1381
|
+
* A grant's auto-approve ("don't ask again", spec 2026-10-06 "Auto-approve"; S7): the standing
|
|
1382
|
+
* payment authority the user gave an AI app on AuthHub — up to `perClaimUpay` a claim and
|
|
1383
|
+
* `totalUpay` in all, until `until`. One row per AuthHub grant. `delegation` is a bearer credential
|
|
1384
|
+
* whose `maxAmount` IS `totalUpay` (the facilitator enforces the total too): never logged or
|
|
1385
|
+
* returned, deleted with the row. `spentUpay` is moved only by single conditional statements, so
|
|
1386
|
+
* concurrent submits can never take it past `totalUpay`. Amounts are upay INTEGERs (the total is at
|
|
1387
|
+
* most $100 = 1e8 upay, far inside SQLite's 64-bit range).
|
|
1388
|
+
*/
|
|
1389
|
+
export const mcpStanding = sqliteTable("mcp_standing", {
|
|
1390
|
+
/** AuthHub's grant (`gid`). */
|
|
1391
|
+
grantId: text().primaryKey(),
|
|
1392
|
+
/** The user (`sub`): the delegation's root issuer. */
|
|
1393
|
+
did: text().notNull(),
|
|
1394
|
+
perClaimUpay: integer().notNull(),
|
|
1395
|
+
totalUpay: integer().notNull(),
|
|
1396
|
+
spentUpay: integer().notNull().default(0),
|
|
1397
|
+
until: integer({ mode: "timestamp_ms" }).notNull(),
|
|
1398
|
+
/** The standing payment delegation (base64 CAR), `maxAmount` = `totalUpay`. */
|
|
1399
|
+
delegation: text(),
|
|
1400
|
+
updatedAt: integer({ mode: "timestamp_ms" })
|
|
1401
|
+
.notNull()
|
|
1402
|
+
.$defaultFn(() => new Date())
|
|
1403
|
+
.$onUpdate(() => new Date()),
|
|
1404
|
+
});
|
|
1405
|
+
/**
|
|
1406
|
+
* A grant's ONE day counter and per-request lock (S3 reviews of #87 and #90). Three kinds of row,
|
|
1407
|
+
* all keyed (grant, key):
|
|
1408
|
+
* - an auto-approve spend (key = the request digest): written in the SAME `db.batch` as the
|
|
1409
|
+
* `mcp_standing` spend, which lands only if this row did — so a retry of the same request (a
|
|
1410
|
+
* model timeout, an ambiguous failure) never spends or pays again;
|
|
1411
|
+
* - a one-claim approval's spend (`approvalSpendKey`), written by `spendApproval`, whose flip
|
|
1412
|
+
* needs it — so the $20/day cap is atomic across both paths; a restore deletes it;
|
|
1413
|
+
* - an answer's marker (`answer:<approval id>`, 0 upay): the one AuthHub answer that won an
|
|
1414
|
+
* approval (`approveWithStanding`).
|
|
1415
|
+
* Each spend row is kept on any outcome but a proven-nothing-reserved refund or restore, which
|
|
1416
|
+
* deletes it in the same batch. `upay` is what the daily cap sums. The sweep trims old rows.
|
|
1417
|
+
*/
|
|
1418
|
+
export const mcpStandingSpends = sqliteTable("mcp_standing_spends", {
|
|
1419
|
+
grantId: text().notNull(),
|
|
1420
|
+
/** The approval digest of the request (`approvalDigest`). */
|
|
1421
|
+
requestDigest: text().notNull(),
|
|
1422
|
+
/** Random per attempt: the spend's own claim on the row (its batch checks it is this one). */
|
|
1423
|
+
spendId: text().notNull(),
|
|
1424
|
+
upay: integer().notNull(),
|
|
1425
|
+
createdAt: integer({ mode: "timestamp_ms" })
|
|
1426
|
+
.notNull()
|
|
1427
|
+
.$defaultFn(() => new Date()),
|
|
1428
|
+
}, (t) => [
|
|
1429
|
+
primaryKey({ columns: [t.grantId, t.requestDigest] }),
|
|
1430
|
+
// The daily cap's sum, and the sweep.
|
|
1431
|
+
index("mcp_standing_spends_grant_created_idx").on(t.grantId, t.createdAt),
|
|
1432
|
+
]);
|
|
1433
|
+
//# sourceMappingURL=schema.js.map
|