@forestrie/mcp-register 0.0.0-stage → 0.1.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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +178 -2
  3. package/bin/mcp-register.mjs +2 -0
  4. package/dist/core/base64.d.ts +7 -0
  5. package/dist/core/base64.d.ts.map +1 -0
  6. package/dist/core/base64.js +20 -0
  7. package/dist/core/base64.js.map +1 -0
  8. package/dist/core/delegation.d.ts +56 -0
  9. package/dist/core/delegation.d.ts.map +1 -0
  10. package/dist/core/delegation.js +130 -0
  11. package/dist/core/delegation.js.map +1 -0
  12. package/dist/core/grant.d.ts +41 -0
  13. package/dist/core/grant.d.ts.map +1 -0
  14. package/dist/core/grant.js +78 -0
  15. package/dist/core/grant.js.map +1 -0
  16. package/dist/core/hex.d.ts +4 -0
  17. package/dist/core/hex.d.ts.map +1 -0
  18. package/dist/core/hex.js +18 -0
  19. package/dist/core/hex.js.map +1 -0
  20. package/dist/core/index.d.ts +28 -0
  21. package/dist/core/index.d.ts.map +1 -0
  22. package/dist/core/index.js +21 -0
  23. package/dist/core/index.js.map +1 -0
  24. package/dist/core/issue.d.ts +38 -0
  25. package/dist/core/issue.d.ts.map +1 -0
  26. package/dist/core/issue.js +135 -0
  27. package/dist/core/issue.js.map +1 -0
  28. package/dist/core/limits.d.ts +9 -0
  29. package/dist/core/limits.d.ts.map +1 -0
  30. package/dist/core/limits.js +9 -0
  31. package/dist/core/limits.js.map +1 -0
  32. package/dist/core/scrapi.d.ts +66 -0
  33. package/dist/core/scrapi.d.ts.map +1 -0
  34. package/dist/core/scrapi.js +174 -0
  35. package/dist/core/scrapi.js.map +1 -0
  36. package/dist/core/signer.d.ts +24 -0
  37. package/dist/core/signer.d.ts.map +1 -0
  38. package/dist/core/signer.js +2 -0
  39. package/dist/core/signer.js.map +1 -0
  40. package/dist/core/statement.d.ts +26 -0
  41. package/dist/core/statement.d.ts.map +1 -0
  42. package/dist/core/statement.js +70 -0
  43. package/dist/core/statement.js.map +1 -0
  44. package/dist/core/version.d.ts +23 -0
  45. package/dist/core/version.d.ts.map +1 -0
  46. package/dist/core/version.js +23 -0
  47. package/dist/core/version.js.map +1 -0
  48. package/dist/core/x402.d.ts +99 -0
  49. package/dist/core/x402.d.ts.map +1 -0
  50. package/dist/core/x402.js +202 -0
  51. package/dist/core/x402.js.map +1 -0
  52. package/dist/net/delegate.d.ts +56 -0
  53. package/dist/net/delegate.d.ts.map +1 -0
  54. package/dist/net/delegate.js +182 -0
  55. package/dist/net/delegate.js.map +1 -0
  56. package/dist/net/http.d.ts +17 -0
  57. package/dist/net/http.d.ts.map +1 -0
  58. package/dist/net/http.js +52 -0
  59. package/dist/net/http.js.map +1 -0
  60. package/dist/net/index.d.ts +14 -0
  61. package/dist/net/index.d.ts.map +1 -0
  62. package/dist/net/index.js +13 -0
  63. package/dist/net/index.js.map +1 -0
  64. package/dist/net/write.d.ts +55 -0
  65. package/dist/net/write.d.ts.map +1 -0
  66. package/dist/net/write.js +46 -0
  67. package/dist/net/write.js.map +1 -0
  68. package/dist/node/cli.d.ts +8 -0
  69. package/dist/node/cli.d.ts.map +1 -0
  70. package/dist/node/cli.js +143 -0
  71. package/dist/node/cli.js.map +1 -0
  72. package/dist/node/grant-store.d.ts +49 -0
  73. package/dist/node/grant-store.d.ts.map +1 -0
  74. package/dist/node/grant-store.js +95 -0
  75. package/dist/node/grant-store.js.map +1 -0
  76. package/dist/node/grant-tools.d.ts +29 -0
  77. package/dist/node/grant-tools.d.ts.map +1 -0
  78. package/dist/node/grant-tools.js +498 -0
  79. package/dist/node/grant-tools.js.map +1 -0
  80. package/dist/node/ledger.d.ts +26 -0
  81. package/dist/node/ledger.d.ts.map +1 -0
  82. package/dist/node/ledger.js +78 -0
  83. package/dist/node/ledger.js.map +1 -0
  84. package/dist/node/payer.d.ts +48 -0
  85. package/dist/node/payer.d.ts.map +1 -0
  86. package/dist/node/payer.js +170 -0
  87. package/dist/node/payer.js.map +1 -0
  88. package/dist/node/resolve-input.d.ts +19 -0
  89. package/dist/node/resolve-input.d.ts.map +1 -0
  90. package/dist/node/resolve-input.js +76 -0
  91. package/dist/node/resolve-input.js.map +1 -0
  92. package/dist/node/server.d.ts +47 -0
  93. package/dist/node/server.d.ts.map +1 -0
  94. package/dist/node/server.js +212 -0
  95. package/dist/node/server.js.map +1 -0
  96. package/dist/node/signer-file.d.ts +34 -0
  97. package/dist/node/signer-file.d.ts.map +1 -0
  98. package/dist/node/signer-file.js +183 -0
  99. package/dist/node/signer-file.js.map +1 -0
  100. package/dist/node/store.d.ts +40 -0
  101. package/dist/node/store.d.ts.map +1 -0
  102. package/dist/node/store.js +117 -0
  103. package/dist/node/store.js.map +1 -0
  104. package/dist/node/text.d.ts +29 -0
  105. package/dist/node/text.d.ts.map +1 -0
  106. package/dist/node/text.js +124 -0
  107. package/dist/node/text.js.map +1 -0
  108. package/dist/node/tools.d.ts +118 -0
  109. package/dist/node/tools.d.ts.map +1 -0
  110. package/dist/node/tools.js +548 -0
  111. package/dist/node/tools.js.map +1 -0
  112. package/package.json +108 -3
  113. package/src/core/base64.ts +18 -0
  114. package/src/core/delegation.ts +239 -0
  115. package/src/core/grant.ts +127 -0
  116. package/src/core/hex.ts +18 -0
  117. package/src/core/index.ts +84 -0
  118. package/src/core/issue.ts +209 -0
  119. package/src/core/limits.ts +8 -0
  120. package/src/core/scrapi.ts +236 -0
  121. package/src/core/signer.ts +23 -0
  122. package/src/core/statement.ts +133 -0
  123. package/src/core/version.ts +25 -0
  124. package/src/core/x402.ts +314 -0
  125. package/src/net/delegate.ts +274 -0
  126. package/src/net/http.ts +71 -0
  127. package/src/net/index.ts +26 -0
  128. package/src/net/write.ts +124 -0
  129. package/src/node/cli.ts +170 -0
  130. package/src/node/grant-store.ts +154 -0
  131. package/src/node/grant-tools.ts +707 -0
  132. package/src/node/ledger.ts +98 -0
  133. package/src/node/payer.ts +241 -0
  134. package/src/node/resolve-input.ts +96 -0
  135. package/src/node/server.ts +332 -0
  136. package/src/node/signer-file.ts +251 -0
  137. package/src/node/store.ts +175 -0
  138. package/src/node/text.ts +153 -0
  139. package/src/node/tools.ts +810 -0
@@ -0,0 +1,498 @@
1
+ /**
2
+ * The requester's tools: issue_grant signs a child grant with the authority
3
+ * key, and register_grant registers it with canopy, paying canopy's 402
4
+ * within the configured caps or relaying the payment requirements, then
5
+ * follows it to its receipt and completes it.
6
+ *
7
+ * register_grant is resumable by the child log id. Each call advances the
8
+ * stored record as far as it can (issued → payment_required → accepted →
9
+ * complete) and stops at the first thing it has to wait for. Every payment
10
+ * it signs for a grant carries a nonce derived from that grant, so one grant
11
+ * can never be paid for twice.
12
+ *
13
+ * Same contract as `tools.ts`: a refusal, an HTTP failure or bad input is a
14
+ * `structuredContent.problem` with a `code`, never a throw.
15
+ */
16
+ import { randomUUID } from "node:crypto";
17
+ import { z } from "zod";
18
+ import { NetError, fetchReceipt } from "@forestrie/mcp-resolve/net";
19
+ import { base64ToBytes, bytesToBase64 } from "../core/base64.js";
20
+ import { inspectGrant } from "../core/grant.js";
21
+ import { toHex } from "../core/hex.js";
22
+ function hexToBytes(hex) {
23
+ const h = hex.replace(/^0x/, "");
24
+ const out = new Uint8Array(h.length / 2);
25
+ for (let i = 0; i < out.length; i++)
26
+ out[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16);
27
+ return out;
28
+ }
29
+ import { MAX_PARENT_GRANT_BYTES, completeGrant, grantContent, issueChildGrant, parentGrantProblems, registerGrantBody, } from "../core/issue.js";
30
+ import { originOf, readReceiptResponse, readRegisterGrantResponse, readStatusResponse, } from "../core/scrapi.js";
31
+ import { PaymentError, grantPaymentNonce, readPaymentPayload, readPaymentRequired, selectWithinCaps, } from "../core/x402.js";
32
+ import { getRegistrationStatus, postGrant, registerGrantUrl, } from "../net/write.js";
33
+ import { readPaymentCaps } from "./payer.js";
34
+ import { InputError } from "./resolve-input.js";
35
+ import { BaseUrlSchema, GrantSchema, decodeBase64Text, guardHandler, httpProblem, httpProblemValue, missingInput, ok, problemResult, resolveGrant, } from "./tools.js";
36
+ const ParentGrantSchema = z
37
+ .string()
38
+ .min(1)
39
+ .describe("your authority grant: the completed grant that created your authority log and names this server's authority key, as base64 or a file path; falls back to FORESTRIE_AUTHORITY_GRANT");
40
+ const LogIdSchema = z
41
+ .string()
42
+ .regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
43
+ .describe("a child log id: a lowercase UUID");
44
+ export const issueGrantInputShape = {
45
+ maxHeight: z
46
+ .number()
47
+ .int()
48
+ .positive()
49
+ .describe("the grant's batch ceiling. canopy prices a payment-gated child grant as its unit price × maxHeight, so size it to the work it is for"),
50
+ parentGrant: ParentGrantSchema.optional(),
51
+ grantee: z
52
+ .string()
53
+ .min(1)
54
+ .optional()
55
+ .describe("base64 of the 64-byte x‖y the grant names (the performer's log key); defaults to this server's own log key, for a self-purchase"),
56
+ logId: LogIdSchema.optional().describe("the child data log to create; a fresh random UUID by default"),
57
+ };
58
+ export const registerGrantInputShape = {
59
+ logId: LogIdSchema.optional().describe("the child log id issue_grant returned: register_grant resumes that grant from wherever the last call reached"),
60
+ grant: GrantSchema.optional().describe("a child grant signed elsewhere (base64 or a file path), instead of logId"),
61
+ parentGrant: ParentGrantSchema.optional(),
62
+ payment: z
63
+ .string()
64
+ .min(1)
65
+ .optional()
66
+ .describe("relay mode: the X-PAYMENT header value your own x402 wallet produced for the payment requirements register_grant returned"),
67
+ baseUrl: BaseUrlSchema.optional(),
68
+ rootLogId: z
69
+ .string()
70
+ .min(1)
71
+ .optional()
72
+ .describe("the forest's root log id (R in /register/{R}/grants); falls back to FORESTRIE_ROOT_LOG_ID"),
73
+ };
74
+ /* ------------------------------ issue_grant ----------------------------- */
75
+ export function makeIssueGrantTool(deps) {
76
+ return (args) => guardHandler("issue_grant", async () => {
77
+ const parent = resolveGrant(args.parentGrant, deps, "FORESTRIE_AUTHORITY_GRANT");
78
+ if (!parent)
79
+ return missingInput("issue_grant", "parentGrant", "FORESTRIE_AUTHORITY_GRANT");
80
+ const authority = await deps.authoritySigner();
81
+ const refusals = parentGrantProblems(parent.view, await authority.publicKeyXY());
82
+ if (refusals.length > 0)
83
+ return problemResult("issue_grant", {
84
+ code: "parent_unusable",
85
+ message: refusals.join("; "),
86
+ ownerLogId: parent.view.logId,
87
+ });
88
+ let grantee;
89
+ let granteeIs;
90
+ if (args.grantee !== undefined) {
91
+ grantee = decodeBase64Text(args.grantee, "grantee");
92
+ if (grantee.length !== 64)
93
+ throw new InputError(`grantee must decode to 64 bytes x‖y (got ${grantee.length})`);
94
+ granteeIs = "the key supplied";
95
+ }
96
+ else {
97
+ grantee = await (await deps.signer()).publicKeyXY();
98
+ granteeIs = "this server's log key";
99
+ }
100
+ const logId = args.logId ?? randomUUID();
101
+ if (deps.grants.has(logId))
102
+ return problemResult("issue_grant", {
103
+ code: "already_issued",
104
+ message: `a grant for log ${logId} is already recorded here; call register_grant with that logId, or issue for a new log`,
105
+ logId,
106
+ });
107
+ const issued = await issueChildGrant({
108
+ logId,
109
+ ownerLogId: parent.view.logId,
110
+ grantData: grantee,
111
+ maxHeight: args.maxHeight,
112
+ }, authority);
113
+ const record = {
114
+ logId,
115
+ ownerLogId: parent.view.logId,
116
+ state: "issued",
117
+ issuedHere: true,
118
+ granteeHex: toHex(grantee),
119
+ maxHeight: args.maxHeight,
120
+ flagsHex: toHex(issued.flags),
121
+ parentRequiresPayment: parent.view.requiresChildPayment,
122
+ issuedAt: deps.now().toISOString(),
123
+ };
124
+ deps.grants.save(record, {
125
+ "grant.cose": issued.grant,
126
+ "parent.cose": base64ToBytes(parent.b64),
127
+ });
128
+ return ok(`issued: a data-log creation grant for log ${logId} under authority log ${record.ownerLogId}, naming ${granteeIs}, maxHeight ${args.maxHeight}. Not yet registered${record.parentRequiresPayment ? "; your authority grant makes its registration payment-gated" : ""}: call register_grant with this logId.`, {
129
+ ...record,
130
+ grantee: granteeIs,
131
+ grantBase64: bytesToBase64(issued.grant),
132
+ });
133
+ });
134
+ }
135
+ /** The grant this call is about: a stored one by logId, or one supplied. */
136
+ function locate(args, deps) {
137
+ if (args.grant !== undefined) {
138
+ const supplied = resolveGrant(args.grant, deps);
139
+ const bytes = base64ToBytes(supplied.b64);
140
+ const logId = supplied.view.logId;
141
+ if (args.logId !== undefined && args.logId !== logId)
142
+ throw new InputError(`the grant is for log ${logId}, not the logId given (${args.logId})`);
143
+ if (deps.grants.has(logId)) {
144
+ const stored = deps.grants.read(logId, "grant.cose");
145
+ if (stored === undefined || toHex(stored) !== toHex(bytes))
146
+ return problemResult("register_grant", {
147
+ code: "grant_conflict",
148
+ message: `a different grant for log ${logId} is already recorded here; pass logId alone to resume it`,
149
+ logId,
150
+ });
151
+ return {
152
+ record: deps.grants.load(logId),
153
+ grant: bytes,
154
+ view: supplied.view,
155
+ };
156
+ }
157
+ const record = {
158
+ logId,
159
+ ownerLogId: supplied.view.ownerLogId,
160
+ state: "issued",
161
+ issuedHere: false,
162
+ granteeHex: toHex(supplied.view.grantData),
163
+ ...(supplied.view.maxHeight !== undefined
164
+ ? { maxHeight: supplied.view.maxHeight }
165
+ : {}),
166
+ flagsHex: supplied.view.flagsHex,
167
+ issuedAt: deps.now().toISOString(),
168
+ };
169
+ deps.grants.save(record, { "grant.cose": bytes });
170
+ return { record, grant: bytes, view: supplied.view };
171
+ }
172
+ if (args.logId === undefined)
173
+ return problemResult("register_grant", {
174
+ code: "missing_input",
175
+ message: "pass logId (a grant issue_grant made) or grant (one signed elsewhere)",
176
+ });
177
+ const record = deps.grants.load(args.logId);
178
+ const grant = deps.grants.read(args.logId, "grant.cose");
179
+ if (grant === undefined)
180
+ return problemResult("register_grant", {
181
+ code: "corrupt_record",
182
+ message: `grant ${args.logId} has a record but no grant.cose`,
183
+ });
184
+ return { record, grant, view: inspectGrant(grant) };
185
+ }
186
+ function decodeHeaderJson(value, what) {
187
+ let text;
188
+ try {
189
+ text = new TextDecoder("utf-8", { fatal: true }).decode(base64ToBytes(value));
190
+ }
191
+ catch {
192
+ throw new PaymentError(what === "X-PAYMENT"
193
+ ? "invalid_payment"
194
+ : "invalid_payment_requirements", `${what} is not base64 of UTF-8 text`);
195
+ }
196
+ try {
197
+ return JSON.parse(text);
198
+ }
199
+ catch {
200
+ throw new PaymentError(what === "X-PAYMENT"
201
+ ? "invalid_payment"
202
+ : "invalid_payment_requirements", `${what} is not base64 of JSON`);
203
+ }
204
+ }
205
+ function requirementsView(required) {
206
+ return {
207
+ accepts: required.accepts,
208
+ ...(required.resource !== undefined
209
+ ? { resource: required.resource }
210
+ : {}),
211
+ };
212
+ }
213
+ /**
214
+ * No lock: paying twice for one grant is prevented by the nonce, not by
215
+ * serialising calls. Every authorisation this server signs for a grant
216
+ * carries `grantPaymentNonce(grant content, payer)`, so overlapping calls,
217
+ * a retry after a lost answer and other processes sharing the payer all
218
+ * sign the same nonce, and EIP-3009 settles at most one authorisation per
219
+ * (payer, nonce). The daily cap is approximate under concurrency: calls that
220
+ * pass the check before either records its payment can overshoot it by at
221
+ * most one per-call cap each.
222
+ */
223
+ export function makeRegisterGrantTool(deps) {
224
+ return (args) => registerGrant(args, deps);
225
+ }
226
+ function registerGrant(args, deps) {
227
+ return guardHandler("register_grant", async () => {
228
+ const located = locate(args, deps);
229
+ if ("content" in located)
230
+ return located;
231
+ const { record, grant } = located;
232
+ const store = deps.grants;
233
+ if (record.state === "complete")
234
+ return completeResult(record, deps);
235
+ if (record.state === "accepted")
236
+ return advance(record, grant, deps);
237
+ // issued | payment_required: (re)send the registration.
238
+ const baseUrl = args.baseUrl ?? record.baseUrl ?? deps.env["FORESTRIE_BASE_URL"];
239
+ if (!baseUrl)
240
+ return missingInput("register_grant", "baseUrl", "FORESTRIE_BASE_URL");
241
+ const rootLogId = args.rootLogId ?? record.rootLogId ?? deps.env["FORESTRIE_ROOT_LOG_ID"];
242
+ if (!rootLogId)
243
+ return missingInput("register_grant", "rootLogId", "FORESTRIE_ROOT_LOG_ID");
244
+ if ((record.baseUrl !== undefined && record.baseUrl !== baseUrl) ||
245
+ (record.rootLogId !== undefined && record.rootLogId !== rootLogId))
246
+ return problemResult("register_grant", {
247
+ code: "invalid_input",
248
+ message: `grant ${record.logId} was already sent to ${record.baseUrl} for forest ${record.rootLogId}; it is resumed there, not moved`,
249
+ });
250
+ let parent = store.read(record.logId, "parent.cose");
251
+ if (args.parentGrant !== undefined || parent === undefined) {
252
+ const p = resolveGrant(args.parentGrant, deps, "FORESTRIE_AUTHORITY_GRANT");
253
+ if (p !== undefined) {
254
+ if (p.view.logId !== record.ownerLogId)
255
+ throw new InputError(`the parent grant is for log ${p.view.logId}, but this grant's owner is ${record.ownerLogId}`);
256
+ parent = base64ToBytes(p.b64);
257
+ record.parentRequiresPayment = p.view.requiresChildPayment;
258
+ }
259
+ }
260
+ if (parent !== undefined && parent.length > MAX_PARENT_GRANT_BYTES)
261
+ throw new InputError(`the parent grant is ${parent.length} bytes; canopy reads at most ${MAX_PARENT_GRANT_BYTES}`);
262
+ // Without the parent as evidence canopy cannot see a payment policy;
263
+ // send an empty body rather than guess one.
264
+ const body = parent !== undefined ? registerGrantBody(parent) : new Uint8Array(0);
265
+ record.baseUrl = baseUrl;
266
+ record.rootLogId = rootLogId;
267
+ store.save(record, parent !== undefined ? { "parent.cose": parent } : {});
268
+ const grantB64 = bytesToBase64(grant);
269
+ const resourceUrl = registerGrantUrl(baseUrl, rootLogId);
270
+ const send = (payment) => postGrant({
271
+ baseUrl,
272
+ rootLogId,
273
+ grantB64,
274
+ body,
275
+ ...(payment !== undefined ? { payment } : {}),
276
+ }, { fetchImpl: deps.fetchImpl });
277
+ // A payment the caller relays from its own wallet.
278
+ let payment;
279
+ if (args.payment !== undefined) {
280
+ readPaymentPayload(decodeHeaderJson(args.payment, "X-PAYMENT"));
281
+ payment = { header: args.payment, via: "relay" };
282
+ }
283
+ let outcome = await sendOrReport(record, deps, () => send(payment?.header), payment);
284
+ if ("content" in outcome)
285
+ return outcome;
286
+ if (outcome.kind === "payment_required" && payment === undefined) {
287
+ const required = readPaymentRequired(decodeHeaderJson(outcome.paymentRequiredHeader, "X-PAYMENT-REQUIRED"));
288
+ record.paymentRequired = required;
289
+ record.state = "payment_required";
290
+ store.save(record);
291
+ const payer = deps.payer();
292
+ if (payer === undefined)
293
+ return ok(`payment_required: canopy asks ${describeOptions(required)} to register the grant for log ${record.logId}. No payer is configured here, so pay from your own x402 wallet: give it the paymentRequiredHeader (or the requirements), then call register_grant again with logId ${record.logId} and payment set to the X-PAYMENT value it returns.`, {
294
+ state: "payment_required",
295
+ logId: record.logId,
296
+ resourceUrl,
297
+ requirements: requirementsView(required),
298
+ paymentRequiredHeader: outcome.paymentRequiredHeader,
299
+ ...(outcome.problem.detail !== undefined
300
+ ? { detail: outcome.problem.detail }
301
+ : {}),
302
+ });
303
+ // Pay within the caps, only the canopy this server is configured for.
304
+ const configured = deps.env["FORESTRIE_BASE_URL"];
305
+ if (configured === undefined ||
306
+ originOf(configured) === undefined ||
307
+ originOf(configured) !== originOf(baseUrl))
308
+ return problemResult("register_grant", {
309
+ code: "cap_origin",
310
+ message: `this server pays only the canopy in FORESTRIE_BASE_URL (${configured ?? "unset"}), not ${baseUrl}`,
311
+ requirements: requirementsView(required),
312
+ });
313
+ const caps = readPaymentCaps(deps.env);
314
+ const now = deps.now();
315
+ let option;
316
+ try {
317
+ option = selectWithinCaps(required, caps, {
318
+ resourceUrl,
319
+ spentTodayAtomic: deps.ledger.spentToday(now, caps.network, caps.asset),
320
+ });
321
+ }
322
+ catch (err) {
323
+ if (!(err instanceof PaymentError))
324
+ throw err;
325
+ return problemResult("register_grant", {
326
+ code: err.code,
327
+ message: err.message,
328
+ requirements: requirementsView(required),
329
+ });
330
+ }
331
+ const nonce = await grantPaymentNonce(grantContent(grant), hexToBytes(payer.address));
332
+ let header;
333
+ try {
334
+ header = await payer.pay({
335
+ required,
336
+ option,
337
+ nonce,
338
+ nowSeconds: Math.floor(now.getTime() / 1000),
339
+ });
340
+ }
341
+ catch (err) {
342
+ return problemResult("register_grant", {
343
+ code: "payer_failed",
344
+ message: `the payer (${payer.description}) did not sign the payment: ${err instanceof Error ? err.message : String(err)}. Nothing was sent or counted.`,
345
+ });
346
+ }
347
+ const summary = readPaymentPayload(decodeHeaderJson(header, "X-PAYMENT"));
348
+ if (summary.value !== option.amount ||
349
+ summary.to.toLowerCase() !== option.payTo.toLowerCase() ||
350
+ summary.network !== option.network ||
351
+ summary.nonce.toLowerCase() !== nonce)
352
+ return problemResult("register_grant", {
353
+ code: "invalid_payment",
354
+ message: `the payer signed ${summary.value} to ${summary.to} on ${summary.network} with nonce ${summary.nonce}, not the ${option.amount} to ${option.payTo} on ${option.network} with the grant's nonce ${nonce} it was asked for; not sending it`,
355
+ });
356
+ // Committed from here: count it, then send it. A retry re-signs with
357
+ // the same nonce, which the ledger counts once.
358
+ deps.ledger.record(now, {
359
+ at: now.toISOString(),
360
+ network: option.network,
361
+ asset: option.asset.toLowerCase(),
362
+ amount: option.amount,
363
+ payTo: option.payTo,
364
+ from: summary.from,
365
+ nonce: summary.nonce,
366
+ logId: record.logId,
367
+ });
368
+ payment = { header, via: "payer" };
369
+ outcome = await sendOrReport(record, deps, () => send(header), payment);
370
+ if ("content" in outcome)
371
+ return outcome;
372
+ }
373
+ if (payment !== undefined) {
374
+ const summary = readPaymentPayload(decodeHeaderJson(payment.header, "X-PAYMENT"));
375
+ if (outcome.kind === "payment_required") {
376
+ // canopy refused the payment presented: the next call starts from
377
+ // the challenge again.
378
+ record.state = "payment_required";
379
+ store.save(record);
380
+ return problemResult("register_grant", {
381
+ code: "payment_rejected",
382
+ message: `canopy refused the payment (${outcome.problem.detail ?? outcome.problem.title}). Nothing was registered${payment.via === "payer" ? "; the authorisation still counts toward today's cap until it expires unspent" : ""}.`,
383
+ logId: record.logId,
384
+ payment: summary,
385
+ });
386
+ }
387
+ record.payment = {
388
+ ...summary,
389
+ via: payment.via,
390
+ at: deps.now().toISOString(),
391
+ };
392
+ }
393
+ if (outcome.kind === "problem") {
394
+ store.save(record);
395
+ return problemResult("register_grant", {
396
+ ...httpProblemValue("canopy refused the grant", outcome.problem),
397
+ logId: record.logId,
398
+ });
399
+ }
400
+ if (outcome.kind === "payment_required")
401
+ // Only reachable with a payment present, handled above.
402
+ throw new Error("unreachable: payment_required after payment");
403
+ record.state = "accepted";
404
+ record.statusUrl = outcome.statusUrl;
405
+ record.acceptedAt = deps.now().toISOString();
406
+ store.save(record);
407
+ return ok(`accepted: canopy enqueued the grant for log ${record.logId} for sequencing under authority log ${record.ownerLogId}${record.payment ? `, paid ${record.payment.value} (${record.payment.via})` : ""}. Call register_grant again with logId ${record.logId}${outcome.retryAfterSeconds !== undefined ? ` in about ${outcome.retryAfterSeconds}s` : ""} to follow it to its receipt.`, {
408
+ ...record,
409
+ ...(outcome.retryAfterSeconds !== undefined
410
+ ? { retryAfterSeconds: outcome.retryAfterSeconds }
411
+ : {}),
412
+ });
413
+ });
414
+ }
415
+ /** Send, mapping a lost answer to a problem that says how to resume. */
416
+ async function sendOrReport(record, deps, send, payment) {
417
+ let res;
418
+ try {
419
+ res = await send();
420
+ }
421
+ catch (err) {
422
+ if (!(err instanceof NetError))
423
+ throw err;
424
+ return problemResult("register_grant", {
425
+ code: err.code,
426
+ message: `${err.message}. canopy may or may not have received the grant${payment ? " and the payment" : ""}. Call register_grant again with logId ${record.logId}: ${payment?.via === "payer" ? "it signs again with the grant's own nonce, so at most one payment can settle" : payment ? "pass the same payment again" : "it is sent again unchanged"}.`,
427
+ logId: record.logId,
428
+ });
429
+ }
430
+ return readRegisterGrantResponse(res, originOf(record.baseUrl));
431
+ }
432
+ function describeOptions(required) {
433
+ return required.accepts
434
+ .map((o) => `${o.amount} atomic units of ${o.asset} on ${o.network}, to ${o.payTo}`)
435
+ .join(" or ");
436
+ }
437
+ /** Accepted: follow the status URL to the receipt, then complete the grant. */
438
+ async function advance(record, grant, deps) {
439
+ const store = deps.grants;
440
+ const origin = originOf(record.baseUrl);
441
+ if (record.receiptUrl === undefined) {
442
+ const res = await getRegistrationStatus({ statusUrl: record.statusUrl }, { fetchImpl: deps.fetchImpl });
443
+ const status = readStatusResponse(res, origin);
444
+ if (status.kind === "problem")
445
+ return httpProblem("register_grant", "the grant's status URL answered with a problem", status.problem);
446
+ if (status.kind === "pending") {
447
+ record.firstPendingAt ??= res.at;
448
+ store.save(record);
449
+ return ok(`pending: the grant for log ${record.logId} is not yet sequenced; call register_grant again in ${status.retryAfterSeconds}s`, {
450
+ state: "accepted",
451
+ logId: record.logId,
452
+ retryAfterSeconds: status.retryAfterSeconds,
453
+ firstPendingAt: record.firstPendingAt,
454
+ });
455
+ }
456
+ record.receiptUrl = status.receiptUrl;
457
+ record.entryId = status.entryId;
458
+ record.massifHeight = status.massifHeight;
459
+ store.save(record);
460
+ }
461
+ const res = await fetchReceipt({ receiptUrl: record.receiptUrl }, { fetchImpl: deps.fetchImpl });
462
+ const receipt = readReceiptResponse(res);
463
+ if (receipt.kind === "problem")
464
+ return httpProblem("register_grant", "the grant's receipt URL answered with a problem", receipt.problem);
465
+ if (receipt.kind === "awaiting_seal")
466
+ return ok(`awaiting_seal: the grant is sequenced as entry ${record.entryId} in authority log ${record.ownerLogId}; canopy says "${receipt.reason}". It seals once that log's sealing is delegated (delegate_sealing with as: "authority"); call register_grant again in about a minute.`, {
467
+ state: "accepted",
468
+ sealed: false,
469
+ logId: record.logId,
470
+ entryId: record.entryId,
471
+ receiptUrl: record.receiptUrl,
472
+ reason: receipt.reason,
473
+ });
474
+ const completed = completeGrant(grant, receipt.receipt, record.entryId);
475
+ record.state = "complete";
476
+ record.completedAt = deps.now().toISOString();
477
+ store.save(record, {
478
+ "receipt.cose": receipt.receipt,
479
+ "completed.cose": completed,
480
+ });
481
+ return completeResult(record, deps);
482
+ }
483
+ async function completeResult(record, deps) {
484
+ const completed = deps.grants.read(record.logId, "completed.cose");
485
+ if (completed === undefined)
486
+ return problemResult("register_grant", {
487
+ code: "corrupt_record",
488
+ message: `grant ${record.logId} is marked complete but has no completed.cose`,
489
+ });
490
+ const logKey = await (await deps.signer()).publicKeyXY();
491
+ const namesThisServer = record.granteeHex === toHex(logKey);
492
+ return ok(`complete: the grant for log ${record.logId} is sealed (entry ${record.entryId}) and completed with its receipt. ${namesThisServer ? "It names this server's log key: pass grantBase64 as grant to delegate_sealing, then to register_statement (or set FORESTRIE_GRANT to it)." : "It names another key: give grantBase64 to the performer holding that key."}`, {
493
+ ...record,
494
+ grantBase64: bytesToBase64(completed),
495
+ namesThisServer,
496
+ });
497
+ }
498
+ //# sourceMappingURL=grant-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grant-tools.js","sourceRoot":"","sources":["../../src/node/grant-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export interface LedgerEntry {
2
+ at: string;
3
+ network: string;
4
+ asset: string;
5
+ amount: string;
6
+ payTo: string;
7
+ from: string;
8
+ nonce: string;
9
+ /** The child log whose grant the payment is for. */
10
+ logId: string;
11
+ }
12
+ export declare class SpendLedger {
13
+ readonly root: string;
14
+ constructor(root: string);
15
+ private file;
16
+ static day(now: Date): string;
17
+ entries(now: Date): LedgerEntry[];
18
+ /**
19
+ * Atomic units committed today on this network and asset. Each nonce
20
+ * counts once: a retry re-signs a grant's payment with the same nonce,
21
+ * and at most one authorisation per nonce can ever settle.
22
+ */
23
+ spentToday(now: Date, network: string, asset: string): bigint;
24
+ record(now: Date, entry: LedgerEntry): void;
25
+ }
26
+ //# sourceMappingURL=ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/node/ledger.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,WAAW;IACV,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;IAEjC,OAAO,CAAC,IAAI;IAIZ,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM;IAI7B,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,WAAW,EAAE;IA2BjC;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAa7D,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;CAe5C"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * What the payer backend has committed, per UTC day:
3
+ * `<home>/payments/<YYYY-MM-DD>.jsonl`, one line per signed authorisation.
4
+ *
5
+ * An entry is written BEFORE the payment is sent: once signed, an
6
+ * authorisation can be settled whether or not this server ever sees
7
+ * canopy's answer, so the daily cap counts every authorisation signed, not
8
+ * only the ones known to have settled. The cap is approximate under
9
+ * concurrency: two calls can both pass the check before either is written.
10
+ */
11
+ import { appendFileSync, mkdirSync, readFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { StoreError } from "./store.js";
14
+ export class SpendLedger {
15
+ root;
16
+ constructor(root) {
17
+ this.root = root;
18
+ }
19
+ file(day) {
20
+ return join(this.root, "payments", `${day}.jsonl`);
21
+ }
22
+ static day(now) {
23
+ return now.toISOString().slice(0, 10);
24
+ }
25
+ entries(now) {
26
+ let text;
27
+ try {
28
+ text = readFileSync(this.file(SpendLedger.day(now)), "utf8");
29
+ }
30
+ catch (err) {
31
+ if (err.code === "ENOENT")
32
+ return [];
33
+ throw new StoreError("store_failed", `cannot read the spend ledger: ${err.message}`);
34
+ }
35
+ const out = [];
36
+ for (const line of text.split("\n")) {
37
+ if (line.trim() === "")
38
+ continue;
39
+ try {
40
+ out.push(JSON.parse(line));
41
+ }
42
+ catch {
43
+ // Refuse rather than guess: an unreadable line could be a payment.
44
+ throw new StoreError("corrupt_record", `the spend ledger ${this.file(SpendLedger.day(now))} has a line that is not JSON; fix or remove it before paying again`);
45
+ }
46
+ }
47
+ return out;
48
+ }
49
+ /**
50
+ * Atomic units committed today on this network and asset. Each nonce
51
+ * counts once: a retry re-signs a grant's payment with the same nonce,
52
+ * and at most one authorisation per nonce can ever settle.
53
+ */
54
+ spentToday(now, network, asset) {
55
+ let total = 0n;
56
+ const seen = new Set();
57
+ for (const e of this.entries(now)) {
58
+ if (e.network !== network || e.asset.toLowerCase() !== asset)
59
+ continue;
60
+ const key = `${e.from.toLowerCase()} ${e.nonce.toLowerCase()}`;
61
+ if (seen.has(key))
62
+ continue;
63
+ seen.add(key);
64
+ total += BigInt(e.amount);
65
+ }
66
+ return total;
67
+ }
68
+ record(now, entry) {
69
+ try {
70
+ mkdirSync(join(this.root, "payments"), { recursive: true, mode: 0o700 });
71
+ appendFileSync(this.file(SpendLedger.day(now)), JSON.stringify(entry) + "\n", { mode: 0o600 });
72
+ }
73
+ catch (err) {
74
+ throw new StoreError("store_failed", `cannot write the spend ledger: ${err.message}`);
75
+ }
76
+ }
77
+ }
78
+ //# sourceMappingURL=ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/node/ledger.ts"],"names":[],"mappings":"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"}