@dvmkit/sdk 0.5.0-rc.1 → 0.7.0-rc.1

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 (54) hide show
  1. package/README.md +100 -0
  2. package/dist/{chunk-JH3SX3LY.js → chunk-6XF3RVVX.js} +1 -1
  3. package/dist/chunk-AFV77S4C.js +258 -0
  4. package/dist/{chunk-RLTSCKRI.js → chunk-BPYMEMQX.js} +50 -3
  5. package/dist/chunk-BQJIFRAZ.js +36 -0
  6. package/dist/{chunk-IWQHUSMO.js → chunk-CXCQLOOK.js} +143 -2
  7. package/dist/{chunk-PB4FYZET.js → chunk-EQLA4FFY.js} +54 -4
  8. package/dist/{chunk-LE74UEV7.js → chunk-EZXAJ6EI.js} +64 -53
  9. package/dist/{chunk-FI4CST2D.js → chunk-FWGWLPXF.js} +4 -6
  10. package/dist/{chunk-EYTHFFFU.js → chunk-GY66THYI.js} +179 -56
  11. package/dist/{chunk-TZ2WKCDD.js → chunk-HCLVYZUZ.js} +2 -2
  12. package/dist/{chunk-O5AT6S5T.js → chunk-IV6Q7NRW.js} +25 -195
  13. package/dist/{chunk-UOCZXO2Z.js → chunk-JEVLNAO3.js} +10 -5
  14. package/dist/{chunk-TUA7PYH7.js → chunk-KMED3H3A.js} +134 -130
  15. package/dist/{chunk-Z4KLECAC.js → chunk-N5RZ5HVB.js} +1 -1
  16. package/dist/{chunk-PAIM66YA.js → chunk-NFMOPYBA.js} +47 -37
  17. package/dist/{chunk-B2IROPQF.js → chunk-O2OTZ5GP.js} +40 -15
  18. package/dist/{chunk-FYRR2UEZ.js → chunk-OML32F6I.js} +1 -1
  19. package/dist/{chunk-6DOGTAHA.js → chunk-QR2EF2NI.js} +9 -43
  20. package/dist/{chunk-7ZUKL4IV.js → chunk-RA2WIX7G.js} +5 -5
  21. package/dist/{chunk-A4YFWZ7R.js → chunk-RCM3P2HE.js} +1 -1
  22. package/dist/{chunk-PLG4XER6.js → chunk-S3OY533W.js} +1 -1
  23. package/dist/{chunk-GFY5FRX3.js → chunk-SZVXOQ75.js} +5 -12
  24. package/dist/{chunk-MZRJR2CW.js → chunk-WBOKPC37.js} +22 -3
  25. package/dist/content-retention-DHyLdA6b.d.ts +78 -0
  26. package/dist/{credit-ledger-MI2H7NEC.js → credit-ledger-MCUXYKSJ.js} +2 -3
  27. package/dist/{credit-menu-CAfqe8IY.d.ts → credit-menu-DjnkeEUU.d.ts} +98 -5
  28. package/dist/{fx-D9nsN3n4.d.ts → fx-zMWFzfrU.d.ts} +1 -1
  29. package/dist/index.d.ts +5 -5
  30. package/dist/index.js +3 -3
  31. package/dist/internal/caller.d.ts +1369 -860
  32. package/dist/internal/caller.js +1079 -991
  33. package/dist/internal/index.js +1 -1
  34. package/dist/internal/server.d.ts +8 -99
  35. package/dist/internal/server.js +19 -18
  36. package/dist/{job-store-Bx-VFRjg.d.ts → job-store-DdLXBpol.d.ts} +1 -1
  37. package/dist/{lightning-backend-BAx2Y8pP.d.ts → lightning-backend-Bw-qtAbt.d.ts} +4 -2
  38. package/dist/{memory-credit-ledger-W2BAUYJP.js → memory-credit-ledger-SBSMGMDX.js} +3 -4
  39. package/dist/{postgres-consumed-credential-store-CUQJKRSL.js → postgres-consumed-credential-store-BUVCAPLS.js} +13 -0
  40. package/dist/{postgres-job-store-VLXLWXUQ.js → postgres-job-store-VHLQBJZC.js} +3 -1
  41. package/dist/server/index.d.ts +28 -10
  42. package/dist/server/index.js +34 -24
  43. package/dist/{step-cache-QG_h5-3G.d.ts → step-cache-2MkvenJn.d.ts} +3 -3
  44. package/dist/tempo-lifecycle-GJ77YKVY.js +15 -0
  45. package/dist/{tempo-wallet-B5XXV3YH.js → tempo-wallet-X2GGAZ6X.js} +4 -4
  46. package/dist/testing/index.d.ts +9 -2
  47. package/dist/testing/index.js +6 -3
  48. package/dist/{usd-EwRqCPF-.d.ts → usd-DI3d3gTK.d.ts} +1 -1
  49. package/dist/{x402-R6HPBY5D.js → x402-FT4S4JS4.js} +8 -10
  50. package/package.json +5 -3
  51. package/recipes/postgres/financial-export-v1.sql +137 -0
  52. package/dist/chunk-CZULM42S.js +0 -143
  53. package/dist/chunk-LIRAHP7B.js +0 -53
  54. package/dist/tempo-lifecycle-ZBBLFBMH.js +0 -15
@@ -8,13 +8,13 @@ import {
8
8
  createX402FacilitatorClient,
9
9
  settleWithFacilitator,
10
10
  verifyWithFacilitator
11
- } from "./chunk-PLG4XER6.js";
11
+ } from "./chunk-S3OY533W.js";
12
12
  import {
13
13
  MemoryCreditLedger
14
- } from "./chunk-FYRR2UEZ.js";
14
+ } from "./chunk-OML32F6I.js";
15
15
  import {
16
16
  PostgresJobStore
17
- } from "./chunk-PB4FYZET.js";
17
+ } from "./chunk-EQLA4FFY.js";
18
18
  import {
19
19
  parseStoreValue
20
20
  } from "./chunk-YG7G4DPZ.js";
@@ -25,24 +25,30 @@ import {
25
25
  humanizeZodIssues,
26
26
  signedRequestInput,
27
27
  zodIssuesOf
28
- } from "./chunk-Z4KLECAC.js";
28
+ } from "./chunk-N5RZ5HVB.js";
29
29
  import {
30
- JobCancelledError,
31
30
  MemoryJobStore,
32
31
  UNCAPPABLE_ASK_TOTAL,
33
- abortJob,
34
32
  accumulateAskedTopUp,
35
33
  createInstrumentedFetch,
36
- fromJobRecord,
37
34
  isJobRetentionStore,
38
35
  isReceiptIssuingStore,
39
- isStreamableJobStore,
36
+ isStreamableJobStore
37
+ } from "./chunk-IV6Q7NRW.js";
38
+ import {
39
+ ContentHoldError,
40
+ JobCancelledError,
41
+ abortJob,
42
+ baselineContentExpiry,
43
+ contentMetadata,
44
+ fromJobRecord,
45
+ isContentHoldStore,
40
46
  isTerminal,
41
47
  isYieldMessage,
42
48
  localMessage,
43
49
  providerMessage,
44
50
  toJobRecord
45
- } from "./chunk-O5AT6S5T.js";
51
+ } from "./chunk-AFV77S4C.js";
46
52
  import {
47
53
  ADMIN_AUTH_CLOCK_SKEW_SECONDS,
48
54
  ADMIN_AUTH_NONCE_TTL_SECONDS,
@@ -63,7 +69,18 @@ import {
63
69
  toLockPubkey,
64
70
  verifyCashuToken,
65
71
  verifyChallenge
66
- } from "./chunk-TUA7PYH7.js";
72
+ } from "./chunk-KMED3H3A.js";
73
+ import {
74
+ IMPLICIT_CREDIT_TTL_MS,
75
+ computeResultHash,
76
+ formatStaleness,
77
+ msatsToUsd,
78
+ msatsToUsdc,
79
+ signDrainReceipt,
80
+ signFundingReceipt,
81
+ signReceipt,
82
+ usdcToMsats
83
+ } from "./chunk-NFMOPYBA.js";
67
84
  import {
68
85
  X402_BATCH_SETTLEMENT_SCHEME,
69
86
  X402_DEFAULT_FACILITATOR,
@@ -77,38 +94,27 @@ import {
77
94
  encodeSettleResponseHeader,
78
95
  exactEvmAuthorization,
79
96
  paymentRequiredV2FromV1,
97
+ resolveRpcOverride,
80
98
  x402NetworkToCaip2
81
- } from "./chunk-IWQHUSMO.js";
82
- import {
83
- IMPLICIT_CREDIT_TTL_MS,
84
- computeResultHash,
85
- formatStaleness,
86
- msatsToUsd,
87
- msatsToUsdc,
88
- signDrainReceipt,
89
- signFundingReceipt,
90
- signReceipt,
91
- usdcToMsats
92
- } from "./chunk-PAIM66YA.js";
93
- import {
94
- resolveRpcOverride
95
- } from "./chunk-CZULM42S.js";
99
+ } from "./chunk-CXCQLOOK.js";
96
100
  import {
97
101
  RAIL_REFUNDABLE,
98
102
  canonicalRequestPath,
99
103
  isZodSchema
100
- } from "./chunk-A4YFWZ7R.js";
104
+ } from "./chunk-RCM3P2HE.js";
101
105
  import {
102
106
  canonicalize
103
107
  } from "./chunk-OFVV37XC.js";
104
108
  import {
105
- StepCache,
106
109
  createConsoleLogger,
107
110
  loggers,
108
111
  pinDimension,
109
112
  withSpan,
110
113
  withTraceContext
111
- } from "./chunk-6DOGTAHA.js";
114
+ } from "./chunk-QR2EF2NI.js";
115
+ import {
116
+ StepCache
117
+ } from "./chunk-BQJIFRAZ.js";
112
118
  import {
113
119
  FxRateUnavailableError,
114
120
  InvalidCurrencyError,
@@ -139,7 +145,7 @@ import {
139
145
  isNonChannelBitcoinRail,
140
146
  netOwedSats,
141
147
  x402SettlementPending
142
- } from "./chunk-JH3SX3LY.js";
148
+ } from "./chunk-6XF3RVVX.js";
143
149
  import {
144
150
  withSdkInitLock
145
151
  } from "./chunk-COYKJRMM.js";
@@ -148,7 +154,7 @@ import {
148
154
  } from "./chunk-P6QON7ER.js";
149
155
  import {
150
156
  x402NetworkByCaip2
151
- } from "./chunk-RLTSCKRI.js";
157
+ } from "./chunk-BPYMEMQX.js";
152
158
  import {
153
159
  TEMPO_MODERATO_CHAIN_ID,
154
160
  TEMPO_MODERATO_RPC,
@@ -768,6 +774,15 @@ var MemoryConsumedCredentialStore = class {
768
774
  }
769
775
  return Promise.resolve(true);
770
776
  }
777
+ consume(realm, challengeId, ttlSeconds) {
778
+ const key = `${realm}:${challengeId}`;
779
+ const now = Date.now();
780
+ if ((this.data.get(key) ?? 0) > now) return Promise.resolve(false);
781
+ for (const [entry, expiry] of this.data) if (expiry <= now) this.data.delete(entry);
782
+ if (this.data.size >= this.maxEntries) return Promise.reject(new Error("Nonce store capacity exhausted"));
783
+ this.data.set(key, now + ttlSeconds * 1e3);
784
+ return Promise.resolve(true);
785
+ }
771
786
  mark(realm, challengeId, ttlSeconds) {
772
787
  const key = `${realm}:${challengeId}`;
773
788
  if (this.data.has(key)) this.data.delete(key);
@@ -3779,7 +3794,7 @@ async function verifyUpfrontPayment(opts) {
3779
3794
  x402Requirements
3780
3795
  });
3781
3796
  }
3782
- const { verifyX402Payment } = await import("./x402-R6HPBY5D.js");
3797
+ const { verifyX402Payment } = await import("./x402-FT4S4JS4.js");
3783
3798
  const receipt = await verifyX402Payment(
3784
3799
  x402Payment,
3785
3800
  x402Config,
@@ -4754,7 +4769,7 @@ async function verifyIncomingPayment(body, opts, snapshot) {
4754
4769
  snapshot
4755
4770
  });
4756
4771
  }
4757
- const { verifyX402Payment } = await import("./x402-R6HPBY5D.js");
4772
+ const { verifyX402Payment } = await import("./x402-FT4S4JS4.js");
4758
4773
  const receipt = await verifyX402Payment(
4759
4774
  body.content.x402_payment,
4760
4775
  opts.x402Config,
@@ -5179,7 +5194,7 @@ async function processIncomingPayment(job, body, opts) {
5179
5194
  try {
5180
5195
  const requiredMsats = job.pendingPaymentMsats ?? 0;
5181
5196
  const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
5182
- const { verifyX402Payment } = await import("./x402-R6HPBY5D.js");
5197
+ const { verifyX402Payment } = await import("./x402-FT4S4JS4.js");
5183
5198
  const receipt = await verifyX402Payment(
5184
5199
  body.content.x402_payment,
5185
5200
  opts.x402Config,
@@ -8707,10 +8722,14 @@ async function verifyAdminAuth(opts) {
8707
8722
  nonceHex,
8708
8723
  unixSeconds: unixStr
8709
8724
  });
8710
- const matched = opts.acceptedPubkeys.some((pk) => verifyChallenge(pk, digest, sigHex));
8725
+ const matched = opts.acceptedPubkeys.find((pk) => verifyChallenge(pk, digest, sigHex));
8711
8726
  if (!matched) return { ok: false, reason: "bad_signature" };
8712
- await opts.nonceStore.mark(NONCE_REALM, nonceHex, NONCE_TTL_SECONDS);
8713
- return { ok: true };
8727
+ if (opts.nonceStore.consume) {
8728
+ if (!await opts.nonceStore.consume(NONCE_REALM, nonceHex, NONCE_TTL_SECONDS)) return { ok: false, reason: "replay" };
8729
+ } else {
8730
+ await opts.nonceStore.mark(NONCE_REALM, nonceHex, NONCE_TTL_SECONDS);
8731
+ }
8732
+ return { ok: true, actor: matched };
8714
8733
  }
8715
8734
  function installAdminCashuRoutes(app, opts) {
8716
8735
  app.get("/admin/cashu/pending-batches", (c) => handlePendingBatches(c, opts));
@@ -8975,6 +8994,69 @@ async function handleRotateLockPubkey(c, opts) {
8975
8994
  });
8976
8995
  }
8977
8996
 
8997
+ // src/sdk/server/admin-content.ts
8998
+ function installAdminContentRoutes(app, opts) {
8999
+ app.get("/admin/jobs/:jobId/content-holds", (c) => handle(c, opts));
9000
+ app.post("/admin/jobs/:jobId/content-holds", (c) => handle(c, opts, "placed"));
9001
+ app.post("/admin/jobs/:jobId/content-holds/:holdId/renew", (c) => handle(c, opts, "renewed"));
9002
+ app.post("/admin/jobs/:jobId/content-holds/:holdId/clear", (c) => handle(c, opts, "cleared"));
9003
+ }
9004
+ async function handle(c, opts, action) {
9005
+ const loaded = await loadAdminLockPubkeyState(c, opts);
9006
+ if ("response" in loaded) return loaded.response;
9007
+ const auth = await verifyAdminAuth({
9008
+ authHeader: c.req.header("Authorization"),
9009
+ method: c.req.method,
9010
+ path: c.req.path,
9011
+ dvmId: opts.dvmId,
9012
+ acceptedPubkeys: [loaded.state.current, ...loaded.state.retired.map((item) => item.pubkey)],
9013
+ nonceStore: opts.nonceStore,
9014
+ now: opts.now
9015
+ });
9016
+ if (!auth.ok) return c.json({ error: "unauthorized", reason: auth.reason }, 401);
9017
+ if (!isContentHoldStore(opts.store) || !opts.nonceStore.consume) {
9018
+ return c.json({ error: "content_holds_unavailable", message: "This service requires a content-hold store and atomic admin nonce store." }, 503);
9019
+ }
9020
+ const jobId = c.req.param("jobId") ?? "";
9021
+ const at = opts.now?.() ?? Date.now();
9022
+ try {
9023
+ if (action) {
9024
+ let body;
9025
+ try {
9026
+ body = await c.req.json();
9027
+ } catch {
9028
+ return c.json({ error: "invalid_body", message: "Send a JSON object." }, 400);
9029
+ }
9030
+ if (!body || typeof body !== "object" || Array.isArray(body)) return c.json({ error: "invalid_body" }, 400);
9031
+ const allowed = action === "placed" ? ["purpose", "reason", "review_due_at"] : action === "renewed" ? ["reason", "review_due_at"] : ["reason"];
9032
+ if (Object.keys(body).some((key) => !allowed.includes(key))) return c.json({ error: "invalid_body", message: "Only purpose, reason and review_due_at are accepted as applicable; identity and times are server-derived." }, 400);
9033
+ if (typeof body.reason !== "string" || body.reason.trim().length === 0 || body.reason.length > 1e3) return c.json({ error: "invalid_reason", message: "reason must contain 1..1000 characters." }, 400);
9034
+ if (action !== "cleared" && (!Number.isSafeInteger(body.review_due_at) || body.review_due_at <= at)) return c.json({ error: "invalid_review_due_at", message: "review_due_at must be a future epoch millisecond integer." }, 400);
9035
+ const base2 = { reason: body.reason.trim(), actor: auth.actor, at };
9036
+ let mutation;
9037
+ if (action === "placed") {
9038
+ if (body.purpose !== "support" && body.purpose !== "dispute") return c.json({ error: "invalid_purpose" }, 400);
9039
+ mutation = { ...base2, action, purpose: body.purpose, review_due_at: body.review_due_at };
9040
+ } else if (action === "renewed") {
9041
+ mutation = { ...base2, action, hold_id: c.req.param("holdId") ?? "", review_due_at: body.review_due_at };
9042
+ } else mutation = { ...base2, action, hold_id: c.req.param("holdId") ?? "" };
9043
+ await opts.store.mutateContentHold(jobId, mutation, opts.dvmId);
9044
+ }
9045
+ const snapshot = await opts.store.getContentSnapshot(jobId, opts.dvmId);
9046
+ if (!snapshot) return c.json({ error: "job_not_found" }, 404);
9047
+ return c.json({
9048
+ job_id: jobId,
9049
+ ...contentMetadata(snapshot.job, opts.retentionDays, snapshot.history.holds),
9050
+ baseline_content_expires_at: baselineContentExpiry(snapshot.job, opts.retentionDays),
9051
+ holds: snapshot.history.holds.map((hold) => ({ ...hold, review_overdue: hold.cleared_at === null && hold.review_due_at <= at })),
9052
+ events: snapshot.history.events
9053
+ }, action === "placed" ? 201 : 200);
9054
+ } catch (error) {
9055
+ if (error instanceof ContentHoldError) return c.json({ error: error.code }, error.code === "job_not_found" ? 404 : 409);
9056
+ throw error;
9057
+ }
9058
+ }
9059
+
8978
9060
  // src/sdk/server/x402-exact-settlement.ts
8979
9061
  import { createHash as createHash4 } from "crypto";
8980
9062
  var X402ExactSettlementServer = class {
@@ -19944,6 +20026,13 @@ var DVMServer = class {
19944
20026
  ...payoutReporter ? { onMelted: payoutReporter.meltHook() } : {}
19945
20027
  });
19946
20028
  }
20029
+ installAdminContentRoutes(this.app, {
20030
+ dvmId,
20031
+ store: this.jobManager.store,
20032
+ retentionDays: this.descriptor.jobRetentionDays,
20033
+ getLockPubkeyState: () => this.loadActiveLockPubkeyState(db, dvmId),
20034
+ nonceStore: this.adminCashuNonceStore
20035
+ });
19947
20036
  installAdminCreditRoutes(this.app, {
19948
20037
  db,
19949
20038
  dvmId,
@@ -20250,12 +20339,12 @@ var DVMServer = class {
20250
20339
  ownerDisplayBlock() {
20251
20340
  const owner = this.opts.owner;
20252
20341
  const env = this.opts.env;
20253
- const handle = owner?.handle ?? env.DVMKIT_OWNER_HANDLE;
20254
- if (!handle) return null;
20342
+ const handle2 = owner?.handle ?? env.DVMKIT_OWNER_HANDLE;
20343
+ if (!handle2) return null;
20255
20344
  const type = owner?.type ?? env.DVMKIT_OWNER_TYPE ?? "builder";
20256
20345
  const displayName = owner?.displayName ?? env.DVMKIT_OWNER_DISPLAY_NAME ?? null;
20257
20346
  const avatarUrl = owner?.avatarUrl ?? env.DVMKIT_OWNER_AVATAR_URL ?? null;
20258
- return { handle, display_name: displayName, avatar_url: avatarUrl, type };
20347
+ return { handle: handle2, display_name: displayName, avatar_url: avatarUrl, type };
20259
20348
  }
20260
20349
  defaultPaymentMethods() {
20261
20350
  const methods = [];
@@ -21140,7 +21229,7 @@ var DVMServer = class {
21140
21229
  if (prior?.requestId !== requestId || prior.requesterPubkey !== authPubkey || prior.requestFingerprint !== fingerprint || prior.requesterId !== c.get("requesterId")) {
21141
21230
  return requestResultNotFound(c, requestId);
21142
21231
  }
21143
- return buildRequestResultResponse(c, requestId, prior);
21232
+ return buildRequestResultResponse(c, requestId, prior, await this.contentFields(prior));
21144
21233
  }
21145
21234
  async handleCreateJob(c, resumeOnly = false) {
21146
21235
  if (!resumeOnly) this.maybeSweepTempoSessions();
@@ -21270,7 +21359,7 @@ var DVMServer = class {
21270
21359
  const prior = priorId ? await this.jobManager.store.get(priorId) : void 0;
21271
21360
  if (prior && prior.requestFingerprint === fingerprint && prior.requesterId === c.get("requesterId") && (!this.descriptor.auth || prior.requesterPubkey === authPubkey)) {
21272
21361
  await this.jobManager.ensureReceipt(prior);
21273
- return buildSubmitResponse(c, prior, prior.requesterToken);
21362
+ return await this.submitResponse(c, prior, prior.requesterToken);
21274
21363
  }
21275
21364
  }
21276
21365
  if (!resumeOnly && this.opts.hostingControlInstance && creditEnvelope && authPubkey) {
@@ -21312,7 +21401,7 @@ var DVMServer = class {
21312
21401
  if (publicRequestId && authPubkey && recoveryStore) {
21313
21402
  const prior = await recoveryStore.findJobByRequestId(publicRequestId, authPubkey);
21314
21403
  if (prior) {
21315
- return resumeOnly ? buildSubmitResponse(c, prior, prior.requesterToken) : requestIdExists(c, publicRequestId);
21404
+ return resumeOnly ? await this.submitResponse(c, prior, prior.requesterToken) : requestIdExists(c, publicRequestId);
21316
21405
  }
21317
21406
  }
21318
21407
  let jobId = publicRequestClaimResult?.jobId ?? this.jobManager.allocateJobId();
@@ -21528,7 +21617,7 @@ var DVMServer = class {
21528
21617
  exactAdmission.intentId
21529
21618
  );
21530
21619
  await this.jobManager.ensureReceipt(prior);
21531
- return buildSubmitResponse(c, prior, prior.requesterToken);
21620
+ return await this.submitResponse(c, prior, prior.requesterToken);
21532
21621
  }
21533
21622
  }
21534
21623
  if (this.descriptor.auth && authEnvelope) {
@@ -21589,7 +21678,7 @@ var DVMServer = class {
21589
21678
  await jm.finalizeStoredTerminal(jobId);
21590
21679
  }
21591
21680
  const terminal = await store.get(jobId);
21592
- if (terminal) return buildSubmitResponse(c, terminal, jobToken);
21681
+ if (terminal) return await this.submitResponse(c, terminal, jobToken);
21593
21682
  }
21594
21683
  if (exactAdmission) {
21595
21684
  await this.x402ExactSettlement?.completeAdmission(
@@ -21604,7 +21693,7 @@ var DVMServer = class {
21604
21693
  setTimeout(resolve, 0);
21605
21694
  });
21606
21695
  await awaitTerminalWork(job);
21607
- let response = buildSubmitResponse(c, job, jobToken);
21696
+ let response = await this.submitResponse(c, job, jobToken);
21608
21697
  if (payment.x402SettleResponseHeader) {
21609
21698
  response = new Response(response.body, response);
21610
21699
  response.headers.set("PAYMENT-RESPONSE", payment.x402SettleResponseHeader);
@@ -21692,7 +21781,7 @@ var DVMServer = class {
21692
21781
  return void 0;
21693
21782
  }
21694
21783
  await this.jobManager.ensureReceipt(prior);
21695
- return buildSubmitResponse(c, prior, prior.requesterToken);
21784
+ return await this.submitResponse(c, prior, prior.requesterToken);
21696
21785
  }
21697
21786
  /**
21698
21787
  * Resolve the recorded draw's job under the same fingerprint/pubkey/requester
@@ -21737,7 +21826,7 @@ var DVMServer = class {
21737
21826
  return void 0;
21738
21827
  }
21739
21828
  await this.jobManager.ensureReceipt(prior);
21740
- return buildSubmitResponse(c, prior, prior.requesterToken);
21829
+ return await this.submitResponse(c, prior, prior.requesterToken);
21741
21830
  }
21742
21831
  /**
21743
21832
  * Resume the gap between a durable x402/Tempo marker+draw commit and the
@@ -21886,6 +21975,23 @@ var DVMServer = class {
21886
21975
  };
21887
21976
  }
21888
21977
  }
21978
+ async submitResponse(c, job, jobToken) {
21979
+ const snapshot = { ...job, messages: [...job.messages] };
21980
+ return buildSubmitResponse(c, snapshot, jobToken, await this.contentFields(snapshot));
21981
+ }
21982
+ async contentFields(job) {
21983
+ const store = this.jobManager.store;
21984
+ const responseStatus = job.status;
21985
+ if (isContentHoldStore(store)) {
21986
+ const snapshot = await store.getContentSnapshot(job.id);
21987
+ if (snapshot) return { ...contentMetadata({ ...snapshot.job, status: responseStatus }, this.descriptor.jobRetentionDays, snapshot.history.holds) };
21988
+ }
21989
+ return isContentHoldStore(store) ? { ...contentMetadata(job, this.descriptor.jobRetentionDays) } : {};
21990
+ }
21991
+ async messageFields(job, messages) {
21992
+ const fields = await this.contentFields(job);
21993
+ return { messages: fields.content_available === false ? [] : messages, ...fields };
21994
+ }
21889
21995
  async handleGetJob(c) {
21890
21996
  if (!jobCredential.presents(c.req)) return c.json(jobCredential.body(), 401);
21891
21997
  const id = c.req.param("id") ?? "";
@@ -21894,7 +22000,8 @@ var DVMServer = class {
21894
22000
  if (!isJobOwner(c, job)) return c.json({ error: "Job not found" }, 404);
21895
22001
  await this.jobManager.ensureReceipt(job);
21896
22002
  const res2 = { job_id: job.id, status: job.status };
21897
- Object.assign(res2, terminalResponseFields(job));
22003
+ Object.assign(res2, terminalResponseFields(job), await this.contentFields(job));
22004
+ removeUnavailableContent(res2);
21898
22005
  return c.json(res2);
21899
22006
  }
21900
22007
  const record = await this.jobManager.store.get(id);
@@ -21902,7 +22009,8 @@ var DVMServer = class {
21902
22009
  if (!isJobOwner(c, record)) return c.json({ error: "Job not found" }, 404);
21903
22010
  await this.jobManager.ensureReceipt(record);
21904
22011
  const res = { job_id: record.id, status: record.status };
21905
- Object.assign(res, terminalResponseFields(record));
22012
+ Object.assign(res, terminalResponseFields(record), await this.contentFields(record));
22013
+ removeUnavailableContent(res);
21906
22014
  return c.json(res);
21907
22015
  }
21908
22016
  async handleGetMessages(c) {
@@ -21973,7 +22081,9 @@ var DVMServer = class {
21973
22081
  });
21974
22082
  });
21975
22083
  }
22084
+ const fields = await this.contentFields(record);
21976
22085
  return streamSSE(c, async (stream) => {
22086
+ if (fields.content_available === false) return;
21977
22087
  for (const msg of filtered) {
21978
22088
  await stream.writeSSE({ data: JSON.stringify(msg), event: "message" });
21979
22089
  }
@@ -21981,13 +22091,15 @@ var DVMServer = class {
21981
22091
  }
21982
22092
  if (isStreamableJobStore(store) && !isTerminal(record.status)) {
21983
22093
  const msgs = await store.getMessages(id, after);
21984
- if (msgs.length > 0) return c.json({ messages: msgs });
22094
+ if (msgs.length > 0) return c.json(await this.messageFields(record, msgs));
21985
22095
  }
21986
- return c.json({ messages: filtered });
22096
+ return c.json(await this.messageFields(record, filtered));
21987
22097
  }
21988
22098
  if (!isJobOwner(c, job)) return c.json({ error: "Job not found" }, 404);
21989
22099
  if (accept.includes("text/event-stream")) {
22100
+ const fields = await this.contentFields(job);
21990
22101
  return streamSSE(c, async (stream) => {
22102
+ if (fields.content_available === false) return;
21991
22103
  const existing = job.messages.filter((m) => m.seq > after);
21992
22104
  let yielded = false;
21993
22105
  for (const msg of existing) {
@@ -22016,7 +22128,7 @@ var DVMServer = class {
22016
22128
  });
22017
22129
  });
22018
22130
  }
22019
- return c.json({ messages: job.messages.filter((m) => m.seq > after) });
22131
+ return c.json(await this.messageFields(job, job.messages.filter((m) => m.seq > after)));
22020
22132
  }
22021
22133
  jobNotActiveResponse(c) {
22022
22134
  return c.json(
@@ -22260,12 +22372,13 @@ function timingSafeEqualHex(a, b) {
22260
22372
  for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
22261
22373
  return diff === 0;
22262
22374
  }
22263
- function buildSubmitResponse(c, job, jobToken) {
22375
+ function buildSubmitResponse(c, job, jobToken, contentFields) {
22264
22376
  const res = { job_id: job.id };
22265
22377
  if (jobToken) res.job_token = jobToken;
22266
22378
  if (job.status === "awaiting-input") res.status = "awaiting-input";
22267
22379
  else if (job.status === "completed") res.status = "completed";
22268
- Object.assign(res, terminalResponseFields(job));
22380
+ Object.assign(res, terminalResponseFields(job), contentFields);
22381
+ removeUnavailableContent(res);
22269
22382
  return c.json(res, job.status === "completed" ? 200 : 202);
22270
22383
  }
22271
22384
  function requestRecoveryStore(store) {
@@ -22321,7 +22434,7 @@ function requestNotAccepted(c, requestId) {
22321
22434
  409
22322
22435
  );
22323
22436
  }
22324
- function buildRequestResultResponse(c, requestId, job) {
22437
+ function buildRequestResultResponse(c, requestId, job, contentFields) {
22325
22438
  const status = job.status === "working" ? "processing" : job.status;
22326
22439
  const res = {
22327
22440
  request_id: requestId,
@@ -22330,7 +22443,8 @@ function buildRequestResultResponse(c, requestId, job) {
22330
22443
  };
22331
22444
  if (job.requesterToken) res.job_token = job.requesterToken;
22332
22445
  if (job.paymentTransactionHash) res.transaction_hash = job.paymentTransactionHash;
22333
- Object.assign(res, terminalResponseFields(job));
22446
+ Object.assign(res, terminalResponseFields(job), contentFields);
22447
+ removeUnavailableContent(res);
22334
22448
  return c.json(res, isTerminal(job.status) ? 200 : 202);
22335
22449
  }
22336
22450
  function requestResultNotFound(c, requestId) {
@@ -22358,6 +22472,14 @@ async function awaitTerminalWork(job) {
22358
22472
  ]);
22359
22473
  clearTimeout(timer);
22360
22474
  }
22475
+ function removeUnavailableContent(fields) {
22476
+ if (fields.content_available === false) {
22477
+ delete fields.summary;
22478
+ fields.has_artifacts = false;
22479
+ delete fields.artifact_count;
22480
+ delete fields.payload_in;
22481
+ }
22482
+ }
22361
22483
  function terminalResponseFields(job) {
22362
22484
  const fields = {};
22363
22485
  if (job.status === "completed") {
@@ -22750,6 +22872,7 @@ export {
22750
22872
  handleCreditRequest,
22751
22873
  installAdminCashuRoutes,
22752
22874
  createAdminCashuNonceStore,
22875
+ installAdminContentRoutes,
22753
22876
  X402ExactSettlementServer,
22754
22877
  X402ExactSettlementEvidenceMissingError,
22755
22878
  HostedSettlementReportObligations,
@@ -4,7 +4,7 @@ import {
4
4
  DEFAULT_CREDIT_TTL_SECONDS,
5
5
  DEFAULT_JOB_RETENTION_DAYS,
6
6
  isZodSchema
7
- } from "./chunk-A4YFWZ7R.js";
7
+ } from "./chunk-RCM3P2HE.js";
8
8
  import {
9
9
  InvalidCurrencyError,
10
10
  validateCurrency
@@ -47,7 +47,7 @@ function configureDVM(config) {
47
47
  }
48
48
  function resolveJobRetentionDays(raw) {
49
49
  const days = raw ?? DEFAULT_JOB_RETENTION_DAYS;
50
- if (!Number.isSafeInteger(days) || days < 0) {
50
+ if (!Number.isSafeInteger(days) || days < 0 || days > Math.floor((Number.MAX_SAFE_INTEGER - Date.now()) / 864e5)) {
51
51
  throw new Error(
52
52
  `configureDVM: jobRetentionDays must be a non-negative whole number of days; received ${JSON.stringify(raw)}`
53
53
  );