@fourier-labs/harbour-contracts 0.46.0 → 0.50.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.
Files changed (40) hide show
  1. package/README.md +32 -6
  2. package/contract-release.json +30 -30
  3. package/dist/gen-ts/ai-policy-snapshot.d.ts +19 -0
  4. package/dist/gen-ts/ai-runtime-contract.d.ts +1 -1
  5. package/dist/gen-ts/ai-trace-event.d.ts +4 -1
  6. package/dist/gen-ts/app-integrations-declaration.d.ts +9 -2
  7. package/dist/gen-ts/contract-release.d.ts +6 -6
  8. package/dist/gen-ts/contract-release.js +6 -6
  9. package/dist/gen-ts/data-grant-v2.d.ts +60 -16
  10. package/dist/gen-ts/integration-error-details.d.ts +2 -2
  11. package/dist/gen-ts/integration-execute-request.d.ts +44 -4
  12. package/dist/gen-ts/integration-execute-result.d.ts +21 -1
  13. package/dist/gen-ts/saas-connection.d.ts +80 -29
  14. package/dist/gen-ts/transform-report.d.ts +2 -0
  15. package/dist/gen-ts/well-defined-app-manifest.d.ts +31 -0
  16. package/dist/resolver/index.d.ts +7 -1
  17. package/gen-ts/ai-policy-snapshot.ts +19 -0
  18. package/gen-ts/ai-runtime-contract.ts +1 -1
  19. package/gen-ts/ai-trace-event.ts +4 -1
  20. package/gen-ts/app-integrations-declaration.ts +9 -2
  21. package/gen-ts/contract-release.ts +6 -6
  22. package/gen-ts/data-grant-v2.ts +67 -16
  23. package/gen-ts/integration-error-details.ts +10 -2
  24. package/gen-ts/integration-execute-request.ts +50 -4
  25. package/gen-ts/integration-execute-result.ts +21 -1
  26. package/gen-ts/saas-connection.ts +87 -29
  27. package/gen-ts/transform-report.ts +2 -0
  28. package/gen-ts/well-defined-app-manifest.ts +31 -0
  29. package/package.json +1 -1
  30. package/schema/ai-policy-snapshot.schema.json +13 -1
  31. package/schema/ai-runtime-contract.schema.json +1 -1
  32. package/schema/ai-trace-event.schema.json +7 -1
  33. package/schema/app-integrations-declaration.schema.json +22 -6
  34. package/schema/data-grant-v2.schema.json +102 -23
  35. package/schema/integration-error-details.schema.json +10 -2
  36. package/schema/integration-execute-request.schema.json +53 -7
  37. package/schema/integration-execute-result.schema.json +36 -1
  38. package/schema/saas-connection.schema.json +97 -41
  39. package/schema/transform-report.schema.json +2 -1
  40. package/schema/well-defined-app-manifest.schema.json +61 -0
package/README.md CHANGED
@@ -25,7 +25,7 @@ exist here first.
25
25
  | `error-envelope.schema.json` | The failure envelope emitted once per FAILED transition | §2.1 |
26
26
  | `error-category.enum.json` | Closed failure-category enum + per-category `retryable` registry | §2.2 |
27
27
  | `artifact-contract.schema.json` | Build output contract (the provider-portability seam), including the digest-pinned well-defined app manifest reference | §3 |
28
- | `well-defined-app-manifest.schema.json` | Versioned runtime wiring for static, full-stack, and browser-first apps: workloads, schedules, queues, and service bindings | Well-defined apps P0 |
28
+ | `well-defined-app-manifest.schema.json` | Versioned runtime wiring for static, full-stack, and browser-first apps: workloads, schedules, queues, service bindings, language runtime, browser capabilities, and route authentication | Well-defined apps P0 |
29
29
  | `version-state.schema.json` | State machine T1a — states, legal transitions, versionId format | §1 |
30
30
  | `env-bindings.schema.json` | `EnvBindings` / `Target` / `Binding` (BYOC-complete) | §4.2.2 |
31
31
  | `kvs-routing-entry.schema.json` | CloudFront KVS routing value (`{static, api}`) | §8 |
@@ -38,10 +38,36 @@ exist here first.
38
38
  | `binding-classification-subject.schema.json` | Complete value-free binding-name classification before version allocation | AI governance §5.7 / SEC-UP-01 |
39
39
  | `sanitized-binding-evidence.schema.json` | Exact-version sanitized runtime-binding allocation receipt | AI governance §5.7 / SEC-UP-02 |
40
40
  | `ai-pricing-revision`, `ai-metering-policy`, `ai-budget-ledger-event`, `ai-trace-event-v2` | Additive metering v2 records, including media dimensions and P5 trace attribution; v1 records remain readable | AI governance §9 |
41
- | `app-integrations-declaration.schema.json` | Committed `.harbour/integrations.json` (`harbour.app-integrations/2.0`): closed three-operation set with fixed identity modes; owns the shared operation/identity/environment enums | Dev kit §4 |
42
- | `integration-execute-request`, `integration-execute-result`, `integration-connect-result`, `integration-error-details` | App SDK integrations wire contract on `/_harbour/integrations/*`: per-operation input bounds, the three result shapes, consent states and the closed `details.code` reason set | Dev kit §4, §8 |
43
- | `saas-connection.schema.json`, `data-grant-v2.schema.json` | Tenant SaaS connection record and the additive `harbour.data-grant/2.0` grant record (status machine generated; legacy `data-grant` untouched) | Dev kit §5 |
41
+ | `app-integrations-declaration.schema.json` | Committed `.harbour/integrations.json` (`harbour.app-integrations/2.0`): closed five-operation set (Slack read/post, Gmail read-only, warehouse view read) with fixed identity modes; owns the shared operation/identity/environment enums | Dev kit §4 |
42
+ | `integration-execute-request`, `integration-execute-result`, `integration-connect-result`, `integration-error-details` | App SDK integrations wire contract on `/_harbour/integrations/*`: per-operation input bounds, the five result shapes, consent states and the closed `details.code` reason set | Dev kit §4, §8 |
43
+ | `saas-connection.schema.json`, `data-grant-v2.schema.json` | Tenant SaaS connection record (one installation and channel map per tenant and provider) and the additive `harbour.data-grant/2.0` grant record with structured resources and provisioning lease/cleanup (status machine generated; legacy `data-grant` untouched) | Dev kit §5 |
44
44
  | `kit-bundle-manifest.schema.json`, `kit-lock.schema.json` | Published kit bundle identity (SDK tarball digest plus optional `sdk.version` and https `sdk.url` download location) and the committed `.harbour/kit.lock.json` the CodeBuild SDK-vendoring gate compares against | Dev kit §3 |
45
+ | `deploy-response.schema.json` | 202 Accepted body for `POST /v1/tenants/{tenant}/apps/{app}/deployments`, returned only after the authoritative QUEUED version exists and its SQS message is accepted | — |
46
+ | `deployment-source.schema.json` | Credential-free GitHub source in the `DeployRequest` body; credentials are resolved internally by MaterializeSource | — |
47
+ | `deployment-environment.schema.json` | Public environment accepted by the preview APIs (`preview` only; production is reachable only through promotion) | — |
48
+ | `api-error-response.schema.json` | Safe JSON error body for Deploy/Status Lambda 4xx/5xx responses; distinct from the internal `ErrorEnvelope` | — |
49
+ | `deployment-status-request.schema.json` | Validated path parameters for `GET /v1/tenants/{tenant}/apps/{app}/deployments/{versionId}` | — |
50
+ | `deployment-status-response.schema.json` | 200 OK body for GET status: that exact immutable version, with the `progress` trail, `deployTarget` and `diagnosticRef` | — |
51
+ | `deployment-status-failure.schema.json` | Frontend-safe failure projection nested in a failed status response; a digest-bound `diagnosticRef` locates the redacted diagnostic | — |
52
+ | `promotion-request.schema.json` | Body for `POST /v1/tenants/{tenant}/apps/{app}/promotions`; repository identity comes from stored records, not the caller | ADR 0003 |
53
+ | `promotion-response.schema.json` | 202 Accepted body returned once the production version and its durable idempotency binding exist | ADR 0003 |
54
+ | `transform-report.schema.json` | Structured output an agent must return from one transformation attempt; handed to the agent as its output schema and re-validated by the control plane | — |
55
+ | `transform-parked-result.schema.json` | Sequential-preview result after a durable checkpoint when builder input is required; not a successful report | — |
56
+ | `builder-input-proposal.schema.json` | Value-free proposal emitted when sequential preview cannot continue without builder-owned input | — |
57
+ | `deployment-continuation.schema.json` | Immutable reference admitting one child deployment from a parked input request; never credential values | — |
58
+ | `security-scan-input.schema.json` | Input to the Security Assurance machine: SOURCE (M1) scans an ingested commit, ARTIFACT (M2) scans built outputs | Security Assurance §2 |
59
+ | `security-verdict.schema.json` | Security Assurance decision; `BLOCKED` surfaces as the non-retryable `gate.security-scan` category | Security Assurance §2 |
60
+ | `data-source.schema.json` | Admin-registered external data source; `credentialRef` is a secretref URI and the credential never crosses this boundary | Data-Access MVP |
61
+ | `data-dependency.schema.json` | One external data dependency of an app, declared or detected, classified against the tenant's data-source inventory | Data-Access MVP |
62
+ | `secret-reference.schema.json` | Named secret slot an app depends on; only the reference and its lifecycle cross, never the value | Secret-Manager MVP |
63
+ | `ai-callsite-inventory.schema.json` | Immutable, sanitized AI call-site discovery for one exact deployment version (detection only) | AI governance |
64
+ | `ai-runtime-contract.schema.json` | Immutable runtime contract derived by an AI Governance PLAN decision; scoped configuration plus a Secrets Manager reference | AI governance |
65
+ | `ai-policy-snapshot.schema.json` | Immutable, content-addressed AI policy snapshot consumed by the AI Gateway | AI governance |
66
+ | `ai-gateway-key-lookup.schema.json` | Value-free Gateway authentication metadata for one version-scoped Harbour key | AI governance |
67
+ | `ai-trace-event.schema.json` | Value-free asynchronous AI Gateway trace metadata (v1); raw prompts and responses never enter the queue | AI governance |
68
+ | `ai-transform-event.schema.json` | Checksum-bound deterministic AI interception task input carrying the ordered PLAN interception plan | AI governance |
69
+ | `ai-transform-result.schema.json` | Bounded deterministic interception result: descriptors and digest evidence only | AI governance |
70
+ | `ai-verification-evidence.schema.json` | Bounded, value-free evidence submitted by deployment verification for one governed version | AI governance |
45
71
 
46
72
  Runtime resource profiles are a closed contract shared by transformation, artifacts, and
47
73
  well-defined application manifests. The supported profiles are `standard`, `memory-1g`, and
@@ -111,7 +137,7 @@ consumer cutover evidence.
111
137
 
112
138
  ## Consuming
113
139
 
114
- - **Go:** `go get github.com/Fourier-Labs-AI/harbour-contracts/gen-go@v0.1.0`
140
+ - **Go:** `go get github.com/Fourier-Labs-AI/harbour-contracts/gen-go@v0.50.0`
115
141
 
116
142
  Two things make this work, and the second is not the obvious one.
117
143
 
@@ -148,7 +174,7 @@ consumer cutover evidence.
148
174
  Without the above, `go get` fails with `Repository not found` — which reads as a
149
175
  missing tag, not as missing access.
150
176
 
151
- - **TS:** `npm i @fourier-labs/harbour-contracts` — published from the tag by CI.
177
+ - **TS:** `npm i @fourier-labs/harbour-contracts` — published from the tag by CI. The hand-written AI policy resolver (`resolver/index.ts`) ships in the same package as the `@fourier-labs/harbour-contracts/resolver` subpath export (`package.json` `exports`).
152
178
 
153
179
  ## Notes
154
180
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schema": "harbour.contract-release/1.0",
3
- "repositoryVersion": "0.46.0.0",
4
- "publishVersion": "0.46.0",
5
- "publishTag": "v0.46.0",
6
- "schemasDigest": "sha256:2d5d65ab7cf2f575de0f93cc3b096b2ac6505e5f505653c65b6a472f219fbbe2",
3
+ "repositoryVersion": "0.50.0.0",
4
+ "publishVersion": "0.50.0",
5
+ "publishTag": "v0.50.0",
6
+ "schemasDigest": "sha256:c77dcbf9daad9c66141e9cb8215760a098afd1bf3e665e247f6a4df8db2bcd4f",
7
7
  "aiFixturesDigest": "sha256:edac31c92e146ca1c40130f2fb5649db82e24b8cd1ac758153b90612052fddb6",
8
- "generatedGoDigest": "sha256:529c21544ed916b2d50854f31acd933d0b5b2f9251465375bfe0338fb11351e5",
9
- "generatedTypeScriptDigest": "sha256:7ebe33c88dcb7e20024201518b0da941b49e25f8ae4324cb15308cb450bf2422",
8
+ "generatedGoDigest": "sha256:545d8b23ab712e75285ea962851bcf8f08f5baeb018bea6f7ba4e1ca2fe80ed0",
9
+ "generatedTypeScriptDigest": "sha256:1e47c3956a3468531690693ff50ff7947a798af01e01d25659401f727cb934c4",
10
10
  "generatedExclusions": {
11
11
  "gen-go/contract_release.go": "contains the generated aggregate digests (self-reference)",
12
12
  "gen-ts/contract-release.ts": "contains the generated aggregate digests (self-reference)"
@@ -21,22 +21,22 @@
21
21
  "schema/ai-gateway-key-lookup.schema.json": "sha256:e994d4782c9bc4f14d3a1c35c9ac1e7a5ec84284cde5b3af7e3e6022130ddbb3",
22
22
  "schema/ai-governance-decision.schema.json": "sha256:d650762a428350748deafd6b251cbd4a03ba564650e74204f1a77bbe923e145f",
23
23
  "schema/ai-metering-policy.schema.json": "sha256:044115938d254d914feac162219d20ee48f741cd7ad32df4613b45f9c862fe8c",
24
- "schema/ai-policy-snapshot.schema.json": "sha256:8229b855861e029c7792c4c43d42c209055f175af747f437570d42c5008f70d8",
24
+ "schema/ai-policy-snapshot.schema.json": "sha256:55cabb3cdd833d66d5d4d30d3e1b41dfc981f473725db2e64983930995424fc3",
25
25
  "schema/ai-pricing-revision.schema.json": "sha256:5ddb40c23712c0cec37b733678e4bb34811f5db44a233773c21a7dfaec188375",
26
26
  "schema/ai-runtime-binding.schema.json": "sha256:e86cac2f70a474997bdef1577ca15f22982ec0ce866921df3f763c4d7f7fa191",
27
- "schema/ai-runtime-contract.schema.json": "sha256:338fbf576d67934592648aff9a9c8ae05a54993e8080c90172b00f346a15db02",
27
+ "schema/ai-runtime-contract.schema.json": "sha256:bfa2f8968b1c0678b328c178c7b9c6563f7a363ae04bf74a1078a1cd9679fa14",
28
28
  "schema/ai-trace-event-v2.schema.json": "sha256:b479199bb6e44ea23a1da53f69943cb8f3886c433914fdb9bf9e9bdbc3dd767d",
29
- "schema/ai-trace-event.schema.json": "sha256:313af995b72dd19d3d33997ba2d270bd163ce3752000fd7d8a6c18bff137af32",
29
+ "schema/ai-trace-event.schema.json": "sha256:96d095805ce35ceac2a4cb76ebcca9188f5dd8689ed6c67e93f33c5412d2a78b",
30
30
  "schema/ai-transform-event.schema.json": "sha256:b845762e653b19afdaf959f7bd1624db490cd10c760daa9aaa61fb83f2a86b6e",
31
31
  "schema/ai-transform-result.schema.json": "sha256:244e380a36957ab2dcb526ea22aaecb56b53664ce1fda6934d0021c084c99133",
32
32
  "schema/ai-verification-evidence.schema.json": "sha256:bdbc762df256d2a8dd0bdda60d4d13915ce40034cd756af9515871d145f10ad9",
33
33
  "schema/api-error-response.schema.json": "sha256:3d43d5bdf0b59c944e20509d832e6776c3ecdba4d6c245a9118bbe52062a8304",
34
- "schema/app-integrations-declaration.schema.json": "sha256:ed289e461a44f24099ed19286e08f8703b7e71c2478a46969579ae1bf4face9d",
34
+ "schema/app-integrations-declaration.schema.json": "sha256:1a6ac2e7d77a4d4dcbce8b937747f125081413f819ffee9e27e8b950a436cb22",
35
35
  "schema/artifact-contract.schema.json": "sha256:8047b461a1c6d07bbe867a259c57bdf5cc0fdf282cf842ec7b683a9e93713b10",
36
36
  "schema/binding-classification-subject.schema.json": "sha256:a8825ce652e7e00a18759c4249bd5bcd0cae552dd58440513f867e87f685133c",
37
37
  "schema/builder-input-proposal.schema.json": "sha256:fe85cffa6d76b1e1effe1f5d75525f8fe0e1eaa3be4a304e491aa23ad72c0e72",
38
38
  "schema/data-dependency.schema.json": "sha256:89ba8481ccabc935e7dab5d13871c985839a751ad1586710d8382a15e1f3340c",
39
- "schema/data-grant-v2.schema.json": "sha256:167abdda40c62119d9f19d9a4b6485acbde15aea4754cfb3093f57a7a00219b7",
39
+ "schema/data-grant-v2.schema.json": "sha256:6d639745e7a00f5f6383fa9034e3b04b6772cb29a60a6db1a3c517dc7a6c26ba",
40
40
  "schema/data-grant.schema.json": "sha256:e640553831ecc1c01cc9a37fe388b84d0ffeaa0d0050e63712b48f65fa437c8a",
41
41
  "schema/data-source.schema.json": "sha256:aec8d2497dae9a91886a3df9f6fbbdb3d3fcab44b14fbcacc3f5e99b827f1bba",
42
42
  "schema/deploy-request.schema.json": "sha256:32531e21983cdfeec511f8b4cddd4dad6530cd90e4e9fe147225d78d138b6198",
@@ -51,23 +51,23 @@
51
51
  "schema/error-category.enum.json": "sha256:2268b8a00dfa1f1ab6db7650c117028247fca980d4a23aa5969ce30b76692be9",
52
52
  "schema/error-envelope.schema.json": "sha256:75dccda7dd16fdf8435deda53fc7dbcdc109b65114617a17f11763010c656f90",
53
53
  "schema/integration-connect-result.schema.json": "sha256:3f254b67ef739dc1fa395bdc8c4dc93359b16d481dba2a2d777aa5b6f34b7af8",
54
- "schema/integration-error-details.schema.json": "sha256:d4cf0c175a109c985a46d1ee5b47fa98b72cab93c2bfebb4e7c29cedaefff7a4",
55
- "schema/integration-execute-request.schema.json": "sha256:9b7a169432853e6bd640bf61b9eed6287a76f5b303820c77d037f48b7ec99411",
56
- "schema/integration-execute-result.schema.json": "sha256:d28a22556c54f9ac6a9bd318e815acc8db487a1e51f6310bceadb41442016930",
54
+ "schema/integration-error-details.schema.json": "sha256:09cebaddb7f88e63cbebaa1cada5f91057ae4dc4370e973ef38f7f11c6323284",
55
+ "schema/integration-execute-request.schema.json": "sha256:658eb66a15bba4fc81eec208c713d5d141d159a6429306909304d5182f728bec",
56
+ "schema/integration-execute-result.schema.json": "sha256:766146779c01ee1dbdd2161c5dc594f43ccaf322762352bb0dc5b80bcb3275b5",
57
57
  "schema/kit-bundle-manifest.schema.json": "sha256:c15e28ae028dbd1c262427b9c797142e19b1f38fa36b4ecfe187e32c20a174ec",
58
58
  "schema/kit-lock.schema.json": "sha256:5e24b76660f83990af7a6c037af350c3850ee439ef956f65a0360facbdcdd997",
59
59
  "schema/kvs-routing-entry.schema.json": "sha256:b75f3a5dfa93a428b2764e03222b66b6ef2bed980f8bac8ffac54afdf3526bc5",
60
60
  "schema/promotion-request.schema.json": "sha256:00e96dfd8ddbdba88ea222941d43f3609ff6c815a79e34f6705cab458101c969",
61
61
  "schema/promotion-response.schema.json": "sha256:4129712d2e29d6ef21d93d4bd0bacfd60ada3f2ee0ade852824e64346b817634",
62
- "schema/saas-connection.schema.json": "sha256:2e35c907b3c470fdf7d451eba504c2875b830e97853d99078aaac61cc56e5ba0",
62
+ "schema/saas-connection.schema.json": "sha256:fa62fc6e28124120c71ebc36e257263ba8820d48b7d505d54ac53bd812fdd9ee",
63
63
  "schema/sanitized-binding-evidence.schema.json": "sha256:1191ab88e2764df927e5f17837674cebebe068d480da2b2fdb390e589f96b51f",
64
64
  "schema/secret-reference.schema.json": "sha256:db4e3c2c6a2dbd72d7ea0f9c91cb3b2343a7e67b601996c6818b2ef08e440895",
65
65
  "schema/security-scan-input.schema.json": "sha256:83502dffb3c07ac2e0698928e6dc123f454fc667d4aacd336bcad6944ef2ac3d",
66
66
  "schema/security-verdict.schema.json": "sha256:ec3c2d5c9df3601aeed0909b36c7f427469c7f0eeb3295c5809b96d09bf3fc26",
67
67
  "schema/transform-parked-result.schema.json": "sha256:11729980d4c89d4a9e18f5f213232cd3359739c85626b36c20c2a37ba794c9af",
68
- "schema/transform-report.schema.json": "sha256:5943c90ad7a8b473119dde5879c59ed384d5dc19253b90bc3507dd1ff4dd9abe",
68
+ "schema/transform-report.schema.json": "sha256:858da48fa7fe97d8d06267bb3435d71ba307133b246cb020f5b473bb488c445a",
69
69
  "schema/version-state.schema.json": "sha256:3b190007e2f8e3821c41ef11c6f5b226da7d5a18d34d4077f4618004846fd444",
70
- "schema/well-defined-app-manifest.schema.json": "sha256:75a06690411880e670f133066a7a469150b53560b9dafa2f066a04485e4b50a0"
70
+ "schema/well-defined-app-manifest.schema.json": "sha256:40f1bfea912dd85a05a0a3be2f6becadaf8ae3c5de9d5782ff1c8dd1bd83485f"
71
71
  },
72
72
  "aiFixtures": {
73
73
  "fixtures/ai/adversarial-binding-classification-value.json": "sha256:ca009f3f6162a9d93b4ab416d52c1fba12a8a15aca5aed956c5fdcf2171b1e28",
@@ -105,8 +105,8 @@
105
105
  "gen-go/contracts_test.go": "sha256:56376287cb1548be1b35ab4c65d6f0b558c5d34885f7a47cb3d9e8d786607bf5",
106
106
  "gen-go/doc.go": "sha256:c17bc2d39ed175ce7105c68305f8ae7152f659eb7cd187ecceee7698eb3a65dd",
107
107
  "gen-go/error_category.go": "sha256:b2ddea22dcfa030f1a45e721e635485b0bd816cf1f38e7654628a653f5ed4583",
108
- "gen-go/schema_documents.go": "sha256:bc8a5119241953827affa45588a1492fdf1e74bb9119564202baf424596d0d86",
109
- "gen-go/types.go": "sha256:5f72328441e849a45508b8e7ed1998388052ef61e079ff0de1c3076e052398cf",
108
+ "gen-go/schema_documents.go": "sha256:66055e0d4354f73d922ee17984de8df065db665f93182b87fcd8a6a94ae94300",
109
+ "gen-go/types.go": "sha256:07429b30905aacfdb95ca9ddea5ae04e3cc7fcc89e69b84f05f2833f4b8339be",
110
110
  "gen-go/version_state.go": "sha256:4ef8abb126414c0025cf2c59bc9c79a74ef4a2ff89e8f316cbf05acc872371c1"
111
111
  },
112
112
  "generatedTypeScript": {
@@ -121,23 +121,23 @@
121
121
  "gen-ts/ai-gateway-key-token.ts": "sha256:ff6551ad3332cc665878d7ec93f42ce185c375e637531b2fbc82c697b877e784",
122
122
  "gen-ts/ai-governance-decision.ts": "sha256:4a04e116f2ec281104e616a8ba414f23a9d34d398f850888d27510173e39c5c3",
123
123
  "gen-ts/ai-metering-policy.ts": "sha256:dd261d57646a509cd46efaefac4aad58d018c7f7da98326dd8859e4ce951c56a",
124
- "gen-ts/ai-policy-snapshot.ts": "sha256:05f5cea100e43a5cc6c1e8c7c07edea974ea0e6785730f622e824e40128f1ebc",
124
+ "gen-ts/ai-policy-snapshot.ts": "sha256:d79223055a03dfabfff3b09800dfb4c50ad6316ee2b97c840d141ef816f4544f",
125
125
  "gen-ts/ai-pricing-revision.ts": "sha256:48afdea7fb09b9a392147a0a62bcee013157a9d536c07e0782ef28781a3000de",
126
126
  "gen-ts/ai-runtime-binding.ts": "sha256:176c830d400ce44c508f8d249bb3c9724b2d595b78262615487cdafc4790263e",
127
- "gen-ts/ai-runtime-contract.ts": "sha256:f34533728dfcf7ce8d2e959b55379650f317a06e29e316caf86e131667891ddc",
127
+ "gen-ts/ai-runtime-contract.ts": "sha256:6ed3bde6ab7a3f7e2e298c2904eb52d35e06699c5e284f98fb39abfc76858beb",
128
128
  "gen-ts/ai-trace-event-v2.ts": "sha256:8c994355f290864da1cf42850c3eceb0e4a1567b45ed989de865213430d3ce0e",
129
- "gen-ts/ai-trace-event.ts": "sha256:657b144e6bc258c465850130a299c0f6d13fd2d0c2920c6667fc4eea39df77c4",
129
+ "gen-ts/ai-trace-event.ts": "sha256:53a74d014c59c059256ea855a100a209d9d4e83c5f95ae8e639073e1182c62dd",
130
130
  "gen-ts/ai-transform-event.ts": "sha256:c8b520e01ce12b0e3a5ebe03a3ca63cc83368f26e1eef933de732c4fc1c504f9",
131
131
  "gen-ts/ai-transform-result.ts": "sha256:208c66b2aeb425c0cbcc18b7191f6e8989443f2b2c1690648e0e06cc1448ce25",
132
132
  "gen-ts/ai-verification-evidence.ts": "sha256:979439d77f8b47631d1eb3b6c3c54ea6fec41089d2a51dc815fd370b1c4917fc",
133
133
  "gen-ts/api-error-response.ts": "sha256:0fd73be282e7a5d72d6c343a4e64d09c232556b16161167f0cffd6278ed7e3d3",
134
- "gen-ts/app-integrations-declaration.ts": "sha256:5d7dac0705de33dbdc926c98caacd277b3a9698c132abeef01700077e961812e",
134
+ "gen-ts/app-integrations-declaration.ts": "sha256:aabebdbffc70dd87017f1c72e0b8713f9cef506ba5258279b3a1405185875141",
135
135
  "gen-ts/artifact-contract.ts": "sha256:4a6dc6d2caaeed4bb2066cc8a333e6e09e5a0d4745e0b1038293d54ab9403aeb",
136
136
  "gen-ts/binding-classification-digest-helper.ts": "sha256:40fc7d85b4c3f3ffc5caf7d7950c62d013c83ee42058c7453b2100d95817f167",
137
137
  "gen-ts/binding-classification-subject.ts": "sha256:c409a3fd7b942b50419632c51d9a79474fb30d6374bdc79c0e25c73618e800c3",
138
138
  "gen-ts/builder-input-proposal.ts": "sha256:b0108c3787873d3cf1a39f00967379418a6766275d3474cfa55f5a9d93ead174",
139
139
  "gen-ts/data-dependency.ts": "sha256:0572c31d7ae9088eccc104eee1a205bf176d1d6dacfaf0f290d666024e284966",
140
- "gen-ts/data-grant-v2.ts": "sha256:e804821a3a4931e22387719ba3865a9a8c7f60d6e1b6ce37d6305cb867ccecb3",
140
+ "gen-ts/data-grant-v2.ts": "sha256:d55491e8d1a73d8999a43904344760de9c6eb2ce500b1e942d49261a9c67808f",
141
141
  "gen-ts/data-grant.ts": "sha256:2358579d8aa1e57b01a6f2b0eacce5531e7f21ef226404c9809925365e0d6155",
142
142
  "gen-ts/data-source.ts": "sha256:77d6bb3b0eaa355789c5d97dd1f548734add6950329dc69549350b8d17c8d582",
143
143
  "gen-ts/deploy-request.ts": "sha256:0214faa8be6680f0bfc117d5ce67c1a59fcc18bd0ea4bc840e03e7d051fa9ab6",
@@ -154,24 +154,24 @@
154
154
  "gen-ts/error-envelope.ts": "sha256:4457309be794f9d4fc0cf62530cc2d442c007bac9ae84aff66df099cc9e40310",
155
155
  "gen-ts/index.ts": "sha256:982599819309370072af19f1c248a033c13b17a6ee9006272d3436ab87b0db21",
156
156
  "gen-ts/integration-connect-result.ts": "sha256:4b10f169b6e1af364e9b418de21caa9fadbfb77b43cbff77d741cfae0b52180c",
157
- "gen-ts/integration-error-details.ts": "sha256:ef0ede67e2fc9e7894604f63f807d43a54987f0e942753de94243bb5320ccf6c",
158
- "gen-ts/integration-execute-request.ts": "sha256:da53eecf99da25c74b07d426adb8473795ebe2df4d8bd539894a6eda050f6c07",
159
- "gen-ts/integration-execute-result.ts": "sha256:c0b8449b442f8286c3ade51667039c71410dd9d53ef8b6a28611af4ba45c1357",
157
+ "gen-ts/integration-error-details.ts": "sha256:8243f5871f376d1cab4d90e07f3151d148fb03c704168dbccdfe6c9fe76bce83",
158
+ "gen-ts/integration-execute-request.ts": "sha256:d884e8368a5c4b8495312733fac3d28870a2cd48453c8f69e92a5d50273df516",
159
+ "gen-ts/integration-execute-result.ts": "sha256:4aaf6a9688f9dfdbc87a408556b62f822518acf5b76548076adb55393c0863b4",
160
160
  "gen-ts/kit-bundle-manifest.ts": "sha256:9041b32af3df781ca6800bc14c3719e5e54c81dff370633454ac3ad27432eb58",
161
161
  "gen-ts/kit-lock.ts": "sha256:de4ae82bac7bd234a3230ae671962e80eed6542d695a032a442673659dc6be5e",
162
162
  "gen-ts/kvs-routing-entry.ts": "sha256:d92e85ee9f257d77850d1d3aac9438e2055f38084ff84a48fcedae239d47d4ca",
163
163
  "gen-ts/promotion-request.ts": "sha256:9db88cef67f777a16bac628039ec3f582acb9e8cfff6fb592b30d0a0e55abc68",
164
164
  "gen-ts/promotion-response.ts": "sha256:f1c9cafac96faeb02a443a31786f67714e818f38d90108e7af41958396524d6f",
165
- "gen-ts/saas-connection.ts": "sha256:6813e6cc0e4c0a3b4fb8181fe95b53a96bbf2953aa6ea0b6f3b6a5744cd0878b",
165
+ "gen-ts/saas-connection.ts": "sha256:62b5c5ffd125099bae46142013461c9ac3f75c2d27ab72cd4842a937f3e2f308",
166
166
  "gen-ts/sanitized-binding-digest-helper.ts": "sha256:c47d7fdc20500e2e72c23fe39ecdd610fc397c47fcba51335ebec3c380fe6872",
167
167
  "gen-ts/sanitized-binding-evidence.ts": "sha256:f3fb7b1d7d2e0929eb0ea981eaf32db3104010647185f6ae59f67167d42538a9",
168
168
  "gen-ts/secret-reference.ts": "sha256:731fbcde7315cb4128d5b01bdbe6e6f248f13c7ad8dea04a3a4e927ac4890198",
169
169
  "gen-ts/security-scan-input.ts": "sha256:b31f048be04c34b40f49d3b3ba53277e473cd435ae9216ba3a3b4dac69fb5685",
170
170
  "gen-ts/security-verdict.ts": "sha256:fea950cddbd12fe0218e2573c9a29c6748d56612a464559f1e6d688fa97f68c7",
171
171
  "gen-ts/transform-parked-result.ts": "sha256:6279e27cee8d75c29f3ede45580fef1daa0ca300867a78e43ead8a7689ec613f",
172
- "gen-ts/transform-report.ts": "sha256:a4f7f895342cd63048b2add63393a1251abb3e97f057b00e3ebd3f96fd1a510e",
172
+ "gen-ts/transform-report.ts": "sha256:005a10b34b89f055c3aae4bf54c095bbca7a9e15bd9b406b61a9eaafffc37a61",
173
173
  "gen-ts/version-state-machine.ts": "sha256:c67af3e86ac306743345b850dfd3ae5201c19d10c40e2c149cf8c38258320d5f",
174
174
  "gen-ts/version-state.ts": "sha256:a835112930299e7b593a1b8810b7414f6c9e809da2092306c743128170a3b702",
175
- "gen-ts/well-defined-app-manifest.ts": "sha256:f29f8f2d0783e9e49d0546d65c2bedee2a6c2cebba0ec291ad52d9b67cb3a2fa"
175
+ "gen-ts/well-defined-app-manifest.ts": "sha256:2b72a39c2fa8e76239634d0478dc0da05446e74e944950eacf999b78876455c6"
176
176
  }
177
177
  }
@@ -82,6 +82,7 @@ export interface AiPolicySnapshot {
82
82
  */
83
83
  limits: AiPolicyLimit[];
84
84
  retention: AiPolicyRetention;
85
+ assignments?: AiPolicyAssignments;
85
86
  }
86
87
  export interface AiPolicyClassificationMinimum {
87
88
  classification: 'Green' | 'Yellow' | 'Orange' | 'Red';
@@ -198,3 +199,21 @@ export interface AiPolicyRetention {
198
199
  */
199
200
  revealRoles: AiPolicyIdentifier[];
200
201
  }
202
+ /**
203
+ * Application-scope only: the tenant resources this application/environment snapshot pins BY NAME (D-8/D-9). A scope without assignments keeps the default rule (the whole merge-narrowed set is the assignment). Every name must exist in the same snapshot's own family; empty route and budget selections are legal (tenant-scoped limits bind regardless).
204
+ */
205
+ export interface AiPolicyAssignments {
206
+ /**
207
+ * @maxItems 256
208
+ */
209
+ routes: AiPolicyIdentifier[];
210
+ /**
211
+ * @minItems 1
212
+ * @maxItems 256
213
+ */
214
+ policies: AiPolicyIdentifier[];
215
+ /**
216
+ * @maxItems 128
217
+ */
218
+ budgets: AiPolicyIdentifier[];
219
+ }
@@ -49,7 +49,7 @@ export interface AiRuntimeContract {
49
49
  export interface AiConfigurationMappingDescriptor {
50
50
  mappingId: string;
51
51
  version: string;
52
- protocol: 'openai-chat';
52
+ protocol: 'openai-chat' | 'openai-images';
53
53
  providerId: string;
54
54
  apiKeyEnvironmentName: string;
55
55
  baseUrlEnvironmentName: string;
@@ -17,7 +17,10 @@ export type AiTraceEvent = {
17
17
  provider?: 'openai' | 'anthropic' | 'gemini' | 'openrouter' | 'deepseek' | 'elevenlabs' | 'deepgram' | 'higgsfield';
18
18
  providerModel?: string;
19
19
  outcome: 'succeeded' | 'blocked' | 'failed' | 'cancelled';
20
- usage?: AiTraceUsage;
20
+ /**
21
+ * Trace-level provider-reported usage, or null when no attempt reported any (the reservation stays committed rather than reconciled against invented zero usage).
22
+ */
23
+ usage?: AiTraceUsage | null;
21
24
  priceRevision?: AiTraceIdentifier;
22
25
  costMicroUsd: number;
23
26
  latencyMs: number;
@@ -9,7 +9,11 @@ export type IntegrationAlias = string;
9
9
  */
10
10
  export type ResourceNames = IntegrationAlias[];
11
11
  /**
12
- * Committed `.harbour/integrations.json`: the app's declared use of tenant-wide integration connections. Keys are logical connection aliases (the governance sourceId); resources are logical names (Slack channel alias, warehouse view name), never IDs, tokens or URLs. The operation set is closed (three operations) and each operation carries a fixed identity mode: slack.channel.history=user, slack.message.post=app, warehouse.view.read=app. A `saas` connection may declare only the Slack operations and a `database` connection only warehouse.view.read. This file also owns the shared IntegrationOperation / IntegrationIdentityMode / IntegrationEnvironment / IntegrationConnectionKind enums referenced by the other integration schemas.
12
+ * A plain column identifier of a warehouse view.
13
+ */
14
+ export type ColumnName = string;
15
+ /**
16
+ * Committed `.harbour/integrations.json`: the app's declared use of tenant-wide integration connections. Keys are logical connection aliases (the governance sourceId); resources are logical names (Slack channel alias, warehouse view name), never IDs, tokens or URLs. The operation set is closed (five operations) and each operation carries a fixed identity mode: slack.channel.history=user, slack.message.post=app, gmail.thread.list=user, gmail.message.read=user, warehouse.view.read=app. A `saas` connection may declare only the Slack and Gmail operations and a `database` connection only warehouse.view.read. Gmail is read-only and user-mode only; its single resource is the fixed `inbox` alias. This file also owns the shared IntegrationOperation / IntegrationIdentityMode / IntegrationEnvironment / IntegrationConnectionKind enums referenced by the other integration schemas.
13
17
  */
14
18
  export interface AppIntegrationsDeclaration {
15
19
  schema: 'harbour.app-integrations/2.0';
@@ -22,6 +26,9 @@ export interface DeclaredConnection {
22
26
  operations: {
23
27
  'slack.channel.history'?: UserModeChannelOperation;
24
28
  'slack.message.post'?: AppModeChannelOperation;
29
+ 'gmail.thread.list'?: UserModeChannelOperation;
30
+ 'gmail.message.read'?: UserModeChannelOperation;
31
+ 'gmail.message.send'?: UserModeChannelOperation;
25
32
  'warehouse.view.read'?: AppModeViewOperation;
26
33
  };
27
34
  }
@@ -44,5 +51,5 @@ export interface ViewResource {
44
51
  * @minItems 1
45
52
  * @maxItems 32
46
53
  */
47
- columns: string[];
54
+ columns: ColumnName[];
48
55
  }
@@ -1,7 +1,7 @@
1
- export declare const ContractRepositoryVersion: "0.46.0.0";
2
- export declare const ContractPublishVersion: "0.46.0";
3
- export declare const ContractPublishTag: "v0.46.0";
4
- export declare const ContractSchemasDigest: "sha256:2d5d65ab7cf2f575de0f93cc3b096b2ac6505e5f505653c65b6a472f219fbbe2";
1
+ export declare const ContractRepositoryVersion: "0.50.0.0";
2
+ export declare const ContractPublishVersion: "0.50.0";
3
+ export declare const ContractPublishTag: "v0.50.0";
4
+ export declare const ContractSchemasDigest: "sha256:c77dcbf9daad9c66141e9cb8215760a098afd1bf3e665e247f6a4df8db2bcd4f";
5
5
  export declare const ContractAiFixturesDigest: "sha256:edac31c92e146ca1c40130f2fb5649db82e24b8cd1ac758153b90612052fddb6";
6
- export declare const ContractGeneratedGoDigest: "sha256:529c21544ed916b2d50854f31acd933d0b5b2f9251465375bfe0338fb11351e5";
7
- export declare const ContractGeneratedTypeScriptDigest: "sha256:7ebe33c88dcb7e20024201518b0da941b49e25f8ae4324cb15308cb450bf2422";
6
+ export declare const ContractGeneratedGoDigest: "sha256:545d8b23ab712e75285ea962851bcf8f08f5baeb018bea6f7ba4e1ca2fe80ed0";
7
+ export declare const ContractGeneratedTypeScriptDigest: "sha256:1e47c3956a3468531690693ff50ff7947a798af01e01d25659401f727cb934c4";
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable */
2
2
  // Code generated by tools/gen/gen.mjs from schema/*.json. DO NOT EDIT.
3
- export const ContractRepositoryVersion = "0.46.0.0";
4
- export const ContractPublishVersion = "0.46.0";
5
- export const ContractPublishTag = "v0.46.0";
6
- export const ContractSchemasDigest = "sha256:2d5d65ab7cf2f575de0f93cc3b096b2ac6505e5f505653c65b6a472f219fbbe2";
3
+ export const ContractRepositoryVersion = "0.50.0.0";
4
+ export const ContractPublishVersion = "0.50.0";
5
+ export const ContractPublishTag = "v0.50.0";
6
+ export const ContractSchemasDigest = "sha256:c77dcbf9daad9c66141e9cb8215760a098afd1bf3e665e247f6a4df8db2bcd4f";
7
7
  export const ContractAiFixturesDigest = "sha256:edac31c92e146ca1c40130f2fb5649db82e24b8cd1ac758153b90612052fddb6";
8
- export const ContractGeneratedGoDigest = "sha256:529c21544ed916b2d50854f31acd933d0b5b2f9251465375bfe0338fb11351e5";
9
- export const ContractGeneratedTypeScriptDigest = "sha256:7ebe33c88dcb7e20024201518b0da941b49e25f8ae4324cb15308cb450bf2422";
8
+ export const ContractGeneratedGoDigest = "sha256:545d8b23ab712e75285ea962851bcf8f08f5baeb018bea6f7ba4e1ca2fe80ed0";
9
+ export const ContractGeneratedTypeScriptDigest = "sha256:1e47c3956a3468531690693ff50ff7947a798af01e01d25659401f727cb934c4";
@@ -6,45 +6,50 @@ export type DataGrantV2Status = 'REQUESTED' | 'GRANTED' | 'DENIED' | 'REVOKED';
6
6
  * Provider-side work for the current approved scope (credential mint, cleanup, installation check).
7
7
  */
8
8
  export type DataGrantV2ProvisioningStatus = 'NONE' | 'PENDING' | 'FAILED' | 'DONE';
9
+ export type DataGrantV2CleanupStatus = 'PENDING' | 'FAILED' | 'DONE';
9
10
  /**
10
- * An app's integration grant for one connection, environment and identity mode (control table sk APP#<appId>#IGRANT#<environment>#<sourceId>#<mode>; grantId = base64url(JSON ["v2",appId,environment,sourceId,mode])). Additive to the legacy DataGrant (data-grant.schema.json), which is never consulted by v2 paths. Expiry is enforced from UTC time on every call and SDK calls never extend it. Status edges live in x-transitions; DENIED and REVOKED are terminal (a regrant after revocation is a new REQUESTED record once cleanup is DONE). Database grants add credentialRef/mintedPrincipal, SaaS grants add installation; both hold references only.
11
+ * An app's integration grant for one connection, environment and identity mode (control table sk APP#<appId>#IGRANT#<environment>#<sourceId>#<mode>; grantId = base64url(JSON ["v2",appId,environment,sourceId,mode])). Additive to the legacy DataGrant (data-grant.schema.json), which is never consulted by v2 paths. A fresh REQUESTED record carries empty `operations`/`resources` until the attached request is approved; approved resources are structured `{name, columns?}` entries (a Slack channel alias, the fixed Gmail `inbox` alias, or a warehouse view alias with its approved columns). Expiry is enforced from UTC time on every call and SDK calls never extend it; `expiredAt` is stamped by the recovery sweep afterwards. Status edges live in x-transitions; DENIED and REVOKED are terminal (a regrant after revocation is a new REQUESTED record once cleanup is DONE). Database grants add credentialRef/mintedPrincipal; both hold references only. `identityMode` and `installation` are the deprecated 0.45.0 spellings: the record carries `mode`, and a SaaS grant runs on the connection's single installation.
11
12
  */
12
13
  export interface DataGrantV2 {
13
14
  schema: 'harbour.data-grant/2.0';
15
+ tenantId: string;
14
16
  appId: string;
15
- /**
16
- * Tenant-wide logical alias of a connection (governance sourceId) or of a resource under it.
17
- */
18
- sourceId: string;
19
- kind: 'saas' | 'database';
20
17
  /**
21
18
  * development is the CLI/local kit; preview and production are hosted.
22
19
  */
23
20
  environment: 'development' | 'preview' | 'production';
21
+ /**
22
+ * Tenant-wide logical alias of a connection (governance sourceId) or of a resource under it.
23
+ */
24
+ sourceId: string;
24
25
  /**
25
26
  * Whose authority an operation runs under. Fixed per operation; callers never choose it.
26
27
  */
27
- identityMode: 'app' | 'user';
28
+ mode: 'app' | 'user';
29
+ kind: 'saas' | 'database';
28
30
  status: DataGrantV2Status;
29
31
  /**
30
- * Approved operations; each must match this grant's identityMode.
32
+ * Approved operations; each must match this grant's mode. Empty until the first approval.
31
33
  *
32
- * @minItems 1
33
- * @maxItems 3
34
+ * @maxItems 5
34
35
  */
35
- operations: ('slack.channel.history' | 'slack.message.post' | 'warehouse.view.read')[];
36
+ operations: ('slack.channel.history' | 'slack.message.post' | 'gmail.thread.list' | 'gmail.message.read' | 'gmail.message.send' | 'warehouse.view.read')[];
36
37
  /**
37
- * Approved logical resource names (channel aliases or view names). Never inherited by wildcard.
38
+ * Approved logical resources. Never inherited by wildcard. Empty until the first approval.
38
39
  *
39
- * @minItems 1
40
40
  * @maxItems 64
41
41
  */
42
- resources: string[];
42
+ resources: IntegrationResource[];
43
43
  /**
44
44
  * Absent only for explicitly approved ongoing production access.
45
45
  */
46
46
  expiresAt?: string;
47
+ /**
48
+ * Set by the recovery sweep once expiry has passed; enforcement itself is the UTC check on every call.
49
+ */
50
+ expiredAt?: string;
47
51
  approvedBy?: string;
52
+ approvedAt?: string;
48
53
  /**
49
54
  * Optimistic-concurrency version; approvals compare it with the reviewed value.
50
55
  */
@@ -55,18 +60,42 @@ export interface DataGrantV2 {
55
60
  pendingRequestId?: string;
56
61
  provisioning: DataGrantV2Provisioning;
57
62
  /**
58
- * Database grants: secretref://tenant/{t}/app/{a}/env/{env}/source/{s}.
63
+ * Database grants: secretref://tenant/{t}/app/{a}/env/{env}/source/{s}. Set only by a successful publish and removed by cleanup.
59
64
  */
60
65
  credentialRef?: string;
61
66
  /**
62
67
  * Database grants: the deterministic per tenant/app/environment/source principal.
63
68
  */
64
69
  mintedPrincipal?: string;
70
+ createdAt: string;
71
+ updatedAt: string;
65
72
  /**
66
- * SaaS grants: the connection installation this environment maps to.
73
+ * @deprecated
74
+ * Whose authority an operation runs under. Fixed per operation; callers never choose it.
75
+ */
76
+ identityMode?: 'app' | 'user';
77
+ /**
78
+ * @deprecated
79
+ * Deprecated: a SaaS grant runs on the connection's single installation; the control plane never writes it.
67
80
  */
68
81
  installation?: string;
69
82
  }
83
+ /**
84
+ * One approved logical resource: a channel alias, the fixed Gmail `inbox` alias, or a warehouse view alias with the approved columns.
85
+ */
86
+ export interface IntegrationResource {
87
+ /**
88
+ * Tenant-wide logical alias of a connection (governance sourceId) or of a resource under it.
89
+ */
90
+ name: string;
91
+ /**
92
+ * warehouse.view.read only: the approved columns of the view.
93
+ *
94
+ * @minItems 1
95
+ * @maxItems 32
96
+ */
97
+ columns?: string[];
98
+ }
70
99
  export interface DataGrantV2Provisioning {
71
100
  status: DataGrantV2ProvisioningStatus;
72
101
  /**
@@ -77,6 +106,21 @@ export interface DataGrantV2Provisioning {
77
106
  * Sanitized reason; never a provider error body.
78
107
  */
79
108
  lastError?: string;
109
+ /**
110
+ * Conditional worker lease serialising database mutations (120 s).
111
+ */
112
+ lease?: {
113
+ until: string;
114
+ owner: string;
115
+ };
116
+ /**
117
+ * Provider-side cleanup after revocation or expiry; a FAILED cleanup waits for an admin retry-cleanup.
118
+ */
119
+ cleanup?: {
120
+ status: DataGrantV2CleanupStatus;
121
+ attempts: number;
122
+ lastError?: string;
123
+ };
80
124
  }
81
125
  /** True iff from→to is a legal DataGrantV2Status edge (schema x-transitions). */
82
126
  export declare function canTransitionDataGrantV2Status(from: string, to: string): boolean;
@@ -3,9 +3,9 @@
3
3
  */
4
4
  export type IntegrationErrorCategory = 'AUTH_REQUIRED' | 'FORBIDDEN' | 'NOT_FOUND' | 'CONFLICT' | 'VALIDATION_FAILED' | 'RATE_LIMITED' | 'UNAVAILABLE';
5
5
  /**
6
- * Stable reason codes. SEND_OUTCOME_UNKNOWN: dispatch happened but the outcome is unknown; never re-post automatically. SEND_KEY_REUSED: the idempotency key was seen with a different payload or subject. GRANT_DENIED: IT denied the request. TOKEN_REFRESH_PENDING: another call holds the refresh lease; retry shortly. REQUEST_PENDING: a different request for this grant is still open.
6
+ * Stable reason codes. SEND_OUTCOME_UNKNOWN: dispatch happened but the outcome is unknown; never re-post automatically. SEND_KEY_REUSED: the idempotency key was seen with a different payload or subject. GRANT_DENIED: IT denied the request. TOKEN_REFRESH_PENDING: another call holds the refresh lease; retry shortly. REQUEST_PENDING: a different request for this grant is still open. INPUT_INVALID: the operation input failed its bounds. IDEMPOTENCY_KEY_REQUIRED: a send without a UUID idempotencyKey. SEND_IN_PROGRESS: a retry arrived while the first send of that key is still running. CONNECTION_NOT_FOUND / APP_NOT_FOUND / GRANT_NOT_FOUND: the named record does not exist. AUTH_REQUIRED: no verified caller. UNAVAILABLE: the governance dependency (store, provider seam) is unreachable.
7
7
  */
8
- export type IntegrationErrorCode = 'USER_CONNECTION_REQUIRED' | 'USER_RECONNECT_REQUIRED' | 'GRANT_NOT_READY' | 'GRANT_EXPIRED' | 'GRANT_REVOKED' | 'CONNECTION_DISABLED' | 'OPERATION_NOT_DECLARED' | 'RESOURCE_NOT_APPROVED' | 'IDENTITY_MODE_MISMATCH' | 'SEND_OUTCOME_UNKNOWN' | 'SEND_KEY_REUSED' | 'PROVIDER_RATE_LIMITED' | 'PROVIDER_UNAVAILABLE' | 'REQUEST_TOO_LARGE' | 'RESULT_TOO_LARGE' | 'DEADLINE_EXCEEDED' | 'APP_ACCESS_REQUIRED' | 'GRANT_DENIED' | 'TOKEN_REFRESH_PENDING' | 'REQUEST_PENDING';
8
+ export type IntegrationErrorCode = 'USER_CONNECTION_REQUIRED' | 'USER_RECONNECT_REQUIRED' | 'GRANT_NOT_READY' | 'GRANT_EXPIRED' | 'GRANT_REVOKED' | 'CONNECTION_DISABLED' | 'OPERATION_NOT_DECLARED' | 'RESOURCE_NOT_APPROVED' | 'IDENTITY_MODE_MISMATCH' | 'SEND_OUTCOME_UNKNOWN' | 'SEND_KEY_REUSED' | 'PROVIDER_RATE_LIMITED' | 'PROVIDER_UNAVAILABLE' | 'REQUEST_TOO_LARGE' | 'RESULT_TOO_LARGE' | 'DEADLINE_EXCEEDED' | 'APP_ACCESS_REQUIRED' | 'GRANT_DENIED' | 'TOKEN_REFRESH_PENDING' | 'REQUEST_PENDING' | 'INPUT_INVALID' | 'IDEMPOTENCY_KEY_REQUIRED' | 'SEND_IN_PROGRESS' | 'CONNECTION_NOT_FOUND' | 'APP_NOT_FOUND' | 'GRANT_NOT_FOUND' | 'AUTH_REQUIRED' | 'UNAVAILABLE';
9
9
  /**
10
10
  * The `error` member of an integration failure response `{error, requestId}` on the execute/connect routes; the SDK maps it onto HarbourError(category, message, details). `category` is the app-SDK HarbourErrorCategory (not the deployment pipeline's dot-path error-category registry), with the HTTP status fixed per category: 401 AUTH_REQUIRED, 403 FORBIDDEN (denied/revoked/expired), 404 NOT_FOUND (unknown app/connection/resource), 409 CONFLICT (pending provisioning/consent/concurrent request), 400 or 413 VALIDATION_FAILED (invalid input / size overflow), 429 RATE_LIMITED (+ Retry-After header), 503 UNAVAILABLE. `details.code` is the closed stable reason set; `message` is human-facing and never carries provider error bodies, tokens or SQL.
11
11
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Body of POST /_harbour/integrations/execute (app SDK), forwarded unchanged to the governance development and runtime execute routes. Exactly one declared operation against one declared resource. The identity mode is NOT a caller field: it is fixed by the operation and enforced from the approved grant; any identity/userId/scope field is rejected by additionalProperties. Per-operation input bounds: slack.channel.history {limit? 1..15, default 15}; slack.message.post {text 1..4000 chars} and a required idempotencyKey retained across retries of one explicit Send; warehouse.view.read {columns 1..32, limit? 1..1000, default 100}. Transport limits (not expressible here): request <= 16 KiB, total deadline 10 s.
2
+ * Body of POST /_harbour/integrations/execute (app SDK), forwarded unchanged to the governance development and runtime execute routes. Exactly one declared operation against one declared resource. The identity mode is NOT a caller field: it is fixed by the operation and enforced from the approved grant; any identity/userId/scope field is rejected by additionalProperties. Per-operation input bounds: slack.channel.history {limit? 1..15, default 15}; slack.message.post {text 1..4000 chars} and a required idempotencyKey retained across retries of one explicit Send; gmail.thread.list {limit? 1..15, default 15}; gmail.message.read {messageId}; gmail.message.send {to 1..50 addresses (to+cc+bcc <= 50 in total), cc?, bcc?, subject 1..256 chars, text 1..4000 chars, replyToMessageId?} and a required idempotencyKey like slack.message.post (plain text only, no attachments); warehouse.view.read {columns 1..32, limit? 1..1000, default 100}. Transport limits (not expressible here): request <= 16 KiB, total deadline 10 s.
3
3
  */
4
4
  export type IntegrationExecuteRequest = {
5
5
  /**
@@ -7,9 +7,9 @@ export type IntegrationExecuteRequest = {
7
7
  */
8
8
  connection: string;
9
9
  /**
10
- * Closed operation set. Extending it is a contracts change.
10
+ * Closed operation set. Extending it is a contracts change. gmail.message.send (0.50.0) sends one plain-text email as the signed-in person: a send like slack.message.post (explicit Send, idempotencyKey, write receipt) under user identity.
11
11
  */
12
- operation: 'slack.channel.history' | 'slack.message.post' | 'warehouse.view.read';
12
+ operation: 'slack.channel.history' | 'slack.message.post' | 'gmail.thread.list' | 'gmail.message.read' | 'gmail.message.send' | 'warehouse.view.read';
13
13
  /**
14
14
  * Tenant-wide logical alias of a connection (governance sourceId) or of a resource under it.
15
15
  */
@@ -17,6 +17,21 @@ export type IntegrationExecuteRequest = {
17
17
  input: {
18
18
  limit?: number;
19
19
  text?: string;
20
+ /**
21
+ * gmail.message.read: the Gmail message id a gmail.thread.list result named.
22
+ */
23
+ messageId?: string;
24
+ to?: EmailAddressList;
25
+ cc?: EmailAddressList1;
26
+ bcc?: EmailAddressList2;
27
+ /**
28
+ * gmail.message.send: one-line subject (no line breaks).
29
+ */
30
+ subject?: string;
31
+ /**
32
+ * gmail.message.send: a Gmail message id (from gmail.thread.list / gmail.message.read) the email replies to; the send joins that thread.
33
+ */
34
+ replyToMessageId?: string;
20
35
  /**
21
36
  * @minItems 1
22
37
  * @maxItems 32
@@ -24,7 +39,32 @@ export type IntegrationExecuteRequest = {
24
39
  columns?: string[];
25
40
  };
26
41
  /**
27
- * UUID of one explicit Send action; required for slack.message.post only. The same key with the same payload and subject returns the recorded outcome for seven days.
42
+ * UUID of one explicit Send action; required for slack.message.post and gmail.message.send only. The same key with the same payload and subject returns the recorded outcome for seven days.
28
43
  */
29
44
  idempotencyKey?: string;
30
45
  };
46
+ /**
47
+ * One bare email address (no display name).
48
+ */
49
+ export type EmailAddress = string;
50
+ /**
51
+ * gmail.message.send: primary recipients.
52
+ *
53
+ * @minItems 1
54
+ * @maxItems 50
55
+ */
56
+ export type EmailAddressList = EmailAddress[];
57
+ /**
58
+ * gmail.message.send: carbon-copy recipients.
59
+ *
60
+ * @minItems 1
61
+ * @maxItems 50
62
+ */
63
+ export type EmailAddressList1 = EmailAddress[];
64
+ /**
65
+ * gmail.message.send: blind-copy recipients.
66
+ *
67
+ * @minItems 1
68
+ * @maxItems 50
69
+ */
70
+ export type EmailAddressList2 = EmailAddress[];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The `data` member of a successful execute response `{data, requestId}`; the SDK unwraps `data`. Exactly one of the three operation results: slack.channel.history -> {messages, hasMore} (plain text/IDs/time only, never the provider payload); slack.message.post -> {messageId}; warehouse.view.read -> {rows} (decimal/64-bit values as strings, dates as ISO strings). An unknown send outcome is never a result; it is an error with details.code SEND_OUTCOME_UNKNOWN. Results over 1 MiB are rejected, not truncated.
2
+ * The `data` member of a successful execute response `{data, requestId}`; the SDK unwraps `data`. Exactly one of the six operation results: slack.channel.history -> {messages, hasMore} (plain text/IDs/time only, never the provider payload); slack.message.post -> {messageId}; gmail.thread.list -> {threads, hasMore} (newest inbox threads; each `messageId` is the thread's newest message, what gmail.message.read takes); gmail.message.read -> {id, threadId, subject, from, to, date, text, truncated} (headers plus the plain text with html stripped, cut at 16 KiB with `truncated` set); gmail.message.send -> {messageId, threadId} (the Gmail ids of the sent message and its thread); warehouse.view.read -> {rows} (decimal/64-bit values as strings, dates as ISO strings). An unknown send outcome is never a result; it is an error with details.code SEND_OUTCOME_UNKNOWN. Results over 1 MiB are rejected, not truncated.
3
3
  */
4
4
  export type IntegrationExecuteResult = {
5
5
  /**
@@ -8,6 +8,18 @@ export type IntegrationExecuteResult = {
8
8
  messages?: ChannelMessage[];
9
9
  hasMore?: boolean;
10
10
  messageId?: string;
11
+ /**
12
+ * @maxItems 15
13
+ */
14
+ threads?: GmailThread[];
15
+ id?: string;
16
+ threadId?: string;
17
+ subject?: string;
18
+ from?: string;
19
+ to?: string;
20
+ date?: string;
21
+ text?: string;
22
+ truncated?: boolean;
11
23
  /**
12
24
  * @maxItems 1000
13
25
  */
@@ -21,3 +33,11 @@ export interface ChannelMessage {
21
33
  authorId: string;
22
34
  createdAt: string;
23
35
  }
36
+ export interface GmailThread {
37
+ id: string;
38
+ messageId: string;
39
+ subject: string;
40
+ from: string;
41
+ date: string;
42
+ snippet: string;
43
+ }