@opendatalabs/vana-sdk 3.16.0 → 3.18.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 (72) hide show
  1. package/README.md +107 -0
  2. package/dist/direct/personal-server-read.cjs +20 -1
  3. package/dist/direct/personal-server-read.cjs.map +1 -1
  4. package/dist/direct/personal-server-read.js +23 -1
  5. package/dist/direct/personal-server-read.js.map +1 -1
  6. package/dist/errors.cjs +121 -2
  7. package/dist/errors.cjs.map +1 -1
  8. package/dist/errors.d.ts +190 -0
  9. package/dist/errors.js +106 -1
  10. package/dist/errors.js.map +1 -1
  11. package/dist/index.browser.d.ts +5 -1
  12. package/dist/index.browser.js +1449 -58
  13. package/dist/index.browser.js.map +4 -4
  14. package/dist/index.node.cjs +1501 -59
  15. package/dist/index.node.cjs.map +4 -4
  16. package/dist/index.node.d.ts +5 -1
  17. package/dist/index.node.js +1449 -58
  18. package/dist/index.node.js.map +4 -4
  19. package/dist/protocol/data-point-deletion.cjs +220 -0
  20. package/dist/protocol/data-point-deletion.cjs.map +1 -0
  21. package/dist/protocol/data-point-deletion.d.ts +180 -0
  22. package/dist/protocol/data-point-deletion.js +193 -0
  23. package/dist/protocol/data-point-deletion.js.map +1 -0
  24. package/dist/protocol/data-point-deletion.test.d.ts +1 -0
  25. package/dist/protocol/gateway.cjs +145 -32
  26. package/dist/protocol/gateway.cjs.map +1 -1
  27. package/dist/protocol/gateway.d.ts +42 -3
  28. package/dist/protocol/gateway.js +156 -32
  29. package/dist/protocol/gateway.js.map +1 -1
  30. package/dist/protocol/lineage.cjs +287 -0
  31. package/dist/protocol/lineage.cjs.map +1 -0
  32. package/dist/protocol/lineage.d.ts +228 -0
  33. package/dist/protocol/lineage.js +258 -0
  34. package/dist/protocol/lineage.js.map +1 -0
  35. package/dist/protocol/lineage.test.d.ts +1 -0
  36. package/dist/protocol/personal-server-data.cjs +20 -1
  37. package/dist/protocol/personal-server-data.cjs.map +1 -1
  38. package/dist/protocol/personal-server-data.js +23 -1
  39. package/dist/protocol/personal-server-data.js.map +1 -1
  40. package/dist/protocol/personal-server-error-body.cjs +57 -0
  41. package/dist/protocol/personal-server-error-body.cjs.map +1 -0
  42. package/dist/protocol/personal-server-error-body.d.ts +18 -0
  43. package/dist/protocol/personal-server-error-body.js +32 -0
  44. package/dist/protocol/personal-server-error-body.js.map +1 -0
  45. package/dist/protocol/personal-server-write.cjs +623 -0
  46. package/dist/protocol/personal-server-write.cjs.map +1 -0
  47. package/dist/protocol/personal-server-write.d.ts +284 -0
  48. package/dist/protocol/personal-server-write.js +601 -0
  49. package/dist/protocol/personal-server-write.js.map +1 -0
  50. package/dist/protocol/personal-server-write.test.d.ts +1 -0
  51. package/dist/protocol/write-signer.cjs +67 -0
  52. package/dist/protocol/write-signer.cjs.map +1 -0
  53. package/dist/protocol/write-signer.d.ts +59 -0
  54. package/dist/protocol/write-signer.js +43 -0
  55. package/dist/protocol/write-signer.js.map +1 -0
  56. package/dist/protocol/write-signer.test.d.ts +1 -0
  57. package/dist/storage/index.cjs.map +1 -1
  58. package/dist/storage/index.d.ts +1 -1
  59. package/dist/storage/index.js.map +1 -1
  60. package/dist/storage/providers/vana-storage.cjs +66 -0
  61. package/dist/storage/providers/vana-storage.cjs.map +1 -1
  62. package/dist/storage/providers/vana-storage.d.ts +26 -0
  63. package/dist/storage/providers/vana-storage.js +66 -0
  64. package/dist/storage/providers/vana-storage.js.map +1 -1
  65. package/dist/tests/mock-personal-server.d.ts +127 -0
  66. package/dist/utils/response-body.cjs +46 -0
  67. package/dist/utils/response-body.cjs.map +1 -0
  68. package/dist/utils/response-body.d.ts +26 -0
  69. package/dist/utils/response-body.js +20 -0
  70. package/dist/utils/response-body.js.map +1 -0
  71. package/dist/utils/response-body.test.d.ts +1 -0
  72. package/package.json +1 -1
@@ -0,0 +1,601 @@
1
+ import { sha256 } from "@noble/hashes/sha2";
2
+ import { bytesToHex, isAddress } from "viem";
3
+ import { z } from "zod";
4
+ import { buildWeb3SignedHeader } from "../auth/web3-signed-builder.js";
5
+ import {
6
+ WriteConflictError,
7
+ WriteForbiddenError,
8
+ WriteLineageError,
9
+ WriteRejectedError,
10
+ WriteRequestError,
11
+ WriteSessionError,
12
+ WriteSessionExpiredError,
13
+ WriteTransportError,
14
+ WriteUnauthorizedError
15
+ } from "../errors.js";
16
+ import { toBase64 } from "../utils/encoding.js";
17
+ import { IngestResponseSchema } from "./data-file.js";
18
+ import {
19
+ assertDerivedScopeNaming,
20
+ deriveDataPointId,
21
+ isDataPointId
22
+ } from "./lineage.js";
23
+ import {
24
+ isRecord,
25
+ readPersonalServerErrorBody
26
+ } from "./personal-server-error-body.js";
27
+ import { scopeMatchesPattern } from "./scopes.js";
28
+ import {
29
+ resolveWriteSigner
30
+ } from "./write-signer.js";
31
+ const WRITE_SESSION_PATH = "/v1/write/session";
32
+ const WRITE_SIGNATURE_HEADER = "X-Vana-Write-Signature";
33
+ const WRITE_METADATA_HEADER = "X-Vana-Metadata";
34
+ const LINEAGE_FIELD = "lineage";
35
+ const MAX_LINEAGE_SOURCES = 256;
36
+ const WRITE_FILENAME_HEADER = "X-Filename";
37
+ const WRITE_CONTENT_DISPOSITION_HEADER = "Content-Disposition";
38
+ const WRITER_ATTRIBUTION_KEY = "$writtenBy";
39
+ const LINEAGE_KEY = "$lineage";
40
+ const RESERVED_WRITE_KEYS = [
41
+ WRITER_ATTRIBUTION_KEY,
42
+ LINEAGE_KEY
43
+ ];
44
+ const WriteDataResultSchema = IngestResponseSchema.extend({
45
+ // Present when the write carried lineage: the validated, lowercased ids.
46
+ lineage: z.object({ sources: z.array(z.string()) }).optional()
47
+ });
48
+ const WriteSessionResponseSchema = z.object({
49
+ access_token: z.string().min(1),
50
+ token_type: z.string(),
51
+ expires_in: z.number().nonnegative(),
52
+ scope: z.string()
53
+ });
54
+ function normalizeBaseUrl(url) {
55
+ return url.replace(/\/+$/, "");
56
+ }
57
+ function resolveFetch(fetchFn) {
58
+ const resolved = fetchFn ?? globalThis.fetch;
59
+ if (resolved === void 0) {
60
+ throw new WriteRequestError("No fetch implementation available");
61
+ }
62
+ return resolved;
63
+ }
64
+ function dataPath(scope) {
65
+ return `/v1/data/${encodeURIComponent(scope)}`;
66
+ }
67
+ function errorMessage(err) {
68
+ return err instanceof Error ? err.message : String(err);
69
+ }
70
+ function finiteOr(value, fallback) {
71
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
72
+ }
73
+ function sleep(ms) {
74
+ return new Promise((resolve) => setTimeout(resolve, ms));
75
+ }
76
+ const issuedProofIats = /* @__PURE__ */ new Map();
77
+ const issuedProofBuckets = /* @__PURE__ */ new Map();
78
+ let issuedProofIatsPrunedAtSec = 0;
79
+ const WEB3_SIGNED_PROOF_LIFETIME_SECONDS = 300;
80
+ const WEB3_SIGNED_CLOCK_SKEW_SECONDS = 60;
81
+ const PROOF_IAT_RETENTION_SECONDS = WEB3_SIGNED_PROOF_LIFETIME_SECONDS + WEB3_SIGNED_CLOCK_SKEW_SECONDS;
82
+ const PROOF_IAT_MAX_AHEAD_SECONDS = 30;
83
+ function pruneIssuedProofIats(nowSec) {
84
+ if (issuedProofIatsPrunedAtSec === nowSec) return;
85
+ issuedProofIatsPrunedAtSec = nowSec;
86
+ const cutoff = nowSec - PROOF_IAT_RETENTION_SECONDS;
87
+ for (const [sec, keys] of issuedProofBuckets) {
88
+ if (sec >= cutoff) continue;
89
+ for (const key of keys) issuedProofIats.delete(key);
90
+ issuedProofBuckets.delete(sec);
91
+ }
92
+ }
93
+ function setIssuedProofIat(key, iat, previous) {
94
+ if (previous !== void 0) {
95
+ const bucket2 = issuedProofBuckets.get(previous);
96
+ bucket2?.delete(key);
97
+ if (bucket2?.size === 0) issuedProofBuckets.delete(previous);
98
+ }
99
+ issuedProofIats.set(key, iat);
100
+ let bucket = issuedProofBuckets.get(iat);
101
+ if (bucket === void 0) {
102
+ bucket = /* @__PURE__ */ new Set();
103
+ issuedProofBuckets.set(iat, bucket);
104
+ }
105
+ bucket.add(key);
106
+ }
107
+ function nextProofIat(proofKey) {
108
+ const nowSec = Math.floor(Date.now() / 1e3);
109
+ pruneIssuedProofIats(nowSec);
110
+ const last = issuedProofIats.get(proofKey);
111
+ const iat = last === void 0 ? nowSec : Math.max(nowSec, last + 1);
112
+ setIssuedProofIat(proofKey, iat, last);
113
+ const waitSec = iat - nowSec - PROOF_IAT_MAX_AHEAD_SECONDS;
114
+ if (waitSec <= 0) return Promise.resolve(iat);
115
+ return sleep(waitSec * 1e3).then(() => iat);
116
+ }
117
+ function proofKeyFor(parts) {
118
+ return bytesToHex(
119
+ sha256(
120
+ new TextEncoder().encode(
121
+ JSON.stringify([
122
+ parts.aud,
123
+ parts.method,
124
+ parts.uri,
125
+ parts.grantId,
126
+ parts.signedBytes ? bytesToHex(sha256(parts.signedBytes)) : ""
127
+ ])
128
+ )
129
+ )
130
+ );
131
+ }
132
+ async function sendWithFreshProof(label, fetchFn, options, proofKey, build) {
133
+ const attempts = Math.max(1, Math.floor(finiteOr(options?.attempts, 3)));
134
+ let delayMs = Math.max(0, finiteOr(options?.initialDelayMs, 1e3));
135
+ let lastError;
136
+ for (let attempt = 0; attempt < attempts; attempt++) {
137
+ const { url, init } = await build(await nextProofIat(proofKey));
138
+ try {
139
+ return await fetchFn(url, init);
140
+ } catch (err) {
141
+ lastError = err;
142
+ }
143
+ if (attempt < attempts - 1) {
144
+ await sleep(delayMs);
145
+ delayMs *= 2;
146
+ }
147
+ }
148
+ throw new WriteTransportError(
149
+ `${label} failed after ${attempts} attempt(s): ${errorMessage(lastError)}`,
150
+ attempts,
151
+ lastError
152
+ );
153
+ }
154
+ async function openWriteSession(params) {
155
+ const fetchFn = resolveFetch(params.fetch);
156
+ const personalServerUrl = normalizeBaseUrl(params.personalServerUrl);
157
+ const audience = params.audience ?? personalServerUrl;
158
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
159
+ const response = await sendWithFreshProof(
160
+ "Write session handshake",
161
+ fetchFn,
162
+ params.retry,
163
+ proofKeyFor({
164
+ aud: audience,
165
+ method: "POST",
166
+ uri: WRITE_SESSION_PATH,
167
+ grantId: params.grantId
168
+ }),
169
+ async (iat) => {
170
+ const headers = new Headers(params.headers);
171
+ headers.set(
172
+ "Authorization",
173
+ await buildWeb3SignedHeader({
174
+ signMessage: signer.signMessage,
175
+ aud: audience,
176
+ method: "POST",
177
+ uri: WRITE_SESSION_PATH,
178
+ grantId: params.grantId,
179
+ iat
180
+ })
181
+ );
182
+ return {
183
+ url: `${personalServerUrl}${WRITE_SESSION_PATH}`,
184
+ init: { method: "POST", headers }
185
+ };
186
+ }
187
+ );
188
+ const mintedAt = Date.now();
189
+ if (!response.ok) {
190
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
191
+ throw new WriteSessionError(
192
+ message ?? `Write session handshake failed: ${response.status} ${response.statusText}`,
193
+ response.status,
194
+ errorCode,
195
+ details
196
+ );
197
+ }
198
+ let body;
199
+ try {
200
+ body = await response.json();
201
+ } catch (err) {
202
+ throw new WriteSessionError(
203
+ "Write session response is not JSON",
204
+ response.status,
205
+ null,
206
+ { cause: errorMessage(err) }
207
+ );
208
+ }
209
+ const parsed = WriteSessionResponseSchema.safeParse(body);
210
+ if (!parsed.success) {
211
+ throw new WriteSessionError(
212
+ "Write session response is not a session",
213
+ response.status,
214
+ null,
215
+ { issues: parsed.error.issues }
216
+ );
217
+ }
218
+ if (parsed.data.token_type.toLowerCase() !== "bearer") {
219
+ throw new WriteSessionError(
220
+ `Write session token type is not Bearer: ${parsed.data.token_type}`,
221
+ response.status
222
+ );
223
+ }
224
+ return {
225
+ personalServerUrl,
226
+ audience,
227
+ grantId: params.grantId,
228
+ accessToken: parsed.data.access_token,
229
+ expiresAt: mintedAt + parsed.data.expires_in * 1e3,
230
+ writeScopes: parsed.data.scope.split(" ").filter((s) => s.length > 0),
231
+ signer
232
+ };
233
+ }
234
+ function isWriteSession(value) {
235
+ if (!isRecord(value)) return false;
236
+ const signer = value.signer;
237
+ return typeof value.personalServerUrl === "string" && typeof value.audience === "string" && typeof value.grantId === "string" && typeof value.accessToken === "string" && value.accessToken.length > 0 && typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt) && Array.isArray(value.writeScopes) && value.writeScopes.every((scope) => typeof scope === "string") && isRecord(signer) && typeof signer.signMessage === "function";
238
+ }
239
+ function sessionCoversScope(session, scope) {
240
+ if (!isRecord(session) || !Array.isArray(session.writeScopes) || !session.writeScopes.every((pattern) => typeof pattern === "string")) {
241
+ throw new WriteRequestError("session must come from openWriteSession");
242
+ }
243
+ return session.writeScopes.some(
244
+ (pattern) => scopeMatchesPattern(scope, pattern)
245
+ );
246
+ }
247
+ function normalizeBinaryMimeType(contentType) {
248
+ if (!contentType) return "application/octet-stream";
249
+ return contentType.split(";")[0].trim() || "application/octet-stream";
250
+ }
251
+ function parseWriteMetadataHeader(value) {
252
+ if (value === null) return void 0;
253
+ const trimmed = value.trim();
254
+ if (trimmed === "") return void 0;
255
+ try {
256
+ return JSON.parse(trimmed);
257
+ } catch {
258
+ return value;
259
+ }
260
+ }
261
+ function encodeWriteMetadataHeader(metadata) {
262
+ let json;
263
+ try {
264
+ json = JSON.stringify(metadata);
265
+ } catch (err) {
266
+ throw new WriteRequestError(
267
+ `metadata is not JSON-serialisable: ${errorMessage(err)}`
268
+ );
269
+ }
270
+ if (typeof json !== "string") {
271
+ throw new WriteRequestError("metadata must serialise to JSON");
272
+ }
273
+ return json.replace(
274
+ /[\u007f-\uffff]/g,
275
+ (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
276
+ );
277
+ }
278
+ function binaryWriteSignedBytes(input) {
279
+ const metadata = parseWriteMetadataHeader(input.metadataHeader ?? null);
280
+ const record = {
281
+ $binary: true,
282
+ mimeType: normalizeBinaryMimeType(input.contentType),
283
+ ...input.filename ? { filename: input.filename } : {},
284
+ sizeBytes: input.bytes.length,
285
+ contentHash: bytesToHex(sha256(input.bytes)),
286
+ encoding: "base64",
287
+ content: toBase64(input.bytes),
288
+ ...metadata !== void 0 ? { metadata } : {}
289
+ };
290
+ return new TextEncoder().encode(JSON.stringify(record));
291
+ }
292
+ const PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
293
+ function setFilenameHeader(headers, filename) {
294
+ if (PRINTABLE_ASCII.test(filename)) {
295
+ headers.set(WRITE_FILENAME_HEADER, filename);
296
+ return;
297
+ }
298
+ headers.set(
299
+ WRITE_CONTENT_DISPOSITION_HEADER,
300
+ `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`
301
+ );
302
+ }
303
+ function assertNoReservedKeys(value, where) {
304
+ for (const key of RESERVED_WRITE_KEYS) {
305
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
306
+ throw new WriteRequestError(
307
+ `${where} must not contain the reserved ${key} key; the Personal Server stamps it`,
308
+ { key }
309
+ );
310
+ }
311
+ }
312
+ }
313
+ function isLineagePair(value) {
314
+ return isRecord(value) && typeof value.ownerAddress === "string" && typeof value.scope === "string";
315
+ }
316
+ function normalizeLineage(lineage, derivedScope) {
317
+ if (!Array.isArray(lineage)) {
318
+ throw new WriteRequestError("lineage must be an array of data point ids");
319
+ }
320
+ if (lineage.length > MAX_LINEAGE_SOURCES) {
321
+ throw new WriteRequestError(
322
+ `lineage lists ${lineage.length} sources; the maximum is ${MAX_LINEAGE_SOURCES}`,
323
+ { max: MAX_LINEAGE_SOURCES, count: lineage.length }
324
+ );
325
+ }
326
+ const seen = /* @__PURE__ */ new Set();
327
+ const sources = [];
328
+ const sourceScopes = [];
329
+ const ownIds = /* @__PURE__ */ new Set();
330
+ for (const entry of lineage) {
331
+ let id;
332
+ if (isLineagePair(entry)) {
333
+ if (!isAddress(entry.ownerAddress, { strict: false })) {
334
+ throw new WriteRequestError(
335
+ "lineage source ownerAddress must be an EVM address",
336
+ { ownerAddress: entry.ownerAddress }
337
+ );
338
+ }
339
+ if (entry.scope.length === 0) {
340
+ throw new WriteRequestError("lineage source scope is required");
341
+ }
342
+ id = deriveDataPointId(entry.ownerAddress, entry.scope);
343
+ sourceScopes.push(entry.scope);
344
+ ownIds.add(deriveDataPointId(entry.ownerAddress, derivedScope));
345
+ } else if (isDataPointId(entry)) {
346
+ id = entry;
347
+ } else {
348
+ throw new WriteRequestError(
349
+ "lineage entries must be 32-byte hex data point ids or { ownerAddress, scope } pairs",
350
+ { entry }
351
+ );
352
+ }
353
+ const normalized = id.toLowerCase();
354
+ if (seen.has(normalized)) {
355
+ throw new WriteRequestError("lineage must not repeat a data point id", {
356
+ dataPointId: normalized
357
+ });
358
+ }
359
+ seen.add(normalized);
360
+ sources.push(normalized);
361
+ }
362
+ for (const own of ownIds) {
363
+ if (seen.has(own)) {
364
+ throw new WriteRequestError(
365
+ "lineage must not cite the record's own data point",
366
+ { dataPointId: own, scope: derivedScope }
367
+ );
368
+ }
369
+ }
370
+ assertDerivedScopeNaming(derivedScope, sourceScopes);
371
+ return sources;
372
+ }
373
+ function assertNoLineageField(value, where) {
374
+ if (Object.prototype.hasOwnProperty.call(value, LINEAGE_FIELD)) {
375
+ throw new WriteRequestError(
376
+ `${where}.${LINEAGE_FIELD} is reserved; pass sources through the lineage option`
377
+ );
378
+ }
379
+ }
380
+ function buildMetadataHeader(metadata, sources) {
381
+ if (metadata !== void 0) {
382
+ if (!isRecord(metadata)) {
383
+ throw new WriteRequestError("metadata must be a plain object");
384
+ }
385
+ assertNoReservedKeys(metadata, "metadata");
386
+ assertNoLineageField(metadata, "metadata");
387
+ }
388
+ if (metadata === void 0 && sources === void 0) return void 0;
389
+ return encodeWriteMetadataHeader({
390
+ ...metadata ?? {},
391
+ ...sources !== void 0 ? { [LINEAGE_FIELD]: sources } : {}
392
+ });
393
+ }
394
+ function prepareWrite(params) {
395
+ if (params.binary !== void 0 && params.data !== void 0) {
396
+ throw new WriteRequestError("Pass either data or binary, not both");
397
+ }
398
+ const rawLineage = params.lineage;
399
+ const sources = rawLineage === void 0 || rawLineage === null ? void 0 : normalizeLineage(rawLineage, params.scope);
400
+ if (params.binary !== void 0) {
401
+ const { bytes, contentType, filename } = params.binary;
402
+ if (!(bytes instanceof Uint8Array)) {
403
+ throw new WriteRequestError("binary.bytes must be a Uint8Array");
404
+ }
405
+ if (typeof contentType !== "string" || contentType.trim() === "") {
406
+ throw new WriteRequestError("binary.contentType is required");
407
+ }
408
+ if (filename !== void 0) {
409
+ if (typeof filename !== "string") {
410
+ throw new WriteRequestError("binary.filename must be a string");
411
+ }
412
+ if (filename !== filename.trim()) {
413
+ throw new WriteRequestError(
414
+ "binary.filename must not have leading or trailing whitespace"
415
+ );
416
+ }
417
+ }
418
+ const metadataHeader = buildMetadataHeader(params.metadata, sources);
419
+ return {
420
+ body: bytes,
421
+ signedBytes: binaryWriteSignedBytes({
422
+ bytes,
423
+ contentType,
424
+ filename,
425
+ metadataHeader
426
+ }),
427
+ contentType,
428
+ filename,
429
+ metadataHeader
430
+ };
431
+ }
432
+ if (params.data === void 0) {
433
+ throw new WriteRequestError("Pass data (a JSON object) or binary");
434
+ }
435
+ if (!isRecord(params.data)) {
436
+ throw new WriteRequestError("data must be a plain JSON object");
437
+ }
438
+ if (params.metadata !== void 0) {
439
+ throw new WriteRequestError(
440
+ "metadata applies to binary writes; put fields to store inside data"
441
+ );
442
+ }
443
+ assertNoReservedKeys(params.data, "data");
444
+ assertNoLineageField(params.data, "data");
445
+ const record = sources === void 0 ? params.data : { ...params.data, [LINEAGE_FIELD]: sources };
446
+ let text;
447
+ try {
448
+ text = JSON.stringify(record);
449
+ } catch (err) {
450
+ throw new WriteRequestError(
451
+ `data is not JSON-serialisable: ${errorMessage(err)}`
452
+ );
453
+ }
454
+ if (typeof text !== "string" || !text.startsWith("{")) {
455
+ throw new WriteRequestError("data must serialise to a JSON object");
456
+ }
457
+ const body = new TextEncoder().encode(text);
458
+ return {
459
+ body,
460
+ signedBytes: body,
461
+ contentType: "application/json"
462
+ };
463
+ }
464
+ async function writeErrorFromResponse(response) {
465
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
466
+ const text = message ?? `Personal Server write failed: ${response.status} ${response.statusText}`;
467
+ if (response.status === 422 || errorCode?.startsWith("LINEAGE_")) {
468
+ return new WriteLineageError(text, response.status, errorCode, details);
469
+ }
470
+ switch (response.status) {
471
+ case 401:
472
+ return new WriteUnauthorizedError(text, errorCode, details);
473
+ case 403:
474
+ return new WriteForbiddenError(text, errorCode, details);
475
+ case 409:
476
+ return new WriteConflictError(text, errorCode, details);
477
+ default:
478
+ return new WriteRejectedError(text, response.status, errorCode, details);
479
+ }
480
+ }
481
+ async function writeData(params) {
482
+ const { session } = params;
483
+ if (!isWriteSession(session)) {
484
+ throw new WriteRequestError("session must come from openWriteSession");
485
+ }
486
+ const fetchFn = resolveFetch(params.fetch);
487
+ if (typeof params.scope !== "string" || params.scope.length === 0) {
488
+ throw new WriteRequestError("scope is required");
489
+ }
490
+ const prepared = prepareWrite(params);
491
+ if (Date.now() >= session.expiresAt) {
492
+ throw new WriteSessionExpiredError(
493
+ "Write session has expired; open a new session",
494
+ { grantId: session.grantId, expiresAt: session.expiresAt }
495
+ );
496
+ }
497
+ const path = dataPath(params.scope);
498
+ const response = await sendWithFreshProof(
499
+ `Write to ${params.scope}`,
500
+ fetchFn,
501
+ params.retry,
502
+ proofKeyFor({
503
+ aud: session.audience,
504
+ method: "POST",
505
+ uri: path,
506
+ grantId: session.grantId,
507
+ signedBytes: prepared.signedBytes
508
+ }),
509
+ async (iat) => {
510
+ const headers = new Headers(params.headers);
511
+ headers.set("Content-Type", prepared.contentType);
512
+ headers.set("Authorization", `Bearer ${session.accessToken}`);
513
+ if (prepared.filename) {
514
+ setFilenameHeader(headers, prepared.filename);
515
+ }
516
+ if (prepared.metadataHeader !== void 0) {
517
+ headers.set(WRITE_METADATA_HEADER, prepared.metadataHeader);
518
+ }
519
+ headers.set(
520
+ WRITE_SIGNATURE_HEADER,
521
+ await buildWeb3SignedHeader({
522
+ signMessage: session.signer.signMessage,
523
+ aud: session.audience,
524
+ method: "POST",
525
+ uri: path,
526
+ body: prepared.signedBytes,
527
+ grantId: session.grantId,
528
+ iat
529
+ })
530
+ );
531
+ return {
532
+ url: `${session.personalServerUrl}${path}`,
533
+ init: {
534
+ method: "POST",
535
+ headers,
536
+ body: prepared.body
537
+ }
538
+ };
539
+ }
540
+ );
541
+ if (!response.ok) {
542
+ throw await writeErrorFromResponse(response);
543
+ }
544
+ let body;
545
+ try {
546
+ body = await response.json();
547
+ } catch (err) {
548
+ throw new WriteRejectedError(
549
+ "Personal Server write response is not JSON",
550
+ response.status,
551
+ null,
552
+ { cause: errorMessage(err) }
553
+ );
554
+ }
555
+ const parsed = WriteDataResultSchema.safeParse(body);
556
+ if (!parsed.success) {
557
+ throw new WriteRejectedError(
558
+ "Personal Server write response is not an ingest result",
559
+ response.status,
560
+ null,
561
+ { issues: parsed.error.issues }
562
+ );
563
+ }
564
+ return parsed.data;
565
+ }
566
+ async function writePersonalServerData(params) {
567
+ const session = await openWriteSession({
568
+ personalServerUrl: params.personalServerUrl,
569
+ signer: params.signer,
570
+ grantId: params.grantId,
571
+ account: params.account,
572
+ audience: params.audience,
573
+ fetch: params.fetch,
574
+ headers: params.headers,
575
+ retry: params.retry
576
+ });
577
+ const writeParams = { ...params, session };
578
+ const result = await writeData(writeParams);
579
+ return { ...result, session };
580
+ }
581
+ export {
582
+ LINEAGE_FIELD,
583
+ LINEAGE_KEY,
584
+ MAX_LINEAGE_SOURCES,
585
+ RESERVED_WRITE_KEYS,
586
+ WRITER_ATTRIBUTION_KEY,
587
+ WRITE_CONTENT_DISPOSITION_HEADER,
588
+ WRITE_FILENAME_HEADER,
589
+ WRITE_METADATA_HEADER,
590
+ WRITE_SESSION_PATH,
591
+ WRITE_SIGNATURE_HEADER,
592
+ binaryWriteSignedBytes,
593
+ encodeWriteMetadataHeader,
594
+ normalizeBinaryMimeType,
595
+ openWriteSession,
596
+ parseWriteMetadataHeader,
597
+ sessionCoversScope,
598
+ writeData,
599
+ writePersonalServerData
600
+ };
601
+ //# sourceMappingURL=personal-server-write.js.map