@supercuts-walrus/backend 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +249 -2
  3. package/dist/audit.d.ts +52 -0
  4. package/dist/audit.js +157 -0
  5. package/dist/backend.d.ts +27 -0
  6. package/dist/backend.js +62 -0
  7. package/dist/buyer-setup.d.ts +6 -0
  8. package/dist/buyer-setup.js +241 -0
  9. package/dist/capability.d.ts +32 -0
  10. package/dist/capability.js +87 -0
  11. package/dist/claude.d.ts +44 -0
  12. package/dist/claude.js +98 -0
  13. package/dist/cli.d.ts +2 -0
  14. package/dist/cli.js +29 -0
  15. package/dist/config.d.ts +20 -0
  16. package/dist/config.js +58 -0
  17. package/dist/dashboard.d.ts +5 -0
  18. package/dist/dashboard.js +21 -0
  19. package/dist/deal-adapter.d.ts +3 -0
  20. package/dist/deal-adapter.js +39 -0
  21. package/dist/deal-engine.d.ts +62 -0
  22. package/dist/deal-engine.js +211 -0
  23. package/dist/deal-wire.d.ts +16 -0
  24. package/dist/deal-wire.js +65 -0
  25. package/dist/deal.d.ts +79 -0
  26. package/dist/deal.js +228 -0
  27. package/dist/demo.d.ts +2 -0
  28. package/dist/demo.js +449 -0
  29. package/dist/errors.d.ts +6 -0
  30. package/dist/errors.js +13 -0
  31. package/dist/events.d.ts +27 -0
  32. package/dist/events.js +68 -0
  33. package/dist/facilitator.d.ts +21 -0
  34. package/dist/facilitator.js +173 -0
  35. package/dist/finality.d.ts +2 -0
  36. package/dist/finality.js +27 -0
  37. package/dist/hosted-exit-cli.d.ts +2 -0
  38. package/dist/hosted-exit-cli.js +37 -0
  39. package/dist/hosted-exit.d.ts +24 -0
  40. package/dist/hosted-exit.js +70 -0
  41. package/dist/hosted-seller-import.d.ts +2 -0
  42. package/dist/hosted-seller-import.js +70 -0
  43. package/dist/hosted-seller-repository.d.ts +31 -0
  44. package/dist/hosted-seller-repository.js +214 -0
  45. package/dist/index.d.ts +37 -0
  46. package/dist/index.js +37 -0
  47. package/dist/indexer.d.ts +63 -0
  48. package/dist/indexer.js +60 -0
  49. package/dist/live-deal-ports.d.ts +41 -0
  50. package/dist/live-deal-ports.js +212 -0
  51. package/dist/live-index.d.ts +28 -0
  52. package/dist/live-index.js +149 -0
  53. package/dist/live-runtime.d.ts +82 -0
  54. package/dist/live-runtime.js +570 -0
  55. package/dist/live-seller-transport.d.ts +30 -0
  56. package/dist/live-seller-transport.js +169 -0
  57. package/dist/live-seller-verifier.d.ts +11 -0
  58. package/dist/live-seller-verifier.js +65 -0
  59. package/dist/mandate.d.ts +34 -0
  60. package/dist/mandate.js +178 -0
  61. package/dist/mcp-bootstrap.d.ts +2 -0
  62. package/dist/mcp-bootstrap.js +39 -0
  63. package/dist/mcp.d.ts +2 -0
  64. package/dist/mcp.js +187 -0
  65. package/dist/memory-worker.d.ts +2 -0
  66. package/dist/memory-worker.js +38 -0
  67. package/dist/memory.d.ts +15 -0
  68. package/dist/memory.js +17 -0
  69. package/dist/memwal.d.ts +35 -0
  70. package/dist/memwal.js +83 -0
  71. package/dist/negotiation.d.ts +23 -0
  72. package/dist/negotiation.js +58 -0
  73. package/dist/notes.d.ts +11 -0
  74. package/dist/notes.js +26 -0
  75. package/dist/onboarding-doctor.d.ts +1 -0
  76. package/dist/onboarding-doctor.js +76 -0
  77. package/dist/phase3.d.ts +100 -0
  78. package/dist/phase3.js +1144 -0
  79. package/dist/procurement.d.ts +8 -0
  80. package/dist/procurement.js +19 -0
  81. package/dist/protocol-engine.d.ts +121 -0
  82. package/dist/protocol-engine.js +149 -0
  83. package/dist/prover.d.ts +28 -0
  84. package/dist/prover.js +70 -0
  85. package/dist/relayer.d.ts +32 -0
  86. package/dist/relayer.js +43 -0
  87. package/dist/remote-buyer.d.ts +67 -0
  88. package/dist/remote-buyer.js +231 -0
  89. package/dist/resource-server.d.ts +2 -0
  90. package/dist/resource-server.js +24 -0
  91. package/dist/resource.d.ts +22 -0
  92. package/dist/resource.js +55 -0
  93. package/dist/seam.d.ts +2 -0
  94. package/dist/seam.js +117 -0
  95. package/dist/seller-catalog-generate.d.ts +2 -0
  96. package/dist/seller-catalog-generate.js +68 -0
  97. package/dist/seller-database.d.ts +41 -0
  98. package/dist/seller-database.js +80 -0
  99. package/dist/seller-directory-cli.d.ts +2 -0
  100. package/dist/seller-directory-cli.js +24 -0
  101. package/dist/seller-directory.d.ts +5 -0
  102. package/dist/seller-directory.js +50 -0
  103. package/dist/seller-live-cli.d.ts +2 -0
  104. package/dist/seller-live-cli.js +53 -0
  105. package/dist/seller-provision.d.ts +2 -0
  106. package/dist/seller-provision.js +84 -0
  107. package/dist/seller-register-cli.d.ts +2 -0
  108. package/dist/seller-register-cli.js +40 -0
  109. package/dist/seller-runtime.d.ts +60 -0
  110. package/dist/seller-runtime.js +96 -0
  111. package/dist/seller-service.d.ts +34 -0
  112. package/dist/seller-service.js +416 -0
  113. package/dist/seller-state.d.ts +19 -0
  114. package/dist/seller-state.js +60 -0
  115. package/dist/seller-stdio.d.ts +6 -0
  116. package/dist/seller-stdio.js +29 -0
  117. package/dist/seller-v2-provision.d.ts +2 -0
  118. package/dist/seller-v2-provision.js +71 -0
  119. package/dist/seller-watch.d.ts +2 -0
  120. package/dist/seller-watch.js +45 -0
  121. package/dist/settlement.d.ts +95 -0
  122. package/dist/settlement.js +141 -0
  123. package/dist/store.d.ts +36 -0
  124. package/dist/store.js +193 -0
  125. package/dist/sui.d.ts +49 -0
  126. package/dist/sui.js +77 -0
  127. package/dist/tatum.d.ts +17 -0
  128. package/dist/tatum.js +83 -0
  129. package/dist/transcript.d.ts +31 -0
  130. package/dist/transcript.js +52 -0
  131. package/dist/v2-exit-relayer.d.ts +34 -0
  132. package/dist/v2-exit-relayer.js +102 -0
  133. package/dist/v2-exit-worker.d.ts +2 -0
  134. package/dist/v2-exit-worker.js +97 -0
  135. package/dist/v2-exits.d.ts +30 -0
  136. package/dist/v2-exits.js +78 -0
  137. package/dist/v2-prefund.d.ts +19 -0
  138. package/dist/v2-prefund.js +43 -0
  139. package/dist/v2-relayer-cli.d.ts +2 -0
  140. package/dist/v2-relayer-cli.js +39 -0
  141. package/dist/wallet.d.ts +32 -0
  142. package/dist/wallet.js +90 -0
  143. package/dist/workflow-memory.d.ts +22 -0
  144. package/dist/workflow-memory.js +49 -0
  145. package/dist/x402-resource-service.d.ts +34 -0
  146. package/dist/x402-resource-service.js +154 -0
  147. package/dist/x402.d.ts +46 -0
  148. package/dist/x402.js +136 -0
  149. package/package.json +60 -3
@@ -0,0 +1,214 @@
1
+ import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
2
+ import { DatabaseSync } from "node:sqlite";
3
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { Pool } from "pg";
7
+ import { fail } from "./errors.js";
8
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
9
+ function keyBytes(encoded) {
10
+ const key = Buffer.from(encoded, "base64url");
11
+ if (key.length !== 32)
12
+ fail("SELLER_STATE_KEY_INVALID", "seller wrapping key must contain 32 bytes");
13
+ return key;
14
+ }
15
+ function seal(key, aad, bytes) {
16
+ const nonce = randomBytes(12), cipher = createCipheriv("aes-256-gcm", key, nonce);
17
+ cipher.setAAD(Buffer.from(aad));
18
+ const ciphertext = Buffer.concat([cipher.update(bytes), cipher.final()]);
19
+ return { nonce: nonce.toString("base64url"), tag: cipher.getAuthTag().toString("base64url"), ciphertext: ciphertext.toString("base64url") };
20
+ }
21
+ function open(key, aad, value) {
22
+ try {
23
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(value.nonce, "base64url"));
24
+ decipher.setAAD(Buffer.from(aad));
25
+ decipher.setAuthTag(Buffer.from(value.tag, "base64url"));
26
+ return Buffer.concat([decipher.update(Buffer.from(value.ciphertext, "base64url")), decipher.final()]);
27
+ }
28
+ catch (error) {
29
+ return fail("SELLER_STATE_DECRYPT_FAILED", "hosted seller row could not be authenticated", error);
30
+ }
31
+ }
32
+ const encodeRow = (row) => Buffer.from(JSON.stringify(Object.fromEntries(Object.entries(row).map(([key, value]) => [key, value instanceof Uint8Array ? { __sellerBytes: Buffer.from(value).toString("base64url") } : value]))));
33
+ const decodeRow = (bytes) => JSON.parse(bytes.toString(), (_key, value) => value && typeof value === "object" && !Array.isArray(value) && "__sellerBytes" in value
34
+ ? Buffer.from(String(value.__sellerBytes), "base64url") : value);
35
+ /** Direct Postgres connection used only by owner-side migration and seller processes. */
36
+ export class HostedSellerRepository {
37
+ wrappingKey;
38
+ #pool;
39
+ constructor(connectionString, wrappingKey) {
40
+ this.wrappingKey = wrappingKey;
41
+ const url = new URL(connectionString);
42
+ if (!["postgres:", "postgresql:"].includes(url.protocol) || !url.hostname || !url.username || !url.password || url.searchParams.get("sslmode") === "disable" || url.searchParams.get("sslmode") === "no-verify")
43
+ fail("SELLER_DB_INVALID", "SUPABASE_DB_URL must be a credentialed Postgres URL with verified TLS");
44
+ // Use parsed fields so URL options cannot override the TLS policy.
45
+ this.#pool = new Pool({ host: url.hostname, port: url.port ? Number(url.port) : 5432,
46
+ user: decodeURIComponent(url.username), password: decodeURIComponent(url.password),
47
+ database: decodeURIComponent(url.pathname.slice(1)), ssl: { rejectUnauthorized: true }, max: 4 });
48
+ keyBytes(wrappingKey);
49
+ }
50
+ async close() { await this.#pool.end(); }
51
+ async verifyLegacyCollections(catalog, claims) {
52
+ const remoteCatalog = await this.#pool.query("SELECT capability_id,seller_id,blob_id,signature,transport_public_key FROM public.seller_catalog ORDER BY capability_id");
53
+ const reduced = catalog.map((row) => ({ capability_id: row.capability_id, seller_id: row.seller_id, blob_id: row.blob_id, signature: row.signature, transport_public_key: row.transport_public_key }));
54
+ if (JSON.stringify(remoteCatalog.rows) !== JSON.stringify(reduced))
55
+ fail("SELLER_IMPORT_MISMATCH", "direct Postgres catalog differs from snapshot source");
56
+ const remoteClaims = await this.#pool.query("SELECT digest,request_id,seller_id FROM public.seller_payment_claims ORDER BY digest");
57
+ if (JSON.stringify(remoteClaims.rows) !== JSON.stringify(claims))
58
+ fail("SELLER_IMPORT_MISMATCH", "direct Postgres payment claims differ from snapshot source");
59
+ }
60
+ /** Durable intent; the caller performs the network action after this returns. */
61
+ async claimOperation(sellerId, operationId, action, inputHash) {
62
+ if (!/^[a-zA-Z0-9._:-]{1,128}$/.test(operationId) || !/^[0-9a-f]{64}$/.test(inputHash) || !action)
63
+ fail("SELLER_REQUEST_INVALID", "operation identity is invalid");
64
+ const result = await this.#pool.query("INSERT INTO public.seller_operation_intents(seller_id,operation_id,action,input_hash,status) VALUES($1,$2,$3,$4,'prepared') ON CONFLICT(seller_id,operation_id) DO UPDATE SET updated_at=seller_operation_intents.updated_at RETURNING action,input_hash,status", [sellerId, operationId, action, inputHash]);
65
+ const row = result.rows[0];
66
+ if (row.action !== action || row.input_hash !== inputHash)
67
+ fail("OPERATION_ID_CONFLICT", "operation ID already identifies another seller action");
68
+ return row.status;
69
+ }
70
+ async transitionOperation(sellerId, operationId, status, evidenceHash) {
71
+ if (evidenceHash !== undefined && !/^[0-9a-f]{64}$/.test(evidenceHash))
72
+ fail("SELLER_REQUEST_INVALID", "operation evidence hash is invalid");
73
+ if (status === "confirmed" && !evidenceHash)
74
+ fail("SELLER_REQUEST_INVALID", "confirmed operation needs finalized evidence");
75
+ const client = await this.#pool.connect();
76
+ try {
77
+ await client.query("BEGIN");
78
+ const result = await client.query("SELECT status,evidence_hash FROM public.seller_operation_intents WHERE seller_id=$1 AND operation_id=$2 FOR UPDATE", [sellerId, operationId]);
79
+ const row = result.rows[0] ?? fail("OPERATION_NOT_FOUND", "seller operation intent is missing");
80
+ if (row.status === "confirmed" && (status !== "confirmed" || row.evidence_hash !== evidenceHash))
81
+ fail("OPERATION_DIGEST_CONFLICT", "confirmed operation evidence cannot change");
82
+ if (row.status !== "confirmed")
83
+ await client.query("UPDATE public.seller_operation_intents SET status=$3,evidence_hash=$4,updated_at=now() WHERE seller_id=$1 AND operation_id=$2", [sellerId, operationId, status, evidenceHash ?? null]);
84
+ await client.query("COMMIT");
85
+ }
86
+ catch (error) {
87
+ await client.query("ROLLBACK");
88
+ throw error;
89
+ }
90
+ finally {
91
+ client.release();
92
+ }
93
+ }
94
+ /** Payment digest and request ID are both unique across all hosted sellers. */
95
+ async claimPayment(digest, requestId, sellerId) {
96
+ const client = await this.#pool.connect();
97
+ try {
98
+ await client.query("BEGIN");
99
+ const result = await client.query("INSERT INTO public.seller_payment_claims(digest,request_id,seller_id) VALUES($1,$2,$3) ON CONFLICT DO NOTHING RETURNING digest,request_id,seller_id", [digest, requestId, sellerId]);
100
+ if (!result.rows.length) {
101
+ const existing = await client.query("SELECT digest,request_id,seller_id FROM public.seller_payment_claims WHERE digest=$1 OR request_id=$2", [digest, requestId]);
102
+ if (existing.rows.length !== 1 || existing.rows[0].digest !== digest || existing.rows[0].request_id !== requestId || existing.rows[0].seller_id !== sellerId)
103
+ fail("PAYMENT_CONSUMED", "payment digest or request ID is already claimed");
104
+ }
105
+ await client.query("COMMIT");
106
+ }
107
+ catch (error) {
108
+ await client.query("ROLLBACK");
109
+ throw error;
110
+ }
111
+ finally {
112
+ client.release();
113
+ }
114
+ }
115
+ /** Import is one transaction. Replays must match the original source exactly. */
116
+ async importSnapshot(snapshot, sourceRevision) {
117
+ if (snapshot.version !== 1 || !/^0x[0-9a-f]{64}$/i.test(snapshot.sellerId))
118
+ fail("SELLER_STATE_INVALID", "seller snapshot identity is invalid");
119
+ const sellerId = snapshot.sellerId, wrapping = keyBytes(this.wrappingKey);
120
+ const stateKey = Buffer.from(snapshot.files["state.key"], "base64url");
121
+ if (stateKey.length !== 32)
122
+ fail("SELLER_STATE_KEY_INVALID", "imported role key must contain 32 bytes");
123
+ const profile = Buffer.from(snapshot.files["profile.json"], "base64url"), mandate = Buffer.from(snapshot.files["mandate.json"], "base64url");
124
+ const sourceHash = hash(Buffer.from(JSON.stringify(snapshot)));
125
+ const temporary = mkdtempSync(join(tmpdir(), "supercuts-seller-import-"));
126
+ const sqlitePath = join(temporary, "state.sqlite");
127
+ writeFileSync(sqlitePath, Buffer.from(snapshot.files["state.sqlite"], "base64url"), { mode: 0o600, flag: "wx" });
128
+ const sqlite = new DatabaseSync(sqlitePath, { readOnly: true });
129
+ let records = [];
130
+ try {
131
+ // The owner-only temporary file is removed before any database connection.
132
+ const tables = sqlite.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name").all();
133
+ for (const { name } of tables) {
134
+ const columns = sqlite.prepare(`PRAGMA table_info("${name.replaceAll('"', '""')}")`).all();
135
+ const pk = columns.filter((column) => column.pk).sort((a, b) => a.pk - b.pk);
136
+ const rows = sqlite.prepare(`SELECT * FROM "${name.replaceAll('"', '""')}" ORDER BY rowid`).all();
137
+ for (let index = 0; index < rows.length; index++) {
138
+ const row = rows[index], bytes = encodeRow(row), recordId = pk.length ? JSON.stringify(pk.map((column) => row[column.name])) : `row:${index}`;
139
+ records.push({ kind: name, recordId, plaintextHash: hash(bytes), ciphertext: seal(wrapping, `seller:${sellerId}:row:${name}:${recordId}`, bytes) });
140
+ }
141
+ }
142
+ }
143
+ finally {
144
+ sqlite.close();
145
+ rmSync(temporary, { recursive: true, force: true });
146
+ }
147
+ records = records.sort((a, b) => a.kind.localeCompare(b.kind) || a.recordId.localeCompare(b.recordId));
148
+ const artifacts = Object.entries(snapshot.artifacts).sort(([a], [b]) => a.localeCompare(b)).map(([artifactKey, encoded]) => {
149
+ const bytes = Buffer.from(encoded, "base64url");
150
+ return { artifactKey, plaintextHash: hash(bytes), ciphertext: seal(wrapping, `seller:${sellerId}:artifact:${artifactKey}`, bytes) };
151
+ });
152
+ const client = await this.#pool.connect();
153
+ try {
154
+ await client.query("BEGIN");
155
+ const current = await client.query("SELECT source_hash,source_revision FROM public.seller_roles WHERE seller_id=$1 FOR UPDATE", [sellerId]);
156
+ if (current.rows.length) {
157
+ if (current.rows[0].source_hash !== sourceHash || Number(current.rows[0].source_revision) !== sourceRevision)
158
+ fail("SELLER_STATE_CONFLICT", "import source differs from the existing seller rows");
159
+ }
160
+ else {
161
+ await client.query("INSERT INTO public.seller_roles(seller_id,profile_ciphertext,mandate_ciphertext,wrapped_state_key,source_revision,source_hash) VALUES($1,$2,$3,$4,$5,$6)", [sellerId, seal(wrapping, `seller:${sellerId}:profile`, profile), seal(wrapping, `seller:${sellerId}:mandate`, mandate), seal(wrapping, `seller:${sellerId}:state-key`, stateKey), sourceRevision, sourceHash]);
162
+ }
163
+ await this.insertRecords(client, sellerId, records, artifacts);
164
+ const count = await client.query("SELECT (SELECT count(*) FROM public.seller_records WHERE seller_id=$1)::text AS records,(SELECT count(*) FROM public.seller_artifacts WHERE seller_id=$1)::text AS artifacts", [sellerId]);
165
+ if (Number(count.rows[0]?.records) !== records.length || Number(count.rows[0]?.artifacts) !== artifacts.length)
166
+ fail("SELLER_IMPORT_MISMATCH", "Postgres row count differs from snapshot");
167
+ await client.query("COMMIT");
168
+ return { records: records.length, artifacts: artifacts.length, sourceHash };
169
+ }
170
+ catch (error) {
171
+ await client.query("ROLLBACK");
172
+ throw error;
173
+ }
174
+ finally {
175
+ client.release();
176
+ }
177
+ }
178
+ async insertRecords(client, sellerId, records, artifacts) {
179
+ for (const row of records) {
180
+ const result = await client.query("INSERT INTO public.seller_records(seller_id,kind,record_id,plaintext_hash,ciphertext) VALUES($1,$2,$3,$4,$5) ON CONFLICT(seller_id,kind,record_id) DO UPDATE SET plaintext_hash=seller_records.plaintext_hash RETURNING plaintext_hash", [sellerId, row.kind, row.recordId, row.plaintextHash, row.ciphertext]);
181
+ if (result.rows[0]?.plaintext_hash !== row.plaintextHash)
182
+ fail("SELLER_IMPORT_MISMATCH", "existing seller row differs from snapshot");
183
+ }
184
+ for (const row of artifacts) {
185
+ const result = await client.query("INSERT INTO public.seller_artifacts(seller_id,artifact_key,plaintext_hash,ciphertext) VALUES($1,$2,$3,$4) ON CONFLICT(seller_id,artifact_key) DO UPDATE SET plaintext_hash=seller_artifacts.plaintext_hash RETURNING plaintext_hash", [sellerId, row.artifactKey, row.plaintextHash, row.ciphertext]);
186
+ if (result.rows[0]?.plaintext_hash !== row.plaintextHash)
187
+ fail("SELLER_IMPORT_MISMATCH", "existing seller artifact differs from snapshot");
188
+ }
189
+ }
190
+ /** Readback authenticates every encrypted row and returns only safe counts. */
191
+ async verifyImport(sellerId) {
192
+ const wrapping = keyBytes(this.wrappingKey);
193
+ const role = await this.#pool.query("SELECT source_hash,profile_ciphertext,mandate_ciphertext,wrapped_state_key FROM public.seller_roles WHERE seller_id=$1", [sellerId]);
194
+ if (role.rows.length !== 1)
195
+ fail("SELLER_STATE_MISSING", "seller role was not imported");
196
+ const value = role.rows[0];
197
+ for (const [kind, envelope] of [["profile", value.profile_ciphertext], ["mandate", value.mandate_ciphertext], ["state-key", value.wrapped_state_key]])
198
+ open(wrapping, `seller:${sellerId}:${kind}`, envelope);
199
+ const rows = await this.#pool.query("SELECT kind,record_id,plaintext_hash,ciphertext FROM public.seller_records WHERE seller_id=$1", [sellerId]);
200
+ const counts = {};
201
+ for (const row of rows.rows) {
202
+ const bytes = open(wrapping, `seller:${sellerId}:row:${row.kind}:${row.record_id}`, row.ciphertext);
203
+ if (hash(bytes) !== row.plaintext_hash)
204
+ fail("SELLER_IMPORT_MISMATCH", "seller row hash differs after readback");
205
+ decodeRow(bytes);
206
+ counts[row.kind] = (counts[row.kind] ?? 0) + 1;
207
+ }
208
+ const artifacts = await this.#pool.query("SELECT artifact_key,plaintext_hash,ciphertext FROM public.seller_artifacts WHERE seller_id=$1", [sellerId]);
209
+ for (const row of artifacts.rows)
210
+ if (hash(open(wrapping, `seller:${sellerId}:artifact:${row.artifact_key}`, row.ciphertext)) !== row.plaintext_hash)
211
+ fail("SELLER_IMPORT_MISMATCH", "seller artifact hash differs after readback");
212
+ return { sourceHash: value.source_hash, records: counts, artifacts: artifacts.rows.length };
213
+ }
214
+ }
@@ -0,0 +1,37 @@
1
+ export * from "./config.js";
2
+ export * from "./deal.js";
3
+ export * from "./deal-engine.js";
4
+ export * from "./deal-adapter.js";
5
+ export * from "./capability.js";
6
+ export * from "./claude.js";
7
+ export * from "./events.js";
8
+ export * from "./dashboard.js";
9
+ export * from "./mandate.js";
10
+ export * from "./procurement.js";
11
+ export * from "./audit.js";
12
+ export * from "./backend.js";
13
+ export * from "./errors.js";
14
+ export * from "./indexer.js";
15
+ export * from "./memory.js";
16
+ export * from "./settlement.js";
17
+ export * from "./seller-runtime.js";
18
+ export * from "./seller-stdio.js";
19
+ export * from "./live-index.js";
20
+ export * from "./live-runtime.js";
21
+ export * from "./protocol-engine.js";
22
+ export * from "./prover.js";
23
+ export * from "./phase3.js";
24
+ export * from "./memwal.js";
25
+ export * from "./negotiation.js";
26
+ export * from "./notes.js";
27
+ export * from "./resource.js";
28
+ export * from "./relayer.js";
29
+ export * from "./store.js";
30
+ export * from "./sui.js";
31
+ export * from "./tatum.js";
32
+ export * from "./transcript.js";
33
+ export * from "./x402.js";
34
+ export * from "./x402-resource-service.js";
35
+ export * from "./facilitator.js";
36
+ export * from "./wallet.js";
37
+ export * from "./workflow-memory.js";
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ export * from "./config.js";
2
+ export * from "./deal.js";
3
+ export * from "./deal-engine.js";
4
+ export * from "./deal-adapter.js";
5
+ export * from "./capability.js";
6
+ export * from "./claude.js";
7
+ export * from "./events.js";
8
+ export * from "./dashboard.js";
9
+ export * from "./mandate.js";
10
+ export * from "./procurement.js";
11
+ export * from "./audit.js";
12
+ export * from "./backend.js";
13
+ export * from "./errors.js";
14
+ export * from "./indexer.js";
15
+ export * from "./memory.js";
16
+ export * from "./settlement.js";
17
+ export * from "./seller-runtime.js";
18
+ export * from "./seller-stdio.js";
19
+ export * from "./live-index.js";
20
+ export * from "./live-runtime.js";
21
+ export * from "./protocol-engine.js";
22
+ export * from "./prover.js";
23
+ export * from "./phase3.js";
24
+ export * from "./memwal.js";
25
+ export * from "./negotiation.js";
26
+ export * from "./notes.js";
27
+ export * from "./resource.js";
28
+ export * from "./relayer.js";
29
+ export * from "./store.js";
30
+ export * from "./sui.js";
31
+ export * from "./tatum.js";
32
+ export * from "./transcript.js";
33
+ export * from "./x402.js";
34
+ export * from "./x402-resource-service.js";
35
+ export * from "./facilitator.js";
36
+ export * from "./wallet.js";
37
+ export * from "./workflow-memory.js";
@@ -0,0 +1,63 @@
1
+ export type PoolEvent = {
2
+ kind: "deposit";
3
+ checkpoint: bigint;
4
+ transactionIndex: bigint;
5
+ eventIndex: number;
6
+ oldRoot: string;
7
+ newRoot: string;
8
+ leafIndex: bigint;
9
+ noteCommitment: string;
10
+ } | {
11
+ kind: "transfer";
12
+ checkpoint: bigint;
13
+ transactionIndex: bigint;
14
+ eventIndex: number;
15
+ oldRoot: string;
16
+ newRoot: string;
17
+ firstLeafIndex: bigint;
18
+ paymentCommitment: string;
19
+ changeCommitment: string;
20
+ dealNullifier: string;
21
+ inputNullifier: string;
22
+ } | {
23
+ kind: "withdraw";
24
+ checkpoint: bigint;
25
+ transactionIndex: bigint;
26
+ eventIndex: number;
27
+ root: string;
28
+ noteNullifier: string;
29
+ recipient: string;
30
+ amount: bigint;
31
+ } | {
32
+ kind: "withdraw_v2";
33
+ checkpoint: bigint;
34
+ transactionIndex: bigint;
35
+ eventIndex: number;
36
+ oldRoot: string;
37
+ newRoot: string;
38
+ leafIndex: bigint;
39
+ noteNullifier: string;
40
+ changeCommitment: string;
41
+ recipient: string;
42
+ amount: bigint;
43
+ exactExit: boolean;
44
+ };
45
+ export interface PoolIndex {
46
+ root: string;
47
+ nextLeaf: bigint;
48
+ spent: Set<string>;
49
+ deals: Set<string>;
50
+ checkpoint: bigint;
51
+ acceptedRoots: Set<string>;
52
+ lastPosition?: {
53
+ checkpoint: bigint;
54
+ transactionIndex: bigint;
55
+ eventIndex: number;
56
+ };
57
+ }
58
+ export declare function createPoolIndex(root: string, checkpoint: bigint): PoolIndex;
59
+ export declare function applyPoolEvent(index: PoolIndex, event: PoolEvent): void;
60
+ export declare function assertPoolState(index: PoolIndex, state: {
61
+ root: string;
62
+ nextLeaf: bigint;
63
+ }): void;
@@ -0,0 +1,60 @@
1
+ import { fail } from "./errors.js";
2
+ export function createPoolIndex(root, checkpoint) { return { root, nextLeaf: 0n, spent: new Set(), deals: new Set(), acceptedRoots: new Set([root]), checkpoint }; }
3
+ function assertEventOrder(index, event) {
4
+ if (event.checkpoint < index.checkpoint || event.transactionIndex < 0n || !Number.isSafeInteger(event.eventIndex) || event.eventIndex < 0)
5
+ fail("CHAIN_ORDER_INVALID", "event position is invalid or precedes the deployment anchor");
6
+ const previous = index.lastPosition;
7
+ if (previous) {
8
+ const ordered = event.checkpoint > previous.checkpoint
9
+ || (event.checkpoint === previous.checkpoint && event.transactionIndex > previous.transactionIndex)
10
+ || (event.checkpoint === previous.checkpoint && event.transactionIndex === previous.transactionIndex && event.eventIndex > previous.eventIndex);
11
+ if (!ordered)
12
+ fail("CHAIN_ORDER_INVALID", "event positions must be unique and strictly increasing");
13
+ }
14
+ }
15
+ export function applyPoolEvent(index, event) {
16
+ assertEventOrder(index, event);
17
+ if (event.kind === "deposit") {
18
+ if (event.oldRoot !== index.root || event.leafIndex !== index.nextLeaf)
19
+ fail("POOL_TRANSITION_INVALID", "deposit root or leaf index does not match index");
20
+ index.root = event.newRoot;
21
+ index.acceptedRoots.add(event.newRoot);
22
+ index.nextLeaf += 1n;
23
+ }
24
+ else if (event.kind === "transfer") {
25
+ if (event.oldRoot !== index.root || event.firstLeafIndex !== index.nextLeaf)
26
+ fail("POOL_TRANSITION_INVALID", "transfer root or leaf index does not match index");
27
+ if (index.spent.has(event.inputNullifier) || index.deals.has(event.dealNullifier))
28
+ fail("POOL_REPLAY", "pool event reuses a consumed identity");
29
+ index.root = event.newRoot;
30
+ index.acceptedRoots.add(event.newRoot);
31
+ index.nextLeaf += 2n;
32
+ index.spent.add(event.inputNullifier);
33
+ index.deals.add(event.dealNullifier);
34
+ }
35
+ else if (event.kind === "withdraw_v2") {
36
+ if (event.oldRoot !== index.root || event.leafIndex !== index.nextLeaf)
37
+ fail("POOL_TRANSITION_INVALID", "v2 exit root or leaf index does not match index");
38
+ if (index.spent.has(event.noteNullifier))
39
+ fail("POOL_REPLAY", "v2 exit reuses a spent nullifier");
40
+ if (!event.exactExit && event.amount !== 1000000n)
41
+ fail("POOL_TRANSITION_INVALID", "v2 standard exit amount is invalid");
42
+ index.root = event.newRoot;
43
+ index.acceptedRoots.add(event.newRoot);
44
+ index.nextLeaf += 1n;
45
+ index.spent.add(event.noteNullifier);
46
+ }
47
+ else {
48
+ if (!index.acceptedRoots.has(event.root))
49
+ fail("POOL_TRANSITION_INVALID", "withdrawal references a root that was never accepted");
50
+ if (index.spent.has(event.noteNullifier))
51
+ fail("POOL_REPLAY", "withdrawal reuses a spent nullifier");
52
+ index.spent.add(event.noteNullifier);
53
+ }
54
+ index.checkpoint = event.checkpoint;
55
+ index.lastPosition = { checkpoint: event.checkpoint, transactionIndex: event.transactionIndex, eventIndex: event.eventIndex };
56
+ }
57
+ export function assertPoolState(index, state) {
58
+ if (index.root !== state.root || index.nextLeaf !== state.nextLeaf)
59
+ fail("POOL_STATE_MISMATCH", "event-derived tree does not match the pool object");
60
+ }
@@ -0,0 +1,41 @@
1
+ import { type SignedCapabilityRegistration } from "./capability.js";
2
+ import type { DealArtifact, DealNegotiation, DealPayment, DealPorts } from "./deal-engine.js";
3
+ import type { ExecuteDealInput } from "./deal.js";
4
+ import { type AgentMandate } from "./mandate.js";
5
+ import type { Phase3App } from "./phase3.js";
6
+ import { type SettlementPlanV1 } from "./settlement.js";
7
+ type LiveNegotiation = DealNegotiation & {
8
+ sessionId: string;
9
+ agreementHash: string;
10
+ agreedAmount: string;
11
+ resourceUrl?: string;
12
+ sellerOrigin: string;
13
+ sellerTransportPublicKey: string;
14
+ };
15
+ /** Built-in live buyer adapter. The owner supplies only seller catalog origins;
16
+ * signing, payment, Walrus and memory stay in the buyer role home. */
17
+ export declare class LiveDealPorts implements DealPorts {
18
+ #private;
19
+ private readonly app;
20
+ private readonly mandate;
21
+ private readonly http;
22
+ constructor(app: Phase3App, mandate: AgentMandate, http?: typeof fetch);
23
+ readBlob(blobId: string): Promise<Uint8Array>;
24
+ private signer;
25
+ private request;
26
+ catalog(): Promise<Array<{
27
+ origin: string;
28
+ registration: SignedCapabilityRegistration;
29
+ }>>;
30
+ discover(input: ExecuteDealInput): Promise<SignedCapabilityRegistration>;
31
+ plan(input: ExecuteDealInput, registration: SignedCapabilityRegistration, paymentOperationId: string): Promise<SettlementPlanV1>;
32
+ negotiate(input: ExecuteDealInput, registration: SignedCapabilityRegistration, plan: SettlementPlanV1, agreementOperationId: string): Promise<LiveNegotiation>;
33
+ pay(input: ExecuteDealInput, plan: SettlementPlanV1, negotiation: DealNegotiation, paymentOperationId: string): Promise<DealPayment>;
34
+ deliver(input: ExecuteDealInput, plan: SettlementPlanV1, negotiation: DealNegotiation, payment: DealPayment, _deliveryOperationId: string): Promise<DealArtifact>;
35
+ rememberOutcome(input: ExecuteDealInput, plan: SettlementPlanV1, payment: DealPayment, artifact: DealArtifact, _outcomeOperationId: string): Promise<{
36
+ queued: true;
37
+ payloadHash: string;
38
+ }>;
39
+ inventory(blobId: string): Promise<boolean>;
40
+ }
41
+ export {};