@dvmkit/sdk 0.7.0-rc.7 → 0.7.0-rc.9
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 +6 -2
- package/dist/{chunk-YK54BJ2L.js → chunk-2DE32RAW.js} +1 -1
- package/dist/{chunk-NUPEAWRM.js → chunk-2GTLF74N.js} +1 -1
- package/dist/{chunk-MYJOV4R4.js → chunk-2HAFZ5GC.js} +1 -1
- package/dist/{chunk-LQQ6H4UB.js → chunk-5CSR33B5.js} +1 -1
- package/dist/{chunk-FXDQMJQ2.js → chunk-5PLQOC4B.js} +29 -3
- package/dist/{chunk-QTH7CIA3.js → chunk-5TIFEMHJ.js} +83 -1
- package/dist/{chunk-JUEEUV5X.js → chunk-6JZDFYQL.js} +15 -4
- package/dist/{chunk-BDHJVTWA.js → chunk-7RZEJJTN.js} +1 -1
- package/dist/{chunk-XEOTTFLH.js → chunk-FYETJDBB.js} +1 -1
- package/dist/{chunk-HGMS3LR7.js → chunk-G7IXOVKV.js} +27 -21
- package/dist/{chunk-GDCIHJAR.js → chunk-HU6ZMQDN.js} +1 -1
- package/dist/{chunk-WP7UX6RF.js → chunk-IOKEKMIU.js} +2 -2
- package/dist/{chunk-6RYCZLCK.js → chunk-QM2OS3NJ.js} +1 -1
- package/dist/{chunk-KYCLHWKO.js → chunk-QN3CQOE2.js} +1 -1
- package/dist/{chunk-SX4WCPW7.js → chunk-RGSWVNQG.js} +1 -1
- package/dist/{chunk-HG2CZPRJ.js → chunk-RJFBBEWQ.js} +1 -1
- package/dist/{chunk-BIZR5ORK.js → chunk-WGK5KZ6S.js} +2 -2
- package/dist/{chunk-FOJKZ4E7.js → chunk-YE53E4BT.js} +1 -1
- package/dist/{chunk-3VFEX2Y3.js → chunk-YNHXOONR.js} +1 -1
- package/dist/{chunk-X5RY2G3C.js → chunk-YS6PWVCZ.js} +1 -1
- package/dist/{chunk-BQP3LU2O.js → chunk-ZLWPEIE2.js} +1 -1
- package/dist/{credit-ledger-SW4BGMNH.js → credit-ledger-F2LWQU6N.js} +3 -3
- package/dist/{credit-menu-Bm8opjYy.d.ts → credit-menu-CUJdCfpt.d.ts} +2 -0
- package/dist/index.js +4 -4
- package/dist/internal/caller.d.ts +64 -1
- package/dist/internal/caller.js +14 -6
- package/dist/internal/index.js +1 -1
- package/dist/internal/server.d.ts +2 -2
- package/dist/internal/server.js +19 -19
- package/dist/{memory-credit-ledger-E4C3VQE4.js → memory-credit-ledger-XOOWJTBZ.js} +4 -4
- package/dist/{mpp-setup-BYKGEYFA.js → mpp-setup-KGX6PLAF.js} +2 -2
- package/dist/{payout-reporter-3UVWPGMO.js → payout-reporter-W3CCLYCN.js} +2 -2
- package/dist/{postgres-consumed-credential-store-EZ4KETWH.js → postgres-consumed-credential-store-LUJ5CUJS.js} +1 -1
- package/dist/{postgres-job-store-E6AUHNKB.js → postgres-job-store-IX7IUXF4.js} +2 -2
- package/dist/{postgres-replay-store-GIYZS4LJ.js → postgres-replay-store-Q6MEQDWZ.js} +2 -2
- package/dist/{pricing-DG5IJ5QF.js → pricing-ZUEFO3CM.js} +3 -3
- package/dist/{revenue-reporter-E56J3NZK.js → revenue-reporter-NRS2FANA.js} +2 -2
- package/dist/server/index.d.ts +4 -3
- package/dist/server/index.js +26 -26
- package/dist/{tempo-charge-store-WTBIX2JX.js → tempo-charge-store-NZJTJCUO.js} +2 -2
- package/dist/{tempo-session-store-AWIFUAA6.js → tempo-session-store-ENFDLDKC.js} +3 -3
- package/dist/testing/index.js +5 -5
- package/dist/{x402-BN26TQZ6.js → x402-T7WVKDD4.js} +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,7 +110,7 @@ This metadata describes the retention schedule. The SDK does not automatically d
|
|
|
110
110
|
|
|
111
111
|
Use the Node.js release in `.nvmrc` (Node 22). Install with `npm ci`, then run the same gate CI runs with `npm run verify`. The gate checks repository metadata in the checkout, copies only tracked and unignored source into an isolated directory, installs its locked dependencies, and runs lint, build, typecheck (including the release scripts under `checkJs`), unit and database tests, API, package, consumer, packed-artifact safety, and release checks there. The clean source tree owns the complete build and test pass, so verification never depends on the checkout's `node_modules` or pre-existing `dist` and does not repeat the full suite; after every check passes, its verified `dist` replaces the checkout's build output for release packaging.
|
|
112
112
|
|
|
113
|
-
`DATABASE_URL` is optional locally. Without it the database suite is skipped rather than passed, and `verify` says so in its summary, because a skipped suite verified nothing and must not be reported as green. Point `DATABASE_URL` at a scratch Postgres to run it, and pass `npm run verify -- --require-database` to make a missing one a failure, which is what CI does.
|
|
113
|
+
`DATABASE_URL` is optional locally. Without it the database suite is skipped rather than passed, and `verify` says so in its summary, because a skipped suite verified nothing and must not be reported as green. Point `DATABASE_URL` at a scratch Postgres to run it, and pass `npm run verify -- --require-database` to make a missing one a failure, which is what CI does. That mode also requires the local test mint started by `node scripts/start-cashu-mint.mjs`.
|
|
114
114
|
|
|
115
115
|
The public surface is exactly `@dvmkit/sdk`, `@dvmkit/sdk/server`, and `@dvmkit/sdk/testing`.
|
|
116
116
|
|
|
@@ -150,6 +150,10 @@ The same values are accepted as `--endpoint <url>` and `--job-token <hex>`. Thes
|
|
|
150
150
|
|
|
151
151
|
If an upgrade broke something for you, an [API compatibility report](https://github.com/dvmkit/sdk/issues/new/choose) is the most useful thing you can send us. It tells us which parts of the published surface people actually build on, which no test of ours can.
|
|
152
152
|
|
|
153
|
+
## Job identity field
|
|
154
|
+
|
|
155
|
+
Every 200 or 202 response to `POST /v1/job`, `POST /v1/request-resume/:id` and `POST /v1/request-result/:id` carries a `DVM-Job-Identity-V1` response-head field whose value is the body's `job_id`, byte for byte, so a router or caller can learn which job a response names without reading a body of any size. No other status carries it. The value grammar is `^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$`; a server whose job ID falls outside it sends no field. A reader takes the value from `Headers.get`, trims nothing and never folds case: a repeated field (joined with `", "`), an empty value or any other character is invalid, and a trailer of the same name is never identity. The portable contract and its classification vectors are in `protocol-fixtures/job-identity-v1.json`. Hosting control's status reports `jobIdentityHeader: "v1"` when the deployment emits the field.
|
|
156
|
+
|
|
153
157
|
## Per-job costs
|
|
154
158
|
|
|
155
159
|
A handler can declare what a job cost **you**, the builder, to serve — a vendor API call, a GPU minute, a per-request licence fee — and the SDK reports it to the platform alongside what the caller paid, so your dashboard can state a margin instead of guessing at one.
|
|
@@ -171,7 +175,7 @@ Three things worth knowing:
|
|
|
171
175
|
- **Declare the cost where you incur it, including inside `ctx.step`.** The step cache carries those declarations with the result and applies them once when a replay skips the body.
|
|
172
176
|
- **Every terminal job reports its declared cost.** A paid completion carries the cost on its revenue report. A free completion, failure, or cancellation sends a separate cost-only report and does not create revenue.
|
|
173
177
|
|
|
174
|
-
The cost is yours, never the caller's: it is recorded separately from what the caller paid and is never netted against it. Both report shapes use the same durable outbox. Cost-only reports are keyed on the job id and revisioned, so retries and cross-machine updates converge on the latest cumulative value. With the Postgres job store, boot-time and periodic reconciliation enqueue any terminal cost revision that a process exited before reporting.
|
|
178
|
+
The cost is yours, never the caller's: it is recorded separately from what the caller paid and is never netted against it. Both report shapes use the same durable outbox. Cost-only reports are keyed on the job id and revisioned, so retries and cross-machine updates converge on the latest cumulative value. With the Postgres job store, boot-time and periodic reconciliation enqueue any terminal cost revision that a process exited before reporting. Other job stores get no reconciliation: their cost-only report is durable only once the outbox insert commits, so an exit between the terminal save and that insert loses it.
|
|
175
179
|
|
|
176
180
|
## Rate cards
|
|
177
181
|
|
|
@@ -779,6 +779,7 @@ var diagnostic_catalogue_v1_default = {
|
|
|
779
779
|
"hardened",
|
|
780
780
|
"head_status",
|
|
781
781
|
"hint",
|
|
782
|
+
"hosting_identity_revoke_failed",
|
|
782
783
|
"ingest_concurrency",
|
|
783
784
|
"ingest_global_concurrency",
|
|
784
785
|
"ingest_ip_concurrency",
|
|
@@ -1067,6 +1068,25 @@ var diagnostic_catalogue_v1_default = {
|
|
|
1067
1068
|
"UA-14",
|
|
1068
1069
|
"UA-40",
|
|
1069
1070
|
"UA-43"
|
|
1071
|
+
],
|
|
1072
|
+
submitIdentitySources: [
|
|
1073
|
+
"header",
|
|
1074
|
+
"header_absent",
|
|
1075
|
+
"header_invalid",
|
|
1076
|
+
"not_extracted"
|
|
1077
|
+
],
|
|
1078
|
+
fundedRuntimeReclaims: [
|
|
1079
|
+
"closed"
|
|
1080
|
+
],
|
|
1081
|
+
suspensionReasons: [
|
|
1082
|
+
"request_limit",
|
|
1083
|
+
"dvm_limit",
|
|
1084
|
+
"behaviour",
|
|
1085
|
+
"free_tier_idle",
|
|
1086
|
+
"admin_org_suspend",
|
|
1087
|
+
"builder_pause",
|
|
1088
|
+
"withdrawn",
|
|
1089
|
+
"operator"
|
|
1070
1090
|
]
|
|
1071
1091
|
};
|
|
1072
1092
|
|
|
@@ -1080,6 +1100,12 @@ var PAYMENT_ENUMS = {
|
|
|
1080
1100
|
failure_stage: new Set(diagnostic_catalogue_v1_default.paymentFailureStages),
|
|
1081
1101
|
phase: new Set(diagnostic_catalogue_v1_default.paymentPhases)
|
|
1082
1102
|
};
|
|
1103
|
+
var ROUTER_ENUMS = {
|
|
1104
|
+
submit_identity_source: new Set(diagnostic_catalogue_v1_default.submitIdentitySources),
|
|
1105
|
+
funded_runtime_reclaim: new Set(diagnostic_catalogue_v1_default.fundedRuntimeReclaims),
|
|
1106
|
+
suspended_reclaim: new Set(diagnostic_catalogue_v1_default.suspensionReasons),
|
|
1107
|
+
suspended_admin: new Set(diagnostic_catalogue_v1_default.suspensionReasons)
|
|
1108
|
+
};
|
|
1083
1109
|
var EVENTS = new Set(diagnostic_catalogue_v1_default.events);
|
|
1084
1110
|
var ROUTE_TEMPLATES = [...diagnostic_catalogue_v1_default.routeTemplates].sort(
|
|
1085
1111
|
compareRouteTemplates
|
|
@@ -1280,9 +1306,9 @@ function projectFields(input, dataset, authority, identityAuthority) {
|
|
|
1280
1306
|
return output;
|
|
1281
1307
|
}
|
|
1282
1308
|
function projectField(key, value, dataset, authority, identityAuthority) {
|
|
1283
|
-
const
|
|
1284
|
-
if (
|
|
1285
|
-
return typeof value === "string" &&
|
|
1309
|
+
const closedEnum = Object.hasOwn(PAYMENT_ENUMS, key) ? PAYMENT_ENUMS[key] : Object.hasOwn(ROUTER_ENUMS, key) ? ROUTER_ENUMS[key] : void 0;
|
|
1310
|
+
if (closedEnum)
|
|
1311
|
+
return typeof value === "string" && closedEnum.has(value) ? value : void 0;
|
|
1286
1312
|
if (BOOLEAN_FIELDS.has(key))
|
|
1287
1313
|
return typeof value === "boolean" ? value : void 0;
|
|
1288
1314
|
if (INTEGER_FIELDS.has(key))
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-BPYMEMQX.js";
|
|
10
10
|
import {
|
|
11
11
|
diagnosticConsole
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-5PLQOC4B.js";
|
|
13
13
|
|
|
14
14
|
// src/lib/cashu/lock-pubkey.ts
|
|
15
15
|
function toLockPubkey(raw) {
|
|
@@ -397,10 +397,20 @@ var DEFAULT_LOCK_RETRY_INTERVAL_MS = 1e3;
|
|
|
397
397
|
var WALLET_VERSION = 9;
|
|
398
398
|
var RECENT_SPENDS_CAP = 10;
|
|
399
399
|
var DEFAULT_AGENT_MINT_URL = "https://mint.coinos.io";
|
|
400
|
+
var MAX_STORABLE_JOB_ID_LENGTH = 512;
|
|
401
|
+
function isStorableJobId(value) {
|
|
402
|
+
return typeof value === "string" && value.length > 0 && value.length <= MAX_STORABLE_JOB_ID_LENGTH && // eslint-disable-next-line no-control-regex -- control characters are what this rejects
|
|
403
|
+
!/[\u0000-\u001f\u007f-\u009f]/u.test(value);
|
|
404
|
+
}
|
|
400
405
|
function loadWalletConfiguredMints() {
|
|
401
406
|
return loadAgentWallet()?.mints ?? [];
|
|
402
407
|
}
|
|
403
408
|
function loadAgentWallet() {
|
|
409
|
+
const wallet = parseAgentWallet();
|
|
410
|
+
if (wallet) normalizeAcceptedUnresolved(wallet);
|
|
411
|
+
return wallet;
|
|
412
|
+
}
|
|
413
|
+
function parseAgentWallet() {
|
|
404
414
|
if (!existsSync4(WALLET_FILE)) return null;
|
|
405
415
|
const raw = readFileSync4(WALLET_FILE, "utf-8");
|
|
406
416
|
let parsed;
|
|
@@ -481,6 +491,7 @@ function loadAgentWallet() {
|
|
|
481
491
|
return parsed;
|
|
482
492
|
}
|
|
483
493
|
function saveAgentWallet(wallet) {
|
|
494
|
+
assertAcceptedUnresolvedStorable(wallet);
|
|
484
495
|
ensureConfigDir();
|
|
485
496
|
const tmp = `${WALLET_FILE}.tmp`;
|
|
486
497
|
const data = JSON.stringify(wallet, null, 2) + "\n";
|
|
@@ -649,6 +660,62 @@ function migrateV8ToV9(parsed) {
|
|
|
649
660
|
created_at: typeof parsed.created_at === "string" ? parsed.created_at : (/* @__PURE__ */ new Date()).toISOString()
|
|
650
661
|
};
|
|
651
662
|
}
|
|
663
|
+
var ACCEPTED_UNRESOLVED_KINDS = /* @__PURE__ */ new Set([
|
|
664
|
+
"identity_mismatch",
|
|
665
|
+
"body_unreadable",
|
|
666
|
+
"router_identity_conflict"
|
|
667
|
+
]);
|
|
668
|
+
var OBSERVED_JOB_ID_FIELDS = ["header_job_id", "body_job_id", "accepted_job_id"];
|
|
669
|
+
var PLACEHOLDER_KIND = "body_unreadable";
|
|
670
|
+
var PLACEHOLDER_OBSERVED_AT = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
671
|
+
function assertAcceptedUnresolvedStorable(wallet) {
|
|
672
|
+
const entries = wallet.pending_submissions;
|
|
673
|
+
if (!Array.isArray(entries)) return;
|
|
674
|
+
for (const entry of entries) {
|
|
675
|
+
const record = entry?.accepted_unresolved;
|
|
676
|
+
if (record === void 0 || isStorableAcceptedUnresolved(record)) continue;
|
|
677
|
+
throw new DvmError(
|
|
678
|
+
"accepted_unresolved_invalid",
|
|
679
|
+
`Refusing to save pending submission ${String(entry?.request_id)}: its accepted_unresolved record is outside the stored contract.`,
|
|
680
|
+
"Use one of the three kinds, an ISO-8601 observed_at, and job IDs and ambiguity_id that pass isStorableJobId; omit an observed ID that does not. The wallet file was not changed."
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function isStorableAcceptedUnresolved(value) {
|
|
685
|
+
if (!isPlainRecord(value)) return false;
|
|
686
|
+
return ACCEPTED_UNRESOLVED_KINDS.has(value.kind) && isIsoTimestamp(value.observed_at) && isStorableJobId(value.ambiguity_id) && OBSERVED_JOB_ID_FIELDS.every((field) => value[field] === void 0 || isStorableJobId(value[field]));
|
|
687
|
+
}
|
|
688
|
+
function normalizeAcceptedUnresolved(wallet) {
|
|
689
|
+
const entries = wallet.pending_submissions;
|
|
690
|
+
if (!Array.isArray(entries)) return;
|
|
691
|
+
for (const entry of entries) {
|
|
692
|
+
if (!entry || entry.accepted_unresolved === void 0) continue;
|
|
693
|
+
const stored = entry.accepted_unresolved;
|
|
694
|
+
if (isStorableAcceptedUnresolved(stored)) continue;
|
|
695
|
+
const record = isPlainRecord(stored) ? { ...stored } : {};
|
|
696
|
+
if (!ACCEPTED_UNRESOLVED_KINDS.has(record.kind)) record.kind = PLACEHOLDER_KIND;
|
|
697
|
+
if (!isIsoTimestamp(record.observed_at)) record.observed_at = PLACEHOLDER_OBSERVED_AT;
|
|
698
|
+
if (!isStorableJobId(record.ambiguity_id)) {
|
|
699
|
+
record.ambiguity_id = isStorableJobId(entry.request_id) ? entry.request_id : "missing-ambiguity";
|
|
700
|
+
}
|
|
701
|
+
for (const field of OBSERVED_JOB_ID_FIELDS) {
|
|
702
|
+
if (record[field] !== void 0 && !isStorableJobId(record[field])) delete record[field];
|
|
703
|
+
}
|
|
704
|
+
entry.accepted_unresolved = record;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function isPlainRecord(value) {
|
|
708
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
709
|
+
}
|
|
710
|
+
var ISO_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d{1,9})?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
|
|
711
|
+
function isIsoTimestamp(value) {
|
|
712
|
+
if (typeof value !== "string") return false;
|
|
713
|
+
const match = ISO_TIMESTAMP.exec(value);
|
|
714
|
+
if (!match) return false;
|
|
715
|
+
const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
716
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
717
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
718
|
+
}
|
|
652
719
|
function isCounterMap(value) {
|
|
653
720
|
if (typeof value !== "object" || value === null) return false;
|
|
654
721
|
for (const inner of Object.values(value)) {
|
|
@@ -1255,6 +1322,17 @@ function buildAdminAuthHeader(args) {
|
|
|
1255
1322
|
};
|
|
1256
1323
|
}
|
|
1257
1324
|
|
|
1325
|
+
// src/lib/job-identity-header.ts
|
|
1326
|
+
var JOB_IDENTITY_HEADER = "dvm-job-identity-v1";
|
|
1327
|
+
var JOB_IDENTITY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
1328
|
+
function isJobIdentityValue(value) {
|
|
1329
|
+
return typeof value === "string" && JOB_IDENTITY_PATTERN.test(value);
|
|
1330
|
+
}
|
|
1331
|
+
function parseJobIdentityHeader(value) {
|
|
1332
|
+
if (value === null) return { kind: "absent" };
|
|
1333
|
+
return isJobIdentityValue(value) ? { kind: "valid", jobId: value } : { kind: "invalid" };
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1258
1336
|
// src/lib/builder-identity.ts
|
|
1259
1337
|
import {
|
|
1260
1338
|
chmodSync as chmodSync4,
|
|
@@ -1808,6 +1886,7 @@ export {
|
|
|
1808
1886
|
WALLET_VERSION,
|
|
1809
1887
|
RECENT_SPENDS_CAP,
|
|
1810
1888
|
DEFAULT_AGENT_MINT_URL,
|
|
1889
|
+
isStorableJobId,
|
|
1811
1890
|
loadWalletConfiguredMints,
|
|
1812
1891
|
loadAgentWallet,
|
|
1813
1892
|
saveAgentWallet,
|
|
@@ -1835,6 +1914,9 @@ export {
|
|
|
1835
1914
|
ADMIN_STATE_UNAVAILABLE,
|
|
1836
1915
|
buildAdminChallenge,
|
|
1837
1916
|
buildAdminAuthHeader,
|
|
1917
|
+
JOB_IDENTITY_HEADER,
|
|
1918
|
+
isJobIdentityValue,
|
|
1919
|
+
parseJobIdentityHeader,
|
|
1838
1920
|
generateIdentity,
|
|
1839
1921
|
loadIdentitySecret,
|
|
1840
1922
|
writeIdentity,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-AFV77S4C.js";
|
|
5
5
|
import {
|
|
6
6
|
diagnosticConsole
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5PLQOC4B.js";
|
|
8
8
|
import {
|
|
9
9
|
withSdkInitLock
|
|
10
10
|
} from "./chunk-COYKJRMM.js";
|
|
@@ -286,10 +286,20 @@ var PostgresJobStore = class {
|
|
|
286
286
|
CREATE INDEX IF NOT EXISTS idx_jobs_retention
|
|
287
287
|
ON jobs (last_activity_at, id)
|
|
288
288
|
WHERE redacted_at IS NULL AND status IN ('completed', 'failed', 'cancelled');
|
|
289
|
-
|
|
289
|
+
-- Terminal cost recovery runs at boot and every 30s on each machine.
|
|
290
|
+
-- Indexing only rows whose latest revision is not yet enqueued keeps each
|
|
291
|
+
-- pass proportional to that backlog; marking a row drops it from the
|
|
292
|
+
-- index. listUnreportedTerminalCosts' WHERE clause must imply this
|
|
293
|
+
-- predicate or the planner falls back to scanning terminal history.
|
|
294
|
+
DROP INDEX IF EXISTS idx_jobs_pending_cost_report;
|
|
295
|
+
CREATE INDEX IF NOT EXISTS idx_jobs_unreported_terminal_cost
|
|
290
296
|
ON jobs (dvm_id, id)
|
|
291
297
|
WHERE cost_revision IS NOT NULL
|
|
292
|
-
AND
|
|
298
|
+
AND (cost_reported_revision IS NULL OR cost_reported_revision < cost_revision)
|
|
299
|
+
AND (
|
|
300
|
+
status IN ('failed', 'cancelled')
|
|
301
|
+
OR (status = 'completed' AND paid_msats = 0)
|
|
302
|
+
);
|
|
293
303
|
-- the idempotent-replay lookup. payment_tx_hash carries the
|
|
294
304
|
-- caller's X-Cashu-Request-Id on the accumulator path, so a retried paid
|
|
295
305
|
-- submit finds the job its payment already created.
|
|
@@ -689,7 +699,8 @@ var PostgresJobStore = class {
|
|
|
689
699
|
}
|
|
690
700
|
/**
|
|
691
701
|
* Read terminal zero-revenue jobs whose latest declared-cost revision has
|
|
692
|
-
* not yet reached the durable reporter outbox.
|
|
702
|
+
* not yet reached the durable reporter outbox. Keep the filter in step with
|
|
703
|
+
* `idx_jobs_unreported_terminal_cost`, which bounds each pass to the backlog.
|
|
693
704
|
*/
|
|
694
705
|
async listUnreportedTerminalCosts(args) {
|
|
695
706
|
const { rows } = await this.pool.query(
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
installHostedTempoCloseGuard,
|
|
8
8
|
isTempoInsufficientFundsError,
|
|
9
9
|
resolveTempoNetwork
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QN3CQOE2.js";
|
|
11
11
|
import {
|
|
12
12
|
x402EarnedCeiling
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-YNHXOONR.js";
|
|
14
14
|
import {
|
|
15
15
|
createX402FacilitatorAuthHeaders,
|
|
16
16
|
createX402FacilitatorClient,
|
|
@@ -19,13 +19,13 @@ import {
|
|
|
19
19
|
verifyWithFacilitator,
|
|
20
20
|
withPaymentDiagnostics,
|
|
21
21
|
withPaymentStage
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-FYETJDBB.js";
|
|
23
23
|
import {
|
|
24
24
|
MemoryCreditLedger
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-YE53E4BT.js";
|
|
26
26
|
import {
|
|
27
27
|
PostgresJobStore
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-6JZDFYQL.js";
|
|
29
29
|
import {
|
|
30
30
|
parseStoreValue
|
|
31
31
|
} from "./chunk-YG7G4DPZ.js";
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
humanizeZodIssues,
|
|
37
37
|
signedRequestInput,
|
|
38
38
|
zodIssuesOf
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-YS6PWVCZ.js";
|
|
40
40
|
import {
|
|
41
41
|
MemoryJobStore,
|
|
42
42
|
UNCAPPABLE_ASK_TOTAL,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
isJobRetentionStore,
|
|
46
46
|
isReceiptIssuingStore,
|
|
47
47
|
isStreamableJobStore
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-2HAFZ5GC.js";
|
|
49
49
|
import {
|
|
50
50
|
ContentHoldError,
|
|
51
51
|
JobCancelledError,
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
ADMIN_AUTH_NONCE_TTL_SECONDS,
|
|
66
66
|
ADMIN_STATE_UNAVAILABLE,
|
|
67
67
|
IMPLICIT_CREDIT_TTL_MS,
|
|
68
|
+
JOB_IDENTITY_HEADER,
|
|
68
69
|
TEMPO_SESSION_UPDATED_REASON,
|
|
69
70
|
X402_BATCH_CHANNEL_ABI,
|
|
70
71
|
attestedDvmIdentity,
|
|
@@ -74,6 +75,7 @@ import {
|
|
|
74
75
|
createMonotonicClock,
|
|
75
76
|
formatStaleness,
|
|
76
77
|
getWallet,
|
|
78
|
+
isJobIdentityValue,
|
|
77
79
|
isPublicRequestId,
|
|
78
80
|
isX402SettlementReconciliationReason,
|
|
79
81
|
parseTraceparent,
|
|
@@ -83,7 +85,7 @@ import {
|
|
|
83
85
|
signReceipt,
|
|
84
86
|
toLockPubkey,
|
|
85
87
|
verifyChallenge
|
|
86
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-5TIFEMHJ.js";
|
|
87
89
|
import {
|
|
88
90
|
X402_BATCH_SETTLEMENT_SCHEME,
|
|
89
91
|
X402_DEFAULT_FACILITATOR,
|
|
@@ -115,7 +117,7 @@ import {
|
|
|
115
117
|
pinDimension,
|
|
116
118
|
withSpan,
|
|
117
119
|
withTraceContext
|
|
118
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-RGSWVNQG.js";
|
|
119
121
|
import {
|
|
120
122
|
StepCache
|
|
121
123
|
} from "./chunk-BQJIFRAZ.js";
|
|
@@ -132,7 +134,7 @@ import {
|
|
|
132
134
|
roundUsd,
|
|
133
135
|
satsToFiat,
|
|
134
136
|
validateCurrency
|
|
135
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-5CSR33B5.js";
|
|
136
138
|
import {
|
|
137
139
|
CreditLedger,
|
|
138
140
|
CreditLedgerError,
|
|
@@ -148,10 +150,10 @@ import {
|
|
|
148
150
|
isNonChannelBitcoinRail,
|
|
149
151
|
netOwedSats,
|
|
150
152
|
x402SettlementPending
|
|
151
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-IOKEKMIU.js";
|
|
152
154
|
import {
|
|
153
155
|
withPostgresRecoveryContext
|
|
154
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-QM2OS3NJ.js";
|
|
155
157
|
import {
|
|
156
158
|
DvmError,
|
|
157
159
|
x402NetworkByCaip2
|
|
@@ -159,7 +161,7 @@ import {
|
|
|
159
161
|
import {
|
|
160
162
|
createDiagnosticCapabilityAuthority,
|
|
161
163
|
diagnosticConsole
|
|
162
|
-
} from "./chunk-
|
|
164
|
+
} from "./chunk-5PLQOC4B.js";
|
|
163
165
|
import {
|
|
164
166
|
MemoryProcessedPaymentStore,
|
|
165
167
|
PostgresProcessedPaymentStore,
|
|
@@ -3875,7 +3877,7 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
3875
3877
|
x402Requirements
|
|
3876
3878
|
});
|
|
3877
3879
|
}
|
|
3878
|
-
const { verifyX402Payment } = await import("./x402-
|
|
3880
|
+
const { verifyX402Payment } = await import("./x402-T7WVKDD4.js");
|
|
3879
3881
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
3880
3882
|
x402Payment,
|
|
3881
3883
|
x402Config,
|
|
@@ -4863,7 +4865,7 @@ async function verifyIncomingPaymentInScope(body, opts, snapshot) {
|
|
|
4863
4865
|
snapshot
|
|
4864
4866
|
});
|
|
4865
4867
|
}
|
|
4866
|
-
const { verifyX402Payment } = await import("./x402-
|
|
4868
|
+
const { verifyX402Payment } = await import("./x402-T7WVKDD4.js");
|
|
4867
4869
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
4868
4870
|
body.content.x402_payment,
|
|
4869
4871
|
opts.x402Config,
|
|
@@ -5294,7 +5296,7 @@ async function processIncomingPaymentInScope(job, body, opts) {
|
|
|
5294
5296
|
try {
|
|
5295
5297
|
const requiredMsats = job.pendingPaymentMsats ?? 0;
|
|
5296
5298
|
const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
|
|
5297
|
-
const { verifyX402Payment } = await import("./x402-
|
|
5299
|
+
const { verifyX402Payment } = await import("./x402-T7WVKDD4.js");
|
|
5298
5300
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
5299
5301
|
body.content.x402_payment,
|
|
5300
5302
|
opts.x402Config,
|
|
@@ -11769,7 +11771,8 @@ var HostingControl = class {
|
|
|
11769
11771
|
pendingAdmissionCount: Number(pending.rows[0].pending),
|
|
11770
11772
|
pendingAdmissions: inFlight.rows.map((row) => ({ admissionId: row.id, workId: row.job_id })),
|
|
11771
11773
|
unresolvedAdmissionCount: Number(pending.rows[0].unresolved),
|
|
11772
|
-
unresolvedAdmissions: unresolved.rows.map((row) => ({ admissionId: row.id, jobId: row.job_id }))
|
|
11774
|
+
unresolvedAdmissions: unresolved.rows.map((row) => ({ admissionId: row.id, jobId: row.job_id })),
|
|
11775
|
+
jobIdentityHeader: "v1"
|
|
11773
11776
|
};
|
|
11774
11777
|
}
|
|
11775
11778
|
};
|
|
@@ -19534,7 +19537,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19534
19537
|
}
|
|
19535
19538
|
}
|
|
19536
19539
|
if (!opts.onJobCompleted && platformToken && platformUrl && dvmId && opts.db) {
|
|
19537
|
-
const { RevenueReporter } = await import("./revenue-reporter-
|
|
19540
|
+
const { RevenueReporter } = await import("./revenue-reporter-NRS2FANA.js");
|
|
19538
19541
|
const reporter = new RevenueReporter(
|
|
19539
19542
|
opts.db,
|
|
19540
19543
|
platformUrl,
|
|
@@ -19544,7 +19547,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19544
19547
|
revenueReporter = reporter;
|
|
19545
19548
|
await reporter.init();
|
|
19546
19549
|
reporter.startRetryLoop();
|
|
19547
|
-
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-
|
|
19550
|
+
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-W3CCLYCN.js");
|
|
19548
19551
|
payoutReporter = new PayoutReporter({
|
|
19549
19552
|
dvmId,
|
|
19550
19553
|
db: opts.db,
|
|
@@ -22495,7 +22498,7 @@ function buildSubmitResponse(c, job, jobToken, contentFields) {
|
|
|
22495
22498
|
else if (job.status === "completed") res.status = "completed";
|
|
22496
22499
|
Object.assign(res, terminalResponseFields(job), contentFields);
|
|
22497
22500
|
removeUnavailableContent(res);
|
|
22498
|
-
return c.json(res, job.status === "completed" ? 200 : 202);
|
|
22501
|
+
return c.json(res, job.status === "completed" ? 200 : 202, jobIdentityHeaders(job.id));
|
|
22499
22502
|
}
|
|
22500
22503
|
function requestRecoveryStore(store) {
|
|
22501
22504
|
return store.findJobByRequestId && store.claimRequestId && store.resumeRequestId && store.releaseRequestIdClaim ? store : void 0;
|
|
@@ -22561,7 +22564,10 @@ function buildRequestResultResponse(c, requestId, job, contentFields) {
|
|
|
22561
22564
|
if (job.paymentTransactionHash) res.transaction_hash = job.paymentTransactionHash;
|
|
22562
22565
|
Object.assign(res, terminalResponseFields(job), contentFields);
|
|
22563
22566
|
removeUnavailableContent(res);
|
|
22564
|
-
return c.json(res, isTerminal(job.status) ? 200 : 202);
|
|
22567
|
+
return c.json(res, isTerminal(job.status) ? 200 : 202, jobIdentityHeaders(job.id));
|
|
22568
|
+
}
|
|
22569
|
+
function jobIdentityHeaders(jobId) {
|
|
22570
|
+
return isJobIdentityValue(jobId) ? { [JOB_IDENTITY_HEADER]: jobId } : {};
|
|
22565
22571
|
}
|
|
22566
22572
|
function requestResultNotFound(c, requestId) {
|
|
22567
22573
|
return c.json(
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyRetryToPool
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QM2OS3NJ.js";
|
|
4
4
|
import {
|
|
5
5
|
x402NetworkByCaip2
|
|
6
6
|
} from "./chunk-BPYMEMQX.js";
|
|
7
7
|
import {
|
|
8
8
|
diagnosticConsole
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-5PLQOC4B.js";
|
|
10
10
|
import {
|
|
11
11
|
withSdkInitLock
|
|
12
12
|
} from "./chunk-COYKJRMM.js";
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
createX402FacilitatorAuthHeaders,
|
|
3
3
|
settleWithFacilitator,
|
|
4
4
|
verifyWithFacilitator
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FYETJDBB.js";
|
|
6
6
|
import {
|
|
7
7
|
buildPaymentRequirements,
|
|
8
8
|
decodePayment,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-KXWROQGK.js";
|
|
16
16
|
import {
|
|
17
17
|
diagnosticConsole
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-5PLQOC4B.js";
|
|
19
19
|
|
|
20
20
|
// src/lib/x402/verify.ts
|
|
21
21
|
async function verifyX402Payment(paymentHeader, config, requiredUsdcMicro, resource, btcUsdRate, exactVersions = { v1: true, v2: true }) {
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
isDrainMethod,
|
|
11
11
|
isFundingRail,
|
|
12
12
|
x402SettlementPending
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-IOKEKMIU.js";
|
|
14
|
+
import "./chunk-QM2OS3NJ.js";
|
|
15
15
|
import "./chunk-BPYMEMQX.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-5PLQOC4B.js";
|
|
17
17
|
import "./chunk-COYKJRMM.js";
|
|
18
18
|
export {
|
|
19
19
|
CreditLedger,
|