codai-sdk 0.6.0 → 0.8.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 +30 -2
- package/dist/index.d.ts +251 -4
- package/dist/index.js +130 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ surface.
|
|
|
65
65
|
| `receipt` | `get` | `GET /v1/receipt` |
|
|
66
66
|
| `feedback` | `submit` | `POST /v1/feedback` |
|
|
67
67
|
| `phoneModels` | `list` | `GET /v1/phone/models` |
|
|
68
|
-
| `resolve` | `submit`, `get`, `accept`, `attestation`, `health`, `waitFor`
|
|
68
|
+
| `resolve` | `submit`, `get`, `accept`, `balance`, `attestation`, `keys`, `verifyAttestation`, `health`, `waitFor` | `https://resolve.codai.ro/v1/resolve/*` (own host) |
|
|
69
69
|
|
|
70
70
|
Every method takes an optional last argument `{ ext, signal }` where `ext` is a
|
|
71
71
|
typed bag of `X-Codai-*` extension headers (see below).
|
|
@@ -180,7 +180,8 @@ if (q.status === 'quoted') {
|
|
|
180
180
|
try {
|
|
181
181
|
await codai.resolve.accept(q.id); // free-tier jobs are auto-accepted
|
|
182
182
|
} catch (err) {
|
|
183
|
-
if (err instanceof ResolveInsufficientFundsError)
|
|
183
|
+
if (err instanceof ResolveInsufficientFundsError)
|
|
184
|
+
console.log('top up:', err.topupUrl, err.bundleUrl ?? ''); // bundleUrl: t7 only
|
|
184
185
|
throw err;
|
|
185
186
|
}
|
|
186
187
|
}
|
|
@@ -198,6 +199,15 @@ with `balance`, `required`, `currency: 'micro_eur'` and `topupUrl`. `submit` and
|
|
|
198
199
|
`accept` are never retried. `waitFor` stops at `resolved | failed | declined | error`
|
|
199
200
|
(or `until`), and throws `ResolveError` with `status: 0` on timeout.
|
|
200
201
|
|
|
202
|
+
**Pricing.** Your first paid accept holds **€1** instead of the list price (the quote then
|
|
203
|
+
carries `intro_price_micro_eur` / `list_price_micro_eur`); it is used up only by a verified
|
|
204
|
+
fix — a failed intro job is refunded and the intro is offered again. A **fix bundle** (€49 = 10
|
|
205
|
+
credits, <https://pay.codai.ro/checkout?bundle=resolve10>) pays for `t7` jobs only: a credit is
|
|
206
|
+
taken at accept instead of a wallet hold and returned on failure. Precedence:
|
|
207
|
+
free > intro > credit (t7) > wallet; `accept()` reports it in `paid_with`, and a t7 `402`
|
|
208
|
+
carries `bundleUrl`. `codai.resolve.balance()` returns `fix_credits`, `intro_available` and
|
|
209
|
+
`wallet_micro_eur`.
|
|
210
|
+
|
|
201
211
|
### Webhooks instead of polling
|
|
202
212
|
|
|
203
213
|
Pass `callback_url` (https, public host) on `submit`; the response carries
|
|
@@ -226,6 +236,24 @@ if (!verifyResolveWebhook(secret, raw, req.headers.get('x-codai-signature'))) {
|
|
|
226
236
|
const evt = JSON.parse(raw) as ResolveWebhookEvent; // evt.event, evt.job.attestation_url
|
|
227
237
|
```
|
|
228
238
|
|
|
239
|
+
### Verifying a signed attestation
|
|
240
|
+
|
|
241
|
+
Attestations created from 2026-09-27 carry `signature`: a DSSE envelope
|
|
242
|
+
(ECDSA P-256/SHA-256) over a canonical statement of sha256 hashes of the patch,
|
|
243
|
+
repro test and test outputs, plus the commands, base commit, runner digest and
|
|
244
|
+
timestamps. `verifyAttestation` checks the signature against
|
|
245
|
+
`GET /v1/resolve/keys` **and** that the statement matches the fields you were
|
|
246
|
+
served. Older attestations have `signature: null` → `{ ok: false, reason: 'UNSIGNED' }`.
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const proof = await codai.resolve.attestation(job.attestation_url!);
|
|
250
|
+
const r = await codai.resolve.verifyAttestation(proof); // or { keys: pinnedKeys }
|
|
251
|
+
if (!r.ok) throw new Error(`attestation not verified: ${r.reason}`);
|
|
252
|
+
// r.keyid — the signing key; reasons: UNSIGNED | BAD_SIGNATURE | STATEMENT_MISMATCH | BAD_PAYLOAD_TYPE
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Offline (no network): `verifyAttestationWithKeys(proof, keys)`. Server-side only (`node:crypto`).
|
|
256
|
+
|
|
229
257
|
## Shared sessions, devices and hosts
|
|
230
258
|
|
|
231
259
|
Shared-sessions and hosts calls need a device UUID (`x-codai-device`). Set it once
|
package/dist/index.d.ts
CHANGED
|
@@ -10940,6 +10940,28 @@ type paths = {
|
|
|
10940
10940
|
readonly patch?: never;
|
|
10941
10941
|
readonly trace?: never;
|
|
10942
10942
|
};
|
|
10943
|
+
readonly '/v1/resolve/balance': {
|
|
10944
|
+
readonly parameters: {
|
|
10945
|
+
readonly query?: never;
|
|
10946
|
+
readonly header?: never;
|
|
10947
|
+
readonly path?: never;
|
|
10948
|
+
readonly cookie?: never;
|
|
10949
|
+
};
|
|
10950
|
+
/**
|
|
10951
|
+
* Fix credits, intro availability and wallet balance
|
|
10952
|
+
* @description Returns what you can pay with right now: the fix-credit balance (usable only on `t7`
|
|
10953
|
+
* jobs), whether the €1 intro price is still available (no verified paid job yet and no
|
|
10954
|
+
* other intro job in flight) and the wallet balance in EUR micros.
|
|
10955
|
+
*/
|
|
10956
|
+
readonly get: operations['getResolveBalance'];
|
|
10957
|
+
readonly put?: never;
|
|
10958
|
+
readonly post?: never;
|
|
10959
|
+
readonly delete?: never;
|
|
10960
|
+
readonly options?: never;
|
|
10961
|
+
readonly head?: never;
|
|
10962
|
+
readonly patch?: never;
|
|
10963
|
+
readonly trace?: never;
|
|
10964
|
+
};
|
|
10943
10965
|
readonly '/v1/resolve/jobs': {
|
|
10944
10966
|
readonly parameters: {
|
|
10945
10967
|
readonly query?: never;
|
|
@@ -11016,6 +11038,11 @@ type paths = {
|
|
|
11016
11038
|
* price). The hold is kept on a verified fix and refunded in full otherwise. If the
|
|
11017
11039
|
* balance is short, the answer is `402 insufficient_funds` with the shortfall and a
|
|
11018
11040
|
* top-up link, and the job stays `quoted` — top up, then call `/accept` again.
|
|
11041
|
+
*
|
|
11042
|
+
* Payment precedence: `intro` (first paid job, €1 hold) > `credit` (t7 only, one fix credit,
|
|
11043
|
+
* no wallet hold) > `wallet` (hold of the list price). `paid_with` in the response says which
|
|
11044
|
+
* was used; `held_micro_eur` is the wallet amount held (`0` for a credit). For a `t7` job the
|
|
11045
|
+
* `402` also carries `bundle_url` (10 fixes for €49).
|
|
11019
11046
|
*/
|
|
11020
11047
|
readonly post: operations['acceptResolveJob'];
|
|
11021
11048
|
readonly delete?: never;
|
|
@@ -11024,13 +11051,43 @@ type paths = {
|
|
|
11024
11051
|
readonly patch?: never;
|
|
11025
11052
|
readonly trace?: never;
|
|
11026
11053
|
};
|
|
11054
|
+
readonly '/v1/resolve/keys': {
|
|
11055
|
+
readonly parameters: {
|
|
11056
|
+
readonly query?: never;
|
|
11057
|
+
readonly header?: never;
|
|
11058
|
+
readonly path?: never;
|
|
11059
|
+
readonly cookie?: never;
|
|
11060
|
+
};
|
|
11061
|
+
/**
|
|
11062
|
+
* Public keys that sign attestations
|
|
11063
|
+
* @description Returns the public key(s) used to sign attestation envelopes (`signature` on
|
|
11064
|
+
* `GET /v1/resolve/attestations/{id}`). ECDSA P-256 / SHA-256 over the DSSE v1 PAE of the
|
|
11065
|
+
* payload; the signature is DER, base64. **Unauthenticated**, CORS-open and cacheable for
|
|
11066
|
+
* 1 hour. Verify with `codaid resolve verify`, `resolve.verifyAttestation` (TypeScript) or
|
|
11067
|
+
* `resolve.verify_attestation` (Python). `503` when signing is not configured.
|
|
11068
|
+
*/
|
|
11069
|
+
readonly get: operations['getResolveKeys'];
|
|
11070
|
+
readonly put?: never;
|
|
11071
|
+
readonly post?: never;
|
|
11072
|
+
readonly delete?: never;
|
|
11073
|
+
readonly options?: never;
|
|
11074
|
+
readonly head?: never;
|
|
11075
|
+
readonly patch?: never;
|
|
11076
|
+
readonly trace?: never;
|
|
11077
|
+
};
|
|
11027
11078
|
};
|
|
11028
11079
|
type components = {
|
|
11029
11080
|
schemas: {
|
|
11030
11081
|
/** Accepted */
|
|
11031
11082
|
readonly ResolveAccepted: {
|
|
11083
|
+
/**
|
|
11084
|
+
* @description Amount held on the wallet in EUR micros — `1000000` for the intro, the quote for `wallet`, `0` for `credit`.
|
|
11085
|
+
* @example 1000000
|
|
11086
|
+
*/
|
|
11087
|
+
readonly held_micro_eur: number;
|
|
11032
11088
|
/** Format: uuid */
|
|
11033
11089
|
readonly id: string;
|
|
11090
|
+
readonly paid_with: components['schemas']['ResolvePaidWith'];
|
|
11034
11091
|
/** @constant */
|
|
11035
11092
|
readonly status: 'accepted';
|
|
11036
11093
|
};
|
|
@@ -11059,6 +11116,13 @@ type components = {
|
|
|
11059
11116
|
readonly repro_test: components['schemas']['ResolveReproTest'] | null;
|
|
11060
11117
|
/** @description Container image digest of the verification runner (`unknown` when not recorded). */
|
|
11061
11118
|
readonly runner_image_digest: string;
|
|
11119
|
+
/**
|
|
11120
|
+
* @description DSSE envelope signing the canonical statement of this attestation (sha256 of the patch,
|
|
11121
|
+
* repro test, test outputs; commands, commit, runner digest, timestamps). `null` for
|
|
11122
|
+
* attestations created before signing was enabled (2026-09-27). Verify against
|
|
11123
|
+
* `GET /v1/resolve/keys`.
|
|
11124
|
+
*/
|
|
11125
|
+
readonly signature: components['schemas']['ResolveAttestationEnvelope'] | null;
|
|
11062
11126
|
/** Format: date-time */
|
|
11063
11127
|
readonly started_at: string;
|
|
11064
11128
|
/** @description FAIL_TO_PASS command that was executed. */
|
|
@@ -11070,6 +11134,46 @@ type components = {
|
|
|
11070
11134
|
/** Format: date-time */
|
|
11071
11135
|
readonly verified_at: string;
|
|
11072
11136
|
};
|
|
11137
|
+
/**
|
|
11138
|
+
* Attestation envelope
|
|
11139
|
+
* @description DSSE v1 envelope. `payload` is base64 of the RFC 8785 (JCS) canonical statement JSON
|
|
11140
|
+
* `{kind: "codai.resolve.attestation.v1", attestation_id, repo_url, base_commit, patch_sha256,
|
|
11141
|
+
* repro_test: {path, sha256} | null, test_command, regression_command,
|
|
11142
|
+
* test_output_before_sha256, test_output_after_sha256, regression_output_sha256,
|
|
11143
|
+
* runner_image_digest, started_at, verified_at}`. Each `sig` is an ECDSA P-256/SHA-256 DER
|
|
11144
|
+
* signature (base64) over `PAE(payloadType, payload bytes)` =
|
|
11145
|
+
* `"DSSEv1 " + len(type) + " " + type + " " + len(body) + " " + body`.
|
|
11146
|
+
*/
|
|
11147
|
+
readonly ResolveAttestationEnvelope: {
|
|
11148
|
+
/** @description Base64 of the canonical statement JSON. */
|
|
11149
|
+
readonly payload: string;
|
|
11150
|
+
/** @constant */
|
|
11151
|
+
readonly payloadType: 'application/vnd.codai.resolve.attestation+json;v=1';
|
|
11152
|
+
readonly signatures: readonly {
|
|
11153
|
+
/** @description Identifier of the signing key; matches `keyid` in `GET /v1/resolve/keys`. */
|
|
11154
|
+
readonly keyid?: string;
|
|
11155
|
+
/** @description DER-encoded ECDSA signature, base64. */
|
|
11156
|
+
readonly sig: string;
|
|
11157
|
+
}[];
|
|
11158
|
+
};
|
|
11159
|
+
/**
|
|
11160
|
+
* Balance
|
|
11161
|
+
* @description Body of `GET /v1/resolve/balance`.
|
|
11162
|
+
*/
|
|
11163
|
+
readonly ResolveBalance: {
|
|
11164
|
+
/**
|
|
11165
|
+
* @description Fix credits left (usable only on `t7` jobs). Buy 10 for €49 at https://pay.codai.ro/checkout?bundle=resolve10.
|
|
11166
|
+
* @example 10
|
|
11167
|
+
*/
|
|
11168
|
+
readonly fix_credits: number;
|
|
11169
|
+
/** @description `true` while your next paid accept would hold the €1 intro price. */
|
|
11170
|
+
readonly intro_available: boolean;
|
|
11171
|
+
/**
|
|
11172
|
+
* @description Wallet balance in EUR micros (`5000000` = €5.00).
|
|
11173
|
+
* @example 5000000
|
|
11174
|
+
*/
|
|
11175
|
+
readonly wallet_micro_eur: number;
|
|
11176
|
+
};
|
|
11073
11177
|
/**
|
|
11074
11178
|
* Declined
|
|
11075
11179
|
* @description `200` body — triage declined the issue. The job is persisted with `status: declined` and is never billed.
|
|
@@ -11114,6 +11218,12 @@ type components = {
|
|
|
11114
11218
|
* @example 5000000
|
|
11115
11219
|
*/
|
|
11116
11220
|
readonly balance: number;
|
|
11221
|
+
/**
|
|
11222
|
+
* Format: uri
|
|
11223
|
+
* @description Present only for a `t7` job — checkout for the fix bundle (10 t7 fix credits for €49).
|
|
11224
|
+
* @example https://pay.codai.ro/checkout?bundle=resolve10
|
|
11225
|
+
*/
|
|
11226
|
+
readonly bundle_url?: string;
|
|
11117
11227
|
/**
|
|
11118
11228
|
* @description Unit of `balance` and `required`.
|
|
11119
11229
|
* @constant
|
|
@@ -11194,6 +11304,8 @@ type components = {
|
|
|
11194
11304
|
readonly fail_reason: string | null;
|
|
11195
11305
|
/** Format: uuid */
|
|
11196
11306
|
readonly id: string;
|
|
11307
|
+
/** @description Present once the job was accepted (and recorded how it was paid). */
|
|
11308
|
+
readonly paid_with?: components['schemas']['ResolvePaidWith'];
|
|
11197
11309
|
/** @description Quoted price in USD micros; `null` until quoted, `0` on the free tier. */
|
|
11198
11310
|
readonly quote_micro_usd: number | null;
|
|
11199
11311
|
/**
|
|
@@ -11213,6 +11325,34 @@ type components = {
|
|
|
11213
11325
|
* @enum {string}
|
|
11214
11326
|
*/
|
|
11215
11327
|
readonly ResolveJobStatus: 'triage' | 'quoted' | 'declined' | 'accepted' | 'running' | 'resolved' | 'failed' | 'error';
|
|
11328
|
+
/** Verification key */
|
|
11329
|
+
readonly ResolveKey: {
|
|
11330
|
+
/** @constant */
|
|
11331
|
+
readonly algorithm: 'ECDSA_P256_SHA256';
|
|
11332
|
+
/**
|
|
11333
|
+
* @description Envelope and signature encoding.
|
|
11334
|
+
* @example DSSE v1; signature DER, base64
|
|
11335
|
+
*/
|
|
11336
|
+
readonly encoding: string;
|
|
11337
|
+
/** @description Key identifier (the Cloud KMS key version name). */
|
|
11338
|
+
readonly keyid: string;
|
|
11339
|
+
/** @constant */
|
|
11340
|
+
readonly payload_type: 'application/vnd.codai.resolve.attestation+json;v=1';
|
|
11341
|
+
/** @description SPKI public key, PEM. */
|
|
11342
|
+
readonly public_key_pem: string;
|
|
11343
|
+
};
|
|
11344
|
+
/** Verification keys */
|
|
11345
|
+
readonly ResolveKeys: {
|
|
11346
|
+
readonly keys: readonly components['schemas']['ResolveKey'][];
|
|
11347
|
+
};
|
|
11348
|
+
/**
|
|
11349
|
+
* Payment method
|
|
11350
|
+
* @description How an accepted job is paid: `free` (free tier), `intro` (first paid job, €1 hold),
|
|
11351
|
+
* `credit` (one t7 fix credit, no wallet hold) or `wallet` (hold of the list price).
|
|
11352
|
+
* Precedence: `free` > `intro` > `credit` > `wallet`.
|
|
11353
|
+
* @enum {string}
|
|
11354
|
+
*/
|
|
11355
|
+
readonly ResolvePaidWith: 'intro' | 'credit' | 'wallet' | 'free';
|
|
11216
11356
|
/**
|
|
11217
11357
|
* Quote
|
|
11218
11358
|
* @description `201` body — the job was quoted (`quoted`) or auto-accepted on the free tier (`accepted`).
|
|
@@ -11228,6 +11368,17 @@ type components = {
|
|
|
11228
11368
|
readonly free_tier_remaining: number;
|
|
11229
11369
|
/** Format: uuid */
|
|
11230
11370
|
readonly id: string;
|
|
11371
|
+
/**
|
|
11372
|
+
* @description Present only on a `quoted` job while the intro price applies to you: accepting holds
|
|
11373
|
+
* this amount (EUR micros, `1000000` = €1) instead of the list price.
|
|
11374
|
+
* @example 1000000
|
|
11375
|
+
*/
|
|
11376
|
+
readonly intro_price_micro_eur?: number;
|
|
11377
|
+
/**
|
|
11378
|
+
* @description Present together with `intro_price_micro_eur`; the regular hold in EUR micros (the quote 1:1).
|
|
11379
|
+
* @example 7000000
|
|
11380
|
+
*/
|
|
11381
|
+
readonly list_price_micro_eur?: number;
|
|
11231
11382
|
/**
|
|
11232
11383
|
* @description Quoted price in USD micros (`7000000` = $7). `0` on the free tier.
|
|
11233
11384
|
* @example 7000000
|
|
@@ -11348,7 +11499,8 @@ type components = {
|
|
|
11348
11499
|
/**
|
|
11349
11500
|
* @description The wallet balance does not cover the quote. Nothing was debited and the job is still
|
|
11350
11501
|
* `quoted`. Open `topup_url` (pay.codai.ro checkout, shortfall rounded up to whole euros,
|
|
11351
|
-
* minimum €10, maximum €1000),
|
|
11502
|
+
* minimum €10, maximum €1000) — or, for a `t7` job, `bundle_url` (10 fix credits for €49) —
|
|
11503
|
+
* then retry `/accept`.
|
|
11352
11504
|
*/
|
|
11353
11505
|
readonly ResolveInsufficientFunds: {
|
|
11354
11506
|
headers: {
|
|
@@ -11452,6 +11604,27 @@ interface operations {
|
|
|
11452
11604
|
readonly 404: components['responses']['ResolveNotFound'];
|
|
11453
11605
|
};
|
|
11454
11606
|
};
|
|
11607
|
+
readonly getResolveBalance: {
|
|
11608
|
+
readonly parameters: {
|
|
11609
|
+
readonly query?: never;
|
|
11610
|
+
readonly header?: never;
|
|
11611
|
+
readonly path?: never;
|
|
11612
|
+
readonly cookie?: never;
|
|
11613
|
+
};
|
|
11614
|
+
readonly requestBody?: never;
|
|
11615
|
+
readonly responses: {
|
|
11616
|
+
/** @description Current balance. */
|
|
11617
|
+
readonly 200: {
|
|
11618
|
+
headers: {
|
|
11619
|
+
readonly [name: string]: unknown;
|
|
11620
|
+
};
|
|
11621
|
+
content: {
|
|
11622
|
+
readonly 'application/json': components['schemas']['ResolveBalance'];
|
|
11623
|
+
};
|
|
11624
|
+
};
|
|
11625
|
+
readonly 401: components['responses']['ResolveUnauthorized'];
|
|
11626
|
+
};
|
|
11627
|
+
};
|
|
11455
11628
|
readonly createResolveJob: {
|
|
11456
11629
|
readonly parameters: {
|
|
11457
11630
|
readonly query?: never;
|
|
@@ -11541,6 +11714,35 @@ interface operations {
|
|
|
11541
11714
|
readonly 409: components['responses']['ResolveConflict'];
|
|
11542
11715
|
};
|
|
11543
11716
|
};
|
|
11717
|
+
readonly getResolveKeys: {
|
|
11718
|
+
readonly parameters: {
|
|
11719
|
+
readonly query?: never;
|
|
11720
|
+
readonly header?: never;
|
|
11721
|
+
readonly path?: never;
|
|
11722
|
+
readonly cookie?: never;
|
|
11723
|
+
};
|
|
11724
|
+
readonly requestBody?: never;
|
|
11725
|
+
readonly responses: {
|
|
11726
|
+
/** @description Current verification keys. */
|
|
11727
|
+
readonly 200: {
|
|
11728
|
+
headers: {
|
|
11729
|
+
readonly [name: string]: unknown;
|
|
11730
|
+
};
|
|
11731
|
+
content: {
|
|
11732
|
+
readonly 'application/json': components['schemas']['ResolveKeys'];
|
|
11733
|
+
};
|
|
11734
|
+
};
|
|
11735
|
+
/** @description Attestation signing is not configured (`attestation signing not configured`). */
|
|
11736
|
+
readonly 503: {
|
|
11737
|
+
headers: {
|
|
11738
|
+
readonly [name: string]: unknown;
|
|
11739
|
+
};
|
|
11740
|
+
content: {
|
|
11741
|
+
readonly 'application/json': components['schemas']['ResolveError'];
|
|
11742
|
+
};
|
|
11743
|
+
};
|
|
11744
|
+
};
|
|
11745
|
+
};
|
|
11544
11746
|
readonly resolveJobWebhook: {
|
|
11545
11747
|
readonly parameters: {
|
|
11546
11748
|
readonly query?: never;
|
|
@@ -11588,10 +11790,18 @@ type ResolveDeclined = ResolveSchemas['ResolveDeclined'];
|
|
|
11588
11790
|
/** `submit()` result: `201` quote / free-tier auto-accept, or `200` decline. */
|
|
11589
11791
|
type ResolveSubmitResult = ResolveQuote | ResolveDeclined;
|
|
11590
11792
|
type ResolveAccepted = ResolveSchemas['ResolveAccepted'];
|
|
11793
|
+
/** How an accepted job is paid: `free` > `intro` (€1) > `credit` (t7 fix credit) > `wallet`. */
|
|
11794
|
+
type ResolvePaidWith = ResolveSchemas['ResolvePaidWith'];
|
|
11795
|
+
/** `GET /v1/resolve/balance` — fix credits, intro availability, wallet (EUR micros). */
|
|
11796
|
+
type ResolveBalance = ResolveSchemas['ResolveBalance'];
|
|
11591
11797
|
type ResolveJob = ResolveSchemas['ResolveJob'];
|
|
11592
11798
|
type ResolveJobStatus = ResolveSchemas['ResolveJobStatus'];
|
|
11593
11799
|
type ResolveTier = ResolveSchemas['ResolveTier'];
|
|
11594
11800
|
type ResolveAttestation = ResolveSchemas['ResolveAttestation'];
|
|
11801
|
+
/** DSSE v1 envelope in `ResolveAttestation.signature` (`null` = unsigned, pre-2026-09-27). */
|
|
11802
|
+
type ResolveAttestationEnvelope = ResolveSchemas['ResolveAttestationEnvelope'];
|
|
11803
|
+
type ResolveKeys = ResolveSchemas['ResolveKeys'];
|
|
11804
|
+
type ResolveKey = ResolveSchemas['ResolveKey'];
|
|
11595
11805
|
type ResolveReproTest = ResolveSchemas['ResolveReproTest'];
|
|
11596
11806
|
type ResolveHealth = ResolveSchemas['ResolveHealth'];
|
|
11597
11807
|
type ResolveValidationDetails = ResolveSchemas['ResolveValidationDetails'];
|
|
@@ -11617,6 +11827,25 @@ interface VerifyResolveWebhookOptions {
|
|
|
11617
11827
|
* Throws only when `node:crypto` is unavailable in the current runtime.
|
|
11618
11828
|
*/
|
|
11619
11829
|
declare function verifyResolveWebhook(secret: string, rawBody: string | Uint8Array, signatureHeader: string | null | undefined, opts?: VerifyResolveWebhookOptions): boolean;
|
|
11830
|
+
/** `payloadType` of Resolve attestation envelopes. */
|
|
11831
|
+
declare const RESOLVE_ATTESTATION_PAYLOAD_TYPE = "application/vnd.codai.resolve.attestation+json;v=1";
|
|
11832
|
+
type ResolveAttestationVerifyResult = {
|
|
11833
|
+
ok: true;
|
|
11834
|
+
keyid: string;
|
|
11835
|
+
} | {
|
|
11836
|
+
ok: false;
|
|
11837
|
+
reason: 'UNSIGNED' | 'BAD_SIGNATURE' | 'STATEMENT_MISMATCH' | 'BAD_PAYLOAD_TYPE';
|
|
11838
|
+
};
|
|
11839
|
+
/** The statement the Resolve service signs, recomputed from the attestation JSON. */
|
|
11840
|
+
declare function resolveAttestationStatement(att: ResolveAttestation): Record<string, unknown>;
|
|
11841
|
+
/**
|
|
11842
|
+
* Verify a Resolve attestation offline against published keys: the DSSE
|
|
11843
|
+
* signature (ECDSA P-256/SHA-256, DER) over `PAE(payloadType, payload)` must
|
|
11844
|
+
* match one key, AND the signed statement must equal the one recomputed from
|
|
11845
|
+
* the attestation's own fields (so a valid signature over other content fails).
|
|
11846
|
+
* Server-side only (`node:crypto`, loaded lazily).
|
|
11847
|
+
*/
|
|
11848
|
+
declare function verifyAttestationWithKeys(att: ResolveAttestation, keys: ResolveKeys): ResolveAttestationVerifyResult;
|
|
11620
11849
|
/** Statuses after which a job never changes again. */
|
|
11621
11850
|
declare const RESOLVE_TERMINAL_STATUSES: ReadonlySet<ResolveJobStatus>;
|
|
11622
11851
|
/** Any non-2xx answer from the Resolve service (flat `{ error }` body). */
|
|
@@ -11637,6 +11866,8 @@ declare class ResolveInsufficientFundsError extends ResolveError {
|
|
|
11637
11866
|
readonly currency: 'micro_eur';
|
|
11638
11867
|
/** pay.codai.ro checkout link for the shortfall — open it, then retry `accept()`. */
|
|
11639
11868
|
readonly topupUrl: string;
|
|
11869
|
+
/** Present only for a `t7` job: fix-bundle checkout (10 t7 fix credits for €49). */
|
|
11870
|
+
readonly bundleUrl?: string;
|
|
11640
11871
|
constructor(message: string, body: ResolveInsufficientFunds, meta?: {
|
|
11641
11872
|
requestId?: string | null;
|
|
11642
11873
|
});
|
|
@@ -11669,8 +11900,10 @@ declare class Resolve {
|
|
|
11669
11900
|
get(id: string, opts?: CallOpts$4): Promise<ResolveJob>;
|
|
11670
11901
|
/**
|
|
11671
11902
|
* `POST /v1/resolve/jobs/{id}/accept` — accept a paid quote and start the job.
|
|
11672
|
-
*
|
|
11673
|
-
*
|
|
11903
|
+
* The result's `paid_with` says how it was paid (`intro` €1 hold, `credit`
|
|
11904
|
+
* t7 fix credit, or `wallet`). Throws `ResolveInsufficientFundsError` (402,
|
|
11905
|
+
* carries `topupUrl`, plus `bundleUrl` for t7) when the wallet is short,
|
|
11906
|
+
* `ResolveError` 409 when the job is not `quoted`.
|
|
11674
11907
|
*/
|
|
11675
11908
|
accept(id: string, opts?: CallOpts$4): Promise<ResolveAccepted>;
|
|
11676
11909
|
/**
|
|
@@ -11680,6 +11913,20 @@ declare class Resolve {
|
|
|
11680
11913
|
attestation(idOrUrl: string, opts?: CallOpts$4): Promise<ResolveAttestation>;
|
|
11681
11914
|
/** `GET /health` — liveness of the Resolve service. */
|
|
11682
11915
|
health(opts?: CallOpts$4): Promise<ResolveHealth>;
|
|
11916
|
+
/** `GET /v1/resolve/balance` — fix credits (t7 only), intro availability and wallet balance. */
|
|
11917
|
+
balance(opts?: CallOpts$4): Promise<ResolveBalance>;
|
|
11918
|
+
/** `GET /v1/resolve/keys` — public keys that sign attestations (no auth needed server-side). */
|
|
11919
|
+
keys(opts?: CallOpts$4): Promise<ResolveKeys>;
|
|
11920
|
+
/**
|
|
11921
|
+
* Verify an attestation's signature and that the signed statement matches
|
|
11922
|
+
* its fields. Fetches `keys()` unless `opts.keys` is given (pin them to
|
|
11923
|
+
* avoid trusting the network). `{ ok: false, reason: 'UNSIGNED' }` for
|
|
11924
|
+
* attestations created before signing (2026-09-27). Server-side only.
|
|
11925
|
+
*/
|
|
11926
|
+
verifyAttestation(att: ResolveAttestation, opts?: {
|
|
11927
|
+
keys?: ResolveKeys;
|
|
11928
|
+
signal?: AbortSignal;
|
|
11929
|
+
}): Promise<ResolveAttestationVerifyResult>;
|
|
11683
11930
|
/**
|
|
11684
11931
|
* Poll `get(id)` until the job reaches a terminal status (`resolved`,
|
|
11685
11932
|
* `failed`, `declined`, `error`) or one of `opts.until`. A `quoted` job
|
|
@@ -12186,4 +12433,4 @@ declare class Codai {
|
|
|
12186
12433
|
private legacyExt;
|
|
12187
12434
|
}
|
|
12188
12435
|
|
|
12189
|
-
export { Account, type AccountPatchRequest, type AccountPatchResponse, type AccountView, type AgentRun, type AgentRunAccepted, type AgentRunCreateRequest, type AgentRunRequest, type AgentRunResult, type AgentRunStats, type AgentRunStatus, type AgentRunStep, type AgentRunStreamEvent, AgentRuns, type AgentSyncResult, Agents, Audio, Chat, type ChatCallOptions, type ChatCompletionChunk, type ChatCompletionInput, type ChatCompletionRequest, type ChatCompletionResponse, ChatCompletions, type ChatMessage, type ChatOptions, type ChatResult, type ChatStream, type ChatStreamResult, type ChatTool, type ChatToolCall, type ChatUsage, Codai, type CodaiClientOptions, CodaiError, type CodaiRequestExtensions, type Device, type DevicePatch, type DevicePatched, Devices, type DispatchInbox, Embeddings, type EmbeddingsOptions, type EmbeddingsRequest, type EmbeddingsResponse, type EmbeddingsResult, type Environment, type EnvironmentAddMemberBody, type EnvironmentCreateBody, type EnvironmentDetail, type EnvironmentEnrollBody, type EnvironmentEnrollToken, type EnvironmentEnrolled, type EnvironmentMember, type EnvironmentMemberCreated, EnvironmentMembers, type EnvironmentPatchBody, type EnvironmentPort, type EnvironmentPortBody, EnvironmentPorts, type EnvironmentProvider, type EnvironmentRole, type EnvironmentSecret, type EnvironmentSecretSet, EnvironmentSecrets, type EnvironmentSshCa, type EnvironmentSshCert, type EnvironmentSshCertBody, type EnvironmentState, type EnvironmentTaskCreateBody, type EnvironmentTaskCreated, type EnvironmentTaskDetail, type EnvironmentTaskList, EnvironmentTasks, type EnvironmentTransition, Environments, type EphemeralScope, type EphemeralToken, type EphemeralTokenResponse, type ErrorCode, Feedback, type FeedbackRequest, type FeedbackResponse, Health, type HealthReadyResponse, type HealthResponse, type HostExecBody, type HostExecRequest, type HostExecResponse, type HostExecResultBody, type HostOp, type HostPresence, type HostStreamEvent, Hosts, HttpClient, type ListEnvironmentsQuery, type MessageCallOptions, type MessageInput, type MessageRequest, type MessageResponse, type MessageResult, type MessageStream, type MessageStreamEvent, type MessageStreamResult, Messages, type Model, type ModelList, Models, type NotificationList, Notifications, type NotificationsDeleted, type NotificationsRead, OPERATION_METHODS, type Org, type OrgAddMemberBody, type OrgMember, OrgMembers, type OrgRole, Orgs, type PhoneModel, PhoneModels, type Project, type ProjectCreateBody, type ProjectDetail, type ProjectIsolation, type ProjectPatchBody, Projects, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, type Receipt, Receipts, type RequestOptions, Resolve, type ResolveAccepted, type ResolveAttestation, type components as ResolveComponents, type ResolveDeclined, ResolveError, type ResolveHealth, type ResolveInsufficientFunds, ResolveInsufficientFundsError, type ResolveIntake, type ResolveJob, type ResolveJobStatus, type operations as ResolveOperations, type paths as ResolvePaths, type ResolveQuote, type ResolveReproTest, type ResolveSubmitResult, type ResolveTier, type ResolveValidationDetails, type ResolveWaitOptions, type ResolveWebhookEvent, type ResolveWebhookEventName, type ResolveWebhookJob, Responses, type ResponsesCallOptions, type ResponsesInput, type ResponsesRequest, type ResponsesResponse, type ResponsesResult, type ResponsesStream, type ResponsesStreamEvent, type ResponsesStreamResult, STREAMING_OPERATIONS, type Session, type SessionControl, type SessionControlAccepted, type SessionControlRequest, SessionControls, type SessionCreateRequest, type SessionDetail, type SessionDispatchRequest, type SessionDispatchResponse, type SessionEvent, SessionEvents, type SessionEventsAppendRequest, type SessionEventsAppendResponse, type SessionEventsPage, type SessionIncomingEvent, SessionLease, type SessionLeaseClaimRequest, type SessionLeaseResponse, type SessionListItem, type SessionPatchRequest, type SessionShare, type SessionShareCreateRequest, type SessionShareCreated, SessionShares, type SessionStreamEvent, Sessions, type SharedSession, type SpeechRequest, type SpeechResult, type SseFrame, type StatusResponse, type Task, type TaskConfirmRequest, type TaskConfirmResponse, type TaskListPage, type TaskListQuery, type TaskOutcome, type TaskStats, Tasks, type TokenUsage, Tokens, type ToolFetchRequest, type ToolFetchResponse, type ToolSearchRequest, type ToolSearchResponse, Tools, type TranscriptionOptions, type TranscriptionResponse, type TranscriptionResult, type TriggerCreateRequest, type TriggerCreated, type TriggerEvents, type TriggerList, type TriggerPatch, type TriggerTestRequest, type TriggerTestResult, type TriggerUpdated, Triggers, type VerifyResolveWebhookOptions, type components$1 as components, Codai as default, extensionHeaders, frameJson, mergeToolCall, type operations$1 as operations, type paths$1 as paths, readSse, verifyResolveWebhook };
|
|
12436
|
+
export { Account, type AccountPatchRequest, type AccountPatchResponse, type AccountView, type AgentRun, type AgentRunAccepted, type AgentRunCreateRequest, type AgentRunRequest, type AgentRunResult, type AgentRunStats, type AgentRunStatus, type AgentRunStep, type AgentRunStreamEvent, AgentRuns, type AgentSyncResult, Agents, Audio, Chat, type ChatCallOptions, type ChatCompletionChunk, type ChatCompletionInput, type ChatCompletionRequest, type ChatCompletionResponse, ChatCompletions, type ChatMessage, type ChatOptions, type ChatResult, type ChatStream, type ChatStreamResult, type ChatTool, type ChatToolCall, type ChatUsage, Codai, type CodaiClientOptions, CodaiError, type CodaiRequestExtensions, type Device, type DevicePatch, type DevicePatched, Devices, type DispatchInbox, Embeddings, type EmbeddingsOptions, type EmbeddingsRequest, type EmbeddingsResponse, type EmbeddingsResult, type Environment, type EnvironmentAddMemberBody, type EnvironmentCreateBody, type EnvironmentDetail, type EnvironmentEnrollBody, type EnvironmentEnrollToken, type EnvironmentEnrolled, type EnvironmentMember, type EnvironmentMemberCreated, EnvironmentMembers, type EnvironmentPatchBody, type EnvironmentPort, type EnvironmentPortBody, EnvironmentPorts, type EnvironmentProvider, type EnvironmentRole, type EnvironmentSecret, type EnvironmentSecretSet, EnvironmentSecrets, type EnvironmentSshCa, type EnvironmentSshCert, type EnvironmentSshCertBody, type EnvironmentState, type EnvironmentTaskCreateBody, type EnvironmentTaskCreated, type EnvironmentTaskDetail, type EnvironmentTaskList, EnvironmentTasks, type EnvironmentTransition, Environments, type EphemeralScope, type EphemeralToken, type EphemeralTokenResponse, type ErrorCode, Feedback, type FeedbackRequest, type FeedbackResponse, Health, type HealthReadyResponse, type HealthResponse, type HostExecBody, type HostExecRequest, type HostExecResponse, type HostExecResultBody, type HostOp, type HostPresence, type HostStreamEvent, Hosts, HttpClient, type ListEnvironmentsQuery, type MessageCallOptions, type MessageInput, type MessageRequest, type MessageResponse, type MessageResult, type MessageStream, type MessageStreamEvent, type MessageStreamResult, Messages, type Model, type ModelList, Models, type NotificationList, Notifications, type NotificationsDeleted, type NotificationsRead, OPERATION_METHODS, type Org, type OrgAddMemberBody, type OrgMember, OrgMembers, type OrgRole, Orgs, type PhoneModel, PhoneModels, type Project, type ProjectCreateBody, type ProjectDetail, type ProjectIsolation, type ProjectPatchBody, Projects, RESOLVE_ATTESTATION_PAYLOAD_TYPE, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, type Receipt, Receipts, type RequestOptions, Resolve, type ResolveAccepted, type ResolveAttestation, type ResolveAttestationEnvelope, type ResolveAttestationVerifyResult, type ResolveBalance, type components as ResolveComponents, type ResolveDeclined, ResolveError, type ResolveHealth, type ResolveInsufficientFunds, ResolveInsufficientFundsError, type ResolveIntake, type ResolveJob, type ResolveJobStatus, type ResolveKey, type ResolveKeys, type operations as ResolveOperations, type ResolvePaidWith, type paths as ResolvePaths, type ResolveQuote, type ResolveReproTest, type ResolveSubmitResult, type ResolveTier, type ResolveValidationDetails, type ResolveWaitOptions, type ResolveWebhookEvent, type ResolveWebhookEventName, type ResolveWebhookJob, Responses, type ResponsesCallOptions, type ResponsesInput, type ResponsesRequest, type ResponsesResponse, type ResponsesResult, type ResponsesStream, type ResponsesStreamEvent, type ResponsesStreamResult, STREAMING_OPERATIONS, type Session, type SessionControl, type SessionControlAccepted, type SessionControlRequest, SessionControls, type SessionCreateRequest, type SessionDetail, type SessionDispatchRequest, type SessionDispatchResponse, type SessionEvent, SessionEvents, type SessionEventsAppendRequest, type SessionEventsAppendResponse, type SessionEventsPage, type SessionIncomingEvent, SessionLease, type SessionLeaseClaimRequest, type SessionLeaseResponse, type SessionListItem, type SessionPatchRequest, type SessionShare, type SessionShareCreateRequest, type SessionShareCreated, SessionShares, type SessionStreamEvent, Sessions, type SharedSession, type SpeechRequest, type SpeechResult, type SseFrame, type StatusResponse, type Task, type TaskConfirmRequest, type TaskConfirmResponse, type TaskListPage, type TaskListQuery, type TaskOutcome, type TaskStats, Tasks, type TokenUsage, Tokens, type ToolFetchRequest, type ToolFetchResponse, type ToolSearchRequest, type ToolSearchResponse, Tools, type TranscriptionOptions, type TranscriptionResponse, type TranscriptionResult, type TriggerCreateRequest, type TriggerCreated, type TriggerEvents, type TriggerList, type TriggerPatch, type TriggerTestRequest, type TriggerTestResult, type TriggerUpdated, Triggers, type VerifyResolveWebhookOptions, type components$1 as components, Codai as default, extensionHeaders, frameJson, mergeToolCall, type operations$1 as operations, type paths$1 as paths, readSse, resolveAttestationStatement, verifyAttestationWithKeys, verifyResolveWebhook };
|
package/dist/index.js
CHANGED
|
@@ -1260,6 +1260,105 @@ function hexToBytes(hex) {
|
|
|
1260
1260
|
for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
1261
1261
|
return out;
|
|
1262
1262
|
}
|
|
1263
|
+
var RESOLVE_ATTESTATION_PAYLOAD_TYPE = "application/vnd.codai.resolve.attestation+json;v=1";
|
|
1264
|
+
function verifyCrypto() {
|
|
1265
|
+
const proc = globalThis.process;
|
|
1266
|
+
const mod = proc?.getBuiltinModule?.("node:crypto");
|
|
1267
|
+
if (!mod) {
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
"verifyAttestation needs node:crypto (Node 20.16+/22.3+, Bun or Deno); run it server-side"
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
return mod;
|
|
1273
|
+
}
|
|
1274
|
+
function canonicalJson(v) {
|
|
1275
|
+
if (v === null || typeof v !== "object") return JSON.stringify(v);
|
|
1276
|
+
if (Array.isArray(v)) return `[${v.map(canonicalJson).join(",")}]`;
|
|
1277
|
+
const o = v;
|
|
1278
|
+
return `{${Object.keys(o).filter((k) => o[k] !== void 0).sort().map((k) => `${JSON.stringify(k)}:${canonicalJson(o[k])}`).join(",")}}`;
|
|
1279
|
+
}
|
|
1280
|
+
function base64ToBytes(b64) {
|
|
1281
|
+
const bin = atob(b64);
|
|
1282
|
+
const out = new Uint8Array(bin.length);
|
|
1283
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
1284
|
+
return out;
|
|
1285
|
+
}
|
|
1286
|
+
function pae(payloadType, body) {
|
|
1287
|
+
const enc2 = new TextEncoder();
|
|
1288
|
+
const typeBytes = enc2.encode(payloadType);
|
|
1289
|
+
const head = enc2.encode(`DSSEv1 ${typeBytes.length} ${payloadType} ${body.length} `);
|
|
1290
|
+
const out = new Uint8Array(head.length + body.length);
|
|
1291
|
+
out.set(head, 0);
|
|
1292
|
+
out.set(body, head.length);
|
|
1293
|
+
return out;
|
|
1294
|
+
}
|
|
1295
|
+
function resolveAttestationStatement(att) {
|
|
1296
|
+
const { createHash } = verifyCrypto();
|
|
1297
|
+
const enc2 = new TextEncoder();
|
|
1298
|
+
const sha = (s) => s == null ? null : createHash("sha256").update(enc2.encode(s)).digest("hex");
|
|
1299
|
+
return {
|
|
1300
|
+
kind: "codai.resolve.attestation.v1",
|
|
1301
|
+
attestation_id: att.id,
|
|
1302
|
+
repo_url: att.repo_url,
|
|
1303
|
+
base_commit: att.base_commit,
|
|
1304
|
+
patch_sha256: sha(att.patch),
|
|
1305
|
+
repro_test: att.repro_test?.path ? { path: att.repro_test.path, sha256: sha(att.repro_test.content) } : null,
|
|
1306
|
+
test_command: att.test_command,
|
|
1307
|
+
regression_command: att.regression_command,
|
|
1308
|
+
test_output_before_sha256: sha(att.test_output_before),
|
|
1309
|
+
test_output_after_sha256: sha(att.test_output_after),
|
|
1310
|
+
regression_output_sha256: sha(att.regression_output),
|
|
1311
|
+
runner_image_digest: att.runner_image_digest,
|
|
1312
|
+
started_at: att.started_at,
|
|
1313
|
+
verified_at: att.verified_at
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
function verifyAttestationWithKeys(att, keys) {
|
|
1317
|
+
const env = att.signature;
|
|
1318
|
+
if (!env || !Array.isArray(env.signatures) || env.signatures.length === 0)
|
|
1319
|
+
return { ok: false, reason: "UNSIGNED" };
|
|
1320
|
+
if (env.payloadType !== RESOLVE_ATTESTATION_PAYLOAD_TYPE)
|
|
1321
|
+
return { ok: false, reason: "BAD_PAYLOAD_TYPE" };
|
|
1322
|
+
const { createVerify } = verifyCrypto();
|
|
1323
|
+
let body;
|
|
1324
|
+
try {
|
|
1325
|
+
body = base64ToBytes(env.payload);
|
|
1326
|
+
} catch {
|
|
1327
|
+
return { ok: false, reason: "BAD_SIGNATURE" };
|
|
1328
|
+
}
|
|
1329
|
+
const msg = pae(env.payloadType, body);
|
|
1330
|
+
let keyid = null;
|
|
1331
|
+
outer: for (const s of env.signatures) {
|
|
1332
|
+
let sig;
|
|
1333
|
+
try {
|
|
1334
|
+
sig = base64ToBytes(s.sig);
|
|
1335
|
+
} catch {
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
for (const k of keys.keys) {
|
|
1339
|
+
if (k.payload_type && k.payload_type !== env.payloadType) continue;
|
|
1340
|
+
try {
|
|
1341
|
+
const v = createVerify("SHA256");
|
|
1342
|
+
v.update(msg);
|
|
1343
|
+
if (v.verify({ key: k.public_key_pem, dsaEncoding: "der" }, sig)) {
|
|
1344
|
+
keyid = k.keyid;
|
|
1345
|
+
break outer;
|
|
1346
|
+
}
|
|
1347
|
+
} catch {
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (keyid === null) return { ok: false, reason: "BAD_SIGNATURE" };
|
|
1352
|
+
let signed;
|
|
1353
|
+
try {
|
|
1354
|
+
signed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(body));
|
|
1355
|
+
} catch {
|
|
1356
|
+
return { ok: false, reason: "STATEMENT_MISMATCH" };
|
|
1357
|
+
}
|
|
1358
|
+
if (canonicalJson(signed) !== canonicalJson(resolveAttestationStatement(att)))
|
|
1359
|
+
return { ok: false, reason: "STATEMENT_MISMATCH" };
|
|
1360
|
+
return { ok: true, keyid };
|
|
1361
|
+
}
|
|
1263
1362
|
var RESOLVE_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
1264
1363
|
"resolved",
|
|
1265
1364
|
"failed",
|
|
@@ -1283,6 +1382,8 @@ var ResolveInsufficientFundsError = class extends ResolveError {
|
|
|
1283
1382
|
currency;
|
|
1284
1383
|
/** pay.codai.ro checkout link for the shortfall — open it, then retry `accept()`. */
|
|
1285
1384
|
topupUrl;
|
|
1385
|
+
/** Present only for a `t7` job: fix-bundle checkout (10 t7 fix credits for €49). */
|
|
1386
|
+
bundleUrl;
|
|
1286
1387
|
constructor(message, body, meta = {}) {
|
|
1287
1388
|
super(message, 402, body, meta);
|
|
1288
1389
|
this.name = "ResolveInsufficientFundsError";
|
|
@@ -1290,6 +1391,7 @@ var ResolveInsufficientFundsError = class extends ResolveError {
|
|
|
1290
1391
|
this.required = body.required;
|
|
1291
1392
|
this.currency = body.currency;
|
|
1292
1393
|
this.topupUrl = body.topup_url;
|
|
1394
|
+
if (typeof body.bundle_url === "string") this.bundleUrl = body.bundle_url;
|
|
1293
1395
|
}
|
|
1294
1396
|
};
|
|
1295
1397
|
var Resolve = class {
|
|
@@ -1321,8 +1423,10 @@ var Resolve = class {
|
|
|
1321
1423
|
}
|
|
1322
1424
|
/**
|
|
1323
1425
|
* `POST /v1/resolve/jobs/{id}/accept` — accept a paid quote and start the job.
|
|
1324
|
-
*
|
|
1325
|
-
*
|
|
1426
|
+
* The result's `paid_with` says how it was paid (`intro` €1 hold, `credit`
|
|
1427
|
+
* t7 fix credit, or `wallet`). Throws `ResolveInsufficientFundsError` (402,
|
|
1428
|
+
* carries `topupUrl`, plus `bundleUrl` for t7) when the wallet is short,
|
|
1429
|
+
* `ResolveError` 409 when the job is not `quoted`.
|
|
1326
1430
|
*/
|
|
1327
1431
|
accept(id, opts = {}) {
|
|
1328
1432
|
return this.call(`/v1/resolve/jobs/${encodeURIComponent(id)}/accept`, {
|
|
@@ -1347,6 +1451,25 @@ var Resolve = class {
|
|
|
1347
1451
|
health(opts = {}) {
|
|
1348
1452
|
return this.call("/health", { signal: opts.signal });
|
|
1349
1453
|
}
|
|
1454
|
+
/** `GET /v1/resolve/balance` — fix credits (t7 only), intro availability and wallet balance. */
|
|
1455
|
+
balance(opts = {}) {
|
|
1456
|
+
return this.call("/v1/resolve/balance", { signal: opts.signal });
|
|
1457
|
+
}
|
|
1458
|
+
/** `GET /v1/resolve/keys` — public keys that sign attestations (no auth needed server-side). */
|
|
1459
|
+
keys(opts = {}) {
|
|
1460
|
+
return this.call("/v1/resolve/keys", { signal: opts.signal });
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Verify an attestation's signature and that the signed statement matches
|
|
1464
|
+
* its fields. Fetches `keys()` unless `opts.keys` is given (pin them to
|
|
1465
|
+
* avoid trusting the network). `{ ok: false, reason: 'UNSIGNED' }` for
|
|
1466
|
+
* attestations created before signing (2026-09-27). Server-side only.
|
|
1467
|
+
*/
|
|
1468
|
+
async verifyAttestation(att, opts = {}) {
|
|
1469
|
+
if (!att.signature) return { ok: false, reason: "UNSIGNED" };
|
|
1470
|
+
const keys = opts.keys ?? await this.keys({ signal: opts.signal });
|
|
1471
|
+
return verifyAttestationWithKeys(att, keys);
|
|
1472
|
+
}
|
|
1350
1473
|
/**
|
|
1351
1474
|
* Poll `get(id)` until the job reaches a terminal status (`resolved`,
|
|
1352
1475
|
* `failed`, `declined`, `error`) or one of `opts.until`. A `quoted` job
|
|
@@ -1397,7 +1520,7 @@ function toResolveError(path, err) {
|
|
|
1397
1520
|
if (err.status === 402 && isInsufficientFunds(err.body)) {
|
|
1398
1521
|
const b = err.body;
|
|
1399
1522
|
return new ResolveInsufficientFundsError(
|
|
1400
|
-
`codai-resolve ${path} \u2192 402: insufficient funds (balance ${b.balance}, required ${b.required} ${b.currency}); top up at ${b.topup_url}`,
|
|
1523
|
+
`codai-resolve ${path} \u2192 402: insufficient funds (balance ${b.balance}, required ${b.required} ${b.currency}); top up at ${b.topup_url}${b.bundle_url ? ` or buy 10 t7 fixes for \u20AC49 at ${b.bundle_url}` : ""}`,
|
|
1401
1524
|
b,
|
|
1402
1525
|
meta
|
|
1403
1526
|
);
|
|
@@ -2059,7 +2182,9 @@ var RESOLVE_OPERATION_METHODS = {
|
|
|
2059
2182
|
createResolveJob: "resolve.submit",
|
|
2060
2183
|
getResolveJob: "resolve.get",
|
|
2061
2184
|
acceptResolveJob: "resolve.accept",
|
|
2062
|
-
getResolveAttestation: "resolve.attestation"
|
|
2185
|
+
getResolveAttestation: "resolve.attestation",
|
|
2186
|
+
getResolveKeys: "resolve.keys",
|
|
2187
|
+
getResolveBalance: "resolve.balance"
|
|
2063
2188
|
};
|
|
2064
2189
|
|
|
2065
2190
|
// src/index.ts
|
|
@@ -2227,6 +2352,6 @@ function allKeys(obj) {
|
|
|
2227
2352
|
}
|
|
2228
2353
|
var index_default = Codai;
|
|
2229
2354
|
|
|
2230
|
-
export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, EnvironmentMembers, EnvironmentPorts, EnvironmentSecrets, EnvironmentTasks, Environments, Feedback, Health, Hosts, HttpClient, Messages, Models, Notifications, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Projects, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, Receipts, Resolve, ResolveError, ResolveInsufficientFundsError, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, Triggers, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse, verifyResolveWebhook };
|
|
2355
|
+
export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, EnvironmentMembers, EnvironmentPorts, EnvironmentSecrets, EnvironmentTasks, Environments, Feedback, Health, Hosts, HttpClient, Messages, Models, Notifications, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Projects, RESOLVE_ATTESTATION_PAYLOAD_TYPE, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, Receipts, Resolve, ResolveError, ResolveInsufficientFundsError, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, Triggers, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse, resolveAttestationStatement, verifyAttestationWithKeys, verifyResolveWebhook };
|
|
2231
2356
|
//# sourceMappingURL=index.js.map
|
|
2232
2357
|
//# sourceMappingURL=index.js.map
|