@arke-institute/sdk 0.1.3 → 2.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 (66) hide show
  1. package/README.md +222 -176
  2. package/dist/crypto-CQnwqWQn.d.ts +459 -0
  3. package/dist/crypto-iYgzUi77.d.cts +459 -0
  4. package/dist/generated/index.cjs +19 -0
  5. package/dist/generated/index.cjs.map +1 -0
  6. package/dist/generated/index.d.cts +6545 -0
  7. package/dist/generated/index.d.ts +6545 -0
  8. package/dist/generated/index.js +1 -0
  9. package/dist/generated/index.js.map +1 -0
  10. package/dist/index.cjs +725 -4248
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +62 -7
  13. package/dist/index.d.ts +62 -7
  14. package/dist/index.js +706 -4221
  15. package/dist/index.js.map +1 -1
  16. package/dist/operations/index.cjs +806 -0
  17. package/dist/operations/index.cjs.map +1 -0
  18. package/dist/operations/index.d.cts +157 -0
  19. package/dist/operations/index.d.ts +157 -0
  20. package/dist/operations/index.js +759 -0
  21. package/dist/operations/index.js.map +1 -0
  22. package/openapi/spec.json +8648 -0
  23. package/openapi/version.json +7 -0
  24. package/package.json +51 -52
  25. package/dist/client-dAk3E64p.d.cts +0 -183
  26. package/dist/client-dAk3E64p.d.ts +0 -183
  27. package/dist/collections/index.cjs +0 -233
  28. package/dist/collections/index.cjs.map +0 -1
  29. package/dist/collections/index.d.cts +0 -9
  30. package/dist/collections/index.d.ts +0 -9
  31. package/dist/collections/index.js +0 -205
  32. package/dist/collections/index.js.map +0 -1
  33. package/dist/content/index.cjs +0 -591
  34. package/dist/content/index.cjs.map +0 -1
  35. package/dist/content/index.d.cts +0 -516
  36. package/dist/content/index.d.ts +0 -516
  37. package/dist/content/index.js +0 -558
  38. package/dist/content/index.js.map +0 -1
  39. package/dist/edit/index.cjs +0 -1503
  40. package/dist/edit/index.cjs.map +0 -1
  41. package/dist/edit/index.d.cts +0 -78
  42. package/dist/edit/index.d.ts +0 -78
  43. package/dist/edit/index.js +0 -1447
  44. package/dist/edit/index.js.map +0 -1
  45. package/dist/errors-3L7IiHcr.d.cts +0 -480
  46. package/dist/errors-BTe8GKRQ.d.ts +0 -480
  47. package/dist/errors-CT7yzKkU.d.cts +0 -874
  48. package/dist/errors-CT7yzKkU.d.ts +0 -874
  49. package/dist/graph/index.cjs +0 -427
  50. package/dist/graph/index.cjs.map +0 -1
  51. package/dist/graph/index.d.cts +0 -485
  52. package/dist/graph/index.d.ts +0 -485
  53. package/dist/graph/index.js +0 -396
  54. package/dist/graph/index.js.map +0 -1
  55. package/dist/query/index.cjs +0 -356
  56. package/dist/query/index.cjs.map +0 -1
  57. package/dist/query/index.d.cts +0 -636
  58. package/dist/query/index.d.ts +0 -636
  59. package/dist/query/index.js +0 -328
  60. package/dist/query/index.js.map +0 -1
  61. package/dist/upload/index.cjs +0 -1634
  62. package/dist/upload/index.cjs.map +0 -1
  63. package/dist/upload/index.d.cts +0 -150
  64. package/dist/upload/index.d.ts +0 -150
  65. package/dist/upload/index.js +0 -1597
  66. package/dist/upload/index.js.map +0 -1
@@ -1,1447 +0,0 @@
1
- // src/edit/types.ts
2
- var DEFAULT_RETRY_CONFIG = {
3
- maxRetries: 10,
4
- baseDelay: 100,
5
- maxDelay: 5e3,
6
- jitterFactor: 0.3
7
- };
8
-
9
- // src/edit/errors.ts
10
- var EditError = class extends Error {
11
- constructor(message, code = "UNKNOWN_ERROR", details) {
12
- super(message);
13
- this.code = code;
14
- this.details = details;
15
- this.name = "EditError";
16
- }
17
- };
18
- var EntityNotFoundError = class extends EditError {
19
- constructor(id) {
20
- super(`Entity not found: ${id}`, "ENTITY_NOT_FOUND", { id });
21
- this.name = "EntityNotFoundError";
22
- }
23
- };
24
- var CASConflictError = class extends EditError {
25
- constructor(id, expectedTip, actualTip) {
26
- super(
27
- `CAS conflict: entity ${id} was modified (expected ${expectedTip}, got ${actualTip})`,
28
- "CAS_CONFLICT",
29
- { id, expectedTip, actualTip }
30
- );
31
- this.name = "CASConflictError";
32
- }
33
- };
34
- var EntityExistsError = class extends EditError {
35
- constructor(id) {
36
- super(`Entity already exists: ${id}`, "ENTITY_EXISTS", { id });
37
- this.name = "EntityExistsError";
38
- }
39
- };
40
- var MergeError = class extends EditError {
41
- constructor(message, sourceId, targetId) {
42
- super(message, "MERGE_ERROR", { sourceId, targetId });
43
- this.name = "MergeError";
44
- }
45
- };
46
- var UnmergeError = class extends EditError {
47
- constructor(message, sourceId, targetId) {
48
- super(message, "UNMERGE_ERROR", { sourceId, targetId });
49
- this.name = "UnmergeError";
50
- }
51
- };
52
- var DeleteError = class extends EditError {
53
- constructor(message, id) {
54
- super(message, "DELETE_ERROR", { id });
55
- this.name = "DeleteError";
56
- }
57
- };
58
- var UndeleteError = class extends EditError {
59
- constructor(message, id) {
60
- super(message, "UNDELETE_ERROR", { id });
61
- this.name = "UndeleteError";
62
- }
63
- };
64
- var ReprocessError = class extends EditError {
65
- constructor(message, batchId) {
66
- super(message, "REPROCESS_ERROR", { batchId });
67
- this.name = "ReprocessError";
68
- }
69
- };
70
- var ValidationError = class extends EditError {
71
- constructor(message, field) {
72
- super(message, "VALIDATION_ERROR", { field });
73
- this.name = "ValidationError";
74
- }
75
- };
76
- var PermissionError = class extends EditError {
77
- constructor(message, id) {
78
- super(message, "PERMISSION_DENIED", { id });
79
- this.name = "PermissionError";
80
- }
81
- };
82
- var NetworkError = class extends EditError {
83
- constructor(message, statusCode) {
84
- super(message, "NETWORK_ERROR", { statusCode });
85
- this.name = "NetworkError";
86
- }
87
- };
88
- var ContentNotFoundError = class extends EditError {
89
- constructor(cid) {
90
- super(`Content not found: ${cid}`, "CONTENT_NOT_FOUND", { cid });
91
- this.name = "ContentNotFoundError";
92
- }
93
- };
94
- var IPFSError = class extends EditError {
95
- constructor(message) {
96
- super(message, "IPFS_ERROR");
97
- this.name = "IPFSError";
98
- }
99
- };
100
- var BackendError = class extends EditError {
101
- constructor(message) {
102
- super(message, "BACKEND_ERROR");
103
- this.name = "BackendError";
104
- }
105
- };
106
-
107
- // src/edit/client.ts
108
- var RETRYABLE_STATUS_CODES = [409, 503];
109
- var RETRYABLE_ERRORS = ["ECONNRESET", "ETIMEDOUT", "fetch failed"];
110
- var EditClient = class {
111
- constructor(config) {
112
- this.gatewayUrl = config.gatewayUrl.replace(/\/$/, "");
113
- this.authToken = config.authToken;
114
- this.network = config.network || "main";
115
- this.userId = config.userId;
116
- this.retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config.retryConfig };
117
- this.statusUrlTransform = config.statusUrlTransform;
118
- this.apiPrefix = config.apiPrefix ?? "/api";
119
- }
120
- // ===========================================================================
121
- // Configuration Methods
122
- // ===========================================================================
123
- /**
124
- * Update the auth token (useful for token refresh)
125
- */
126
- setAuthToken(token) {
127
- this.authToken = token;
128
- }
129
- /**
130
- * Set the network (main or test)
131
- */
132
- setNetwork(network) {
133
- this.network = network;
134
- }
135
- /**
136
- * Set the user ID for permission checks
137
- */
138
- setUserId(userId) {
139
- this.userId = userId;
140
- }
141
- // ===========================================================================
142
- // Internal Helpers
143
- // ===========================================================================
144
- /**
145
- * Build URL with API prefix
146
- */
147
- buildUrl(path) {
148
- return `${this.gatewayUrl}${this.apiPrefix}${path}`;
149
- }
150
- sleep(ms) {
151
- return new Promise((resolve) => setTimeout(resolve, ms));
152
- }
153
- getHeaders(contentType = "application/json") {
154
- const headers = {};
155
- if (contentType) {
156
- headers["Content-Type"] = contentType;
157
- }
158
- if (this.authToken) {
159
- headers["Authorization"] = `Bearer ${this.authToken}`;
160
- }
161
- headers["X-Arke-Network"] = this.network;
162
- if (this.userId) {
163
- headers["X-User-Id"] = this.userId;
164
- }
165
- return headers;
166
- }
167
- calculateDelay(attempt) {
168
- const { baseDelay, maxDelay, jitterFactor } = this.retryConfig;
169
- const exponentialDelay = baseDelay * Math.pow(2, attempt);
170
- const cappedDelay = Math.min(exponentialDelay, maxDelay);
171
- const jitter = cappedDelay * jitterFactor * (Math.random() * 2 - 1);
172
- return Math.max(0, cappedDelay + jitter);
173
- }
174
- isRetryableStatus(status) {
175
- return RETRYABLE_STATUS_CODES.includes(status);
176
- }
177
- isRetryableError(error) {
178
- const message = error.message.toLowerCase();
179
- return RETRYABLE_ERRORS.some((e) => message.includes(e.toLowerCase()));
180
- }
181
- /**
182
- * Execute a fetch with exponential backoff retry on transient errors
183
- */
184
- async fetchWithRetry(url, options, context) {
185
- let lastError = null;
186
- for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {
187
- try {
188
- const response = await fetch(url, options);
189
- if (this.isRetryableStatus(response.status) && attempt < this.retryConfig.maxRetries) {
190
- const delay = this.calculateDelay(attempt);
191
- lastError = new Error(`${context}: ${response.status} ${response.statusText}`);
192
- await this.sleep(delay);
193
- continue;
194
- }
195
- return response;
196
- } catch (error) {
197
- lastError = error;
198
- if (this.isRetryableError(lastError) && attempt < this.retryConfig.maxRetries) {
199
- const delay = this.calculateDelay(attempt);
200
- await this.sleep(delay);
201
- continue;
202
- }
203
- throw new NetworkError(lastError.message);
204
- }
205
- }
206
- throw lastError || new NetworkError("Request failed after retries");
207
- }
208
- /**
209
- * Handle common error responses and throw appropriate error types
210
- */
211
- async handleErrorResponse(response, context) {
212
- let errorData = {};
213
- try {
214
- errorData = await response.json();
215
- } catch {
216
- }
217
- const message = errorData.message || `${context}: ${response.statusText}`;
218
- const errorCode = errorData.error || "";
219
- switch (response.status) {
220
- case 400:
221
- throw new ValidationError(message);
222
- case 403:
223
- throw new PermissionError(message);
224
- case 404:
225
- throw new EntityNotFoundError(message);
226
- case 409:
227
- if (errorCode === "CAS_FAILURE") {
228
- const details = errorData.details;
229
- throw new CASConflictError(
230
- context,
231
- details?.expect || "unknown",
232
- details?.actual || "unknown"
233
- );
234
- }
235
- if (errorCode === "CONFLICT") {
236
- throw new EntityExistsError(message);
237
- }
238
- throw new EditError(message, errorCode, errorData.details);
239
- case 503:
240
- if (errorCode === "IPFS_ERROR") {
241
- throw new IPFSError(message);
242
- }
243
- if (errorCode === "BACKEND_ERROR") {
244
- throw new BackendError(message);
245
- }
246
- throw new NetworkError(message, response.status);
247
- default:
248
- throw new EditError(message, errorCode || "API_ERROR", { status: response.status });
249
- }
250
- }
251
- // ===========================================================================
252
- // Entity CRUD Operations
253
- // ===========================================================================
254
- /**
255
- * Create a new entity
256
- */
257
- async createEntity(request) {
258
- const url = this.buildUrl("/entities");
259
- const response = await this.fetchWithRetry(
260
- url,
261
- {
262
- method: "POST",
263
- headers: this.getHeaders(),
264
- body: JSON.stringify(request)
265
- },
266
- "Create entity"
267
- );
268
- if (!response.ok) {
269
- await this.handleErrorResponse(response, "Create entity");
270
- }
271
- return response.json();
272
- }
273
- /**
274
- * Get an entity by ID
275
- */
276
- async getEntity(id) {
277
- const url = this.buildUrl(`/entities/${encodeURIComponent(id)}`);
278
- const response = await this.fetchWithRetry(
279
- url,
280
- { headers: this.getHeaders() },
281
- `Get entity ${id}`
282
- );
283
- if (!response.ok) {
284
- await this.handleErrorResponse(response, `Get entity ${id}`);
285
- }
286
- return response.json();
287
- }
288
- /**
289
- * List entities with pagination
290
- */
291
- async listEntities(options = {}) {
292
- const params = new URLSearchParams();
293
- if (options.limit) params.set("limit", options.limit.toString());
294
- if (options.cursor) params.set("cursor", options.cursor);
295
- if (options.include_metadata) params.set("include_metadata", "true");
296
- const queryString = params.toString();
297
- const url = this.buildUrl(`/entities${queryString ? `?${queryString}` : ""}`);
298
- const response = await this.fetchWithRetry(url, { headers: this.getHeaders() }, "List entities");
299
- if (!response.ok) {
300
- await this.handleErrorResponse(response, "List entities");
301
- }
302
- return response.json();
303
- }
304
- /**
305
- * Update an entity (append new version)
306
- */
307
- async updateEntity(id, update) {
308
- const url = this.buildUrl(`/entities/${encodeURIComponent(id)}/versions`);
309
- const response = await this.fetchWithRetry(
310
- url,
311
- {
312
- method: "POST",
313
- headers: this.getHeaders(),
314
- body: JSON.stringify(update)
315
- },
316
- `Update entity ${id}`
317
- );
318
- if (!response.ok) {
319
- await this.handleErrorResponse(response, `Update entity ${id}`);
320
- }
321
- return response.json();
322
- }
323
- // ===========================================================================
324
- // Version Operations
325
- // ===========================================================================
326
- /**
327
- * List version history for an entity
328
- */
329
- async listVersions(id, options = {}) {
330
- const params = new URLSearchParams();
331
- if (options.limit) params.set("limit", options.limit.toString());
332
- if (options.cursor) params.set("cursor", options.cursor);
333
- const queryString = params.toString();
334
- const url = this.buildUrl(`/entities/${encodeURIComponent(id)}/versions${queryString ? `?${queryString}` : ""}`);
335
- const response = await this.fetchWithRetry(url, { headers: this.getHeaders() }, `List versions for ${id}`);
336
- if (!response.ok) {
337
- await this.handleErrorResponse(response, `List versions for ${id}`);
338
- }
339
- return response.json();
340
- }
341
- /**
342
- * Get a specific version of an entity
343
- */
344
- async getVersion(id, selector) {
345
- const url = this.buildUrl(`/entities/${encodeURIComponent(id)}/versions/${encodeURIComponent(selector)}`);
346
- const response = await this.fetchWithRetry(
347
- url,
348
- { headers: this.getHeaders() },
349
- `Get version ${selector} for ${id}`
350
- );
351
- if (!response.ok) {
352
- await this.handleErrorResponse(response, `Get version ${selector} for ${id}`);
353
- }
354
- return response.json();
355
- }
356
- /**
357
- * Resolve an entity ID to its current tip CID (fast lookup)
358
- */
359
- async resolve(id) {
360
- const url = this.buildUrl(`/resolve/${encodeURIComponent(id)}`);
361
- const response = await this.fetchWithRetry(
362
- url,
363
- { headers: this.getHeaders() },
364
- `Resolve ${id}`
365
- );
366
- if (!response.ok) {
367
- await this.handleErrorResponse(response, `Resolve ${id}`);
368
- }
369
- return response.json();
370
- }
371
- // ===========================================================================
372
- // Hierarchy Operations
373
- // ===========================================================================
374
- /**
375
- * Update parent-child hierarchy relationships
376
- */
377
- async updateHierarchy(request) {
378
- const apiRequest = {
379
- parent_pi: request.parent_id,
380
- expect_tip: request.expect_tip,
381
- add_children: request.add_children,
382
- remove_children: request.remove_children,
383
- note: request.note
384
- };
385
- const url = this.buildUrl("/hierarchy");
386
- const response = await this.fetchWithRetry(
387
- url,
388
- {
389
- method: "POST",
390
- headers: this.getHeaders(),
391
- body: JSON.stringify(apiRequest)
392
- },
393
- `Update hierarchy for ${request.parent_id}`
394
- );
395
- if (!response.ok) {
396
- await this.handleErrorResponse(response, `Update hierarchy for ${request.parent_id}`);
397
- }
398
- return response.json();
399
- }
400
- // ===========================================================================
401
- // Merge Operations
402
- // ===========================================================================
403
- /**
404
- * Merge source entity into target entity
405
- */
406
- async mergeEntity(sourceId, request) {
407
- const url = this.buildUrl(`/entities/${encodeURIComponent(sourceId)}/merge`);
408
- const response = await this.fetchWithRetry(
409
- url,
410
- {
411
- method: "POST",
412
- headers: this.getHeaders(),
413
- body: JSON.stringify(request)
414
- },
415
- `Merge ${sourceId} into ${request.target_id}`
416
- );
417
- if (!response.ok) {
418
- try {
419
- const error = await response.json();
420
- throw new MergeError(
421
- error.message || `Merge failed: ${response.statusText}`,
422
- sourceId,
423
- request.target_id
424
- );
425
- } catch (e) {
426
- if (e instanceof MergeError) throw e;
427
- await this.handleErrorResponse(response, `Merge ${sourceId}`);
428
- }
429
- }
430
- return response.json();
431
- }
432
- /**
433
- * Unmerge (restore) a previously merged entity
434
- */
435
- async unmergeEntity(sourceId, request) {
436
- const url = this.buildUrl(`/entities/${encodeURIComponent(sourceId)}/unmerge`);
437
- const response = await this.fetchWithRetry(
438
- url,
439
- {
440
- method: "POST",
441
- headers: this.getHeaders(),
442
- body: JSON.stringify(request)
443
- },
444
- `Unmerge ${sourceId}`
445
- );
446
- if (!response.ok) {
447
- try {
448
- const error = await response.json();
449
- throw new UnmergeError(
450
- error.message || `Unmerge failed: ${response.statusText}`,
451
- sourceId,
452
- request.target_id
453
- );
454
- } catch (e) {
455
- if (e instanceof UnmergeError) throw e;
456
- await this.handleErrorResponse(response, `Unmerge ${sourceId}`);
457
- }
458
- }
459
- return response.json();
460
- }
461
- // ===========================================================================
462
- // Delete Operations
463
- // ===========================================================================
464
- /**
465
- * Soft delete an entity (creates tombstone, preserves history)
466
- */
467
- async deleteEntity(id, request) {
468
- const url = this.buildUrl(`/entities/${encodeURIComponent(id)}/delete`);
469
- const response = await this.fetchWithRetry(
470
- url,
471
- {
472
- method: "POST",
473
- headers: this.getHeaders(),
474
- body: JSON.stringify(request)
475
- },
476
- `Delete ${id}`
477
- );
478
- if (!response.ok) {
479
- try {
480
- const error = await response.json();
481
- throw new DeleteError(error.message || `Delete failed: ${response.statusText}`, id);
482
- } catch (e) {
483
- if (e instanceof DeleteError) throw e;
484
- await this.handleErrorResponse(response, `Delete ${id}`);
485
- }
486
- }
487
- return response.json();
488
- }
489
- /**
490
- * Restore a deleted entity
491
- */
492
- async undeleteEntity(id, request) {
493
- const url = this.buildUrl(`/entities/${encodeURIComponent(id)}/undelete`);
494
- const response = await this.fetchWithRetry(
495
- url,
496
- {
497
- method: "POST",
498
- headers: this.getHeaders(),
499
- body: JSON.stringify(request)
500
- },
501
- `Undelete ${id}`
502
- );
503
- if (!response.ok) {
504
- try {
505
- const error = await response.json();
506
- throw new UndeleteError(error.message || `Undelete failed: ${response.statusText}`, id);
507
- } catch (e) {
508
- if (e instanceof UndeleteError) throw e;
509
- await this.handleErrorResponse(response, `Undelete ${id}`);
510
- }
511
- }
512
- return response.json();
513
- }
514
- // ===========================================================================
515
- // Content Operations
516
- // ===========================================================================
517
- /**
518
- * Upload files to IPFS
519
- */
520
- async upload(files) {
521
- let formData;
522
- if (files instanceof FormData) {
523
- formData = files;
524
- } else {
525
- formData = new FormData();
526
- const fileArray = Array.isArray(files) ? files : [files];
527
- for (const file of fileArray) {
528
- if (file instanceof File) {
529
- formData.append("file", file, file.name);
530
- } else {
531
- formData.append("file", file, "file");
532
- }
533
- }
534
- }
535
- const url = this.buildUrl("/upload");
536
- const response = await this.fetchWithRetry(
537
- url,
538
- {
539
- method: "POST",
540
- headers: this.getHeaders(null),
541
- // No Content-Type for multipart
542
- body: formData
543
- },
544
- "Upload files"
545
- );
546
- if (!response.ok) {
547
- await this.handleErrorResponse(response, "Upload files");
548
- }
549
- return response.json();
550
- }
551
- /**
552
- * Upload text content and return CID
553
- */
554
- async uploadContent(content, filename) {
555
- const blob = new Blob([content], { type: "text/plain" });
556
- const file = new File([blob], filename, { type: "text/plain" });
557
- const [result] = await this.upload(file);
558
- return result.cid;
559
- }
560
- /**
561
- * Download file content by CID
562
- */
563
- async getContent(cid) {
564
- const url = this.buildUrl(`/cat/${encodeURIComponent(cid)}`);
565
- const response = await this.fetchWithRetry(
566
- url,
567
- { headers: this.getHeaders() },
568
- `Get content ${cid}`
569
- );
570
- if (response.status === 404) {
571
- throw new ContentNotFoundError(cid);
572
- }
573
- if (!response.ok) {
574
- await this.handleErrorResponse(response, `Get content ${cid}`);
575
- }
576
- return response.text();
577
- }
578
- /**
579
- * Download a DAG node (JSON) by CID
580
- */
581
- async getDag(cid) {
582
- const url = this.buildUrl(`/dag/${encodeURIComponent(cid)}`);
583
- const response = await this.fetchWithRetry(
584
- url,
585
- { headers: this.getHeaders() },
586
- `Get DAG ${cid}`
587
- );
588
- if (response.status === 404) {
589
- throw new ContentNotFoundError(cid);
590
- }
591
- if (!response.ok) {
592
- await this.handleErrorResponse(response, `Get DAG ${cid}`);
593
- }
594
- return response.json();
595
- }
596
- // ===========================================================================
597
- // Arke Origin Operations
598
- // ===========================================================================
599
- /**
600
- * Get the Arke origin block (genesis entity)
601
- */
602
- async getArke() {
603
- const url = this.buildUrl("/arke");
604
- const response = await this.fetchWithRetry(
605
- url,
606
- { headers: this.getHeaders() },
607
- "Get Arke"
608
- );
609
- if (!response.ok) {
610
- await this.handleErrorResponse(response, "Get Arke");
611
- }
612
- return response.json();
613
- }
614
- /**
615
- * Initialize the Arke origin block (creates if doesn't exist)
616
- */
617
- async initArke() {
618
- const url = this.buildUrl("/arke/init");
619
- const response = await this.fetchWithRetry(
620
- url,
621
- {
622
- method: "POST",
623
- headers: this.getHeaders()
624
- },
625
- "Init Arke"
626
- );
627
- if (!response.ok) {
628
- await this.handleErrorResponse(response, "Init Arke");
629
- }
630
- return response.json();
631
- }
632
- // ===========================================================================
633
- // Reprocess API Operations (via /reprocess/*)
634
- // ===========================================================================
635
- /**
636
- * Trigger reprocessing for an entity
637
- */
638
- async reprocess(request) {
639
- const response = await this.fetchWithRetry(
640
- `${this.gatewayUrl}/reprocess/reprocess`,
641
- {
642
- method: "POST",
643
- headers: this.getHeaders(),
644
- body: JSON.stringify({
645
- pi: request.pi,
646
- phases: request.phases,
647
- cascade: request.cascade,
648
- options: request.options
649
- })
650
- },
651
- `Reprocess ${request.pi}`
652
- );
653
- if (response.status === 403) {
654
- const error = await response.json().catch(() => ({}));
655
- throw new PermissionError(
656
- error.message || `Permission denied to reprocess ${request.pi}`,
657
- request.pi
658
- );
659
- }
660
- if (!response.ok) {
661
- const error = await response.json().catch(() => ({}));
662
- throw new ReprocessError(error.message || `Reprocess failed: ${response.statusText}`);
663
- }
664
- return response.json();
665
- }
666
- /**
667
- * Get reprocessing status by batch ID
668
- */
669
- async getReprocessStatus(statusUrl, isFirstPoll = false) {
670
- const fetchUrl = this.statusUrlTransform ? this.statusUrlTransform(statusUrl) : statusUrl;
671
- const delay = isFirstPoll ? 3e3 : this.retryConfig.baseDelay;
672
- if (isFirstPoll) {
673
- await this.sleep(delay);
674
- }
675
- const response = await this.fetchWithRetry(
676
- fetchUrl,
677
- { headers: this.getHeaders() },
678
- "Get reprocess status"
679
- );
680
- if (!response.ok) {
681
- throw new EditError(
682
- `Failed to fetch reprocess status: ${response.statusText}`,
683
- "STATUS_ERROR",
684
- { status: response.status }
685
- );
686
- }
687
- return response.json();
688
- }
689
- // ===========================================================================
690
- // Utility Methods
691
- // ===========================================================================
692
- /**
693
- * Execute an operation with automatic CAS retry
694
- */
695
- async withCAS(id, operation, maxRetries = 3) {
696
- let lastError = null;
697
- for (let attempt = 0; attempt < maxRetries; attempt++) {
698
- try {
699
- const entity = await this.getEntity(id);
700
- return await operation(entity);
701
- } catch (error) {
702
- if (error instanceof CASConflictError && attempt < maxRetries - 1) {
703
- lastError = error;
704
- const delay = this.calculateDelay(attempt);
705
- await this.sleep(delay);
706
- continue;
707
- }
708
- throw error;
709
- }
710
- }
711
- throw lastError || new EditError("withCAS failed after retries");
712
- }
713
- };
714
-
715
- // src/edit/diff.ts
716
- import * as Diff from "diff";
717
- var DiffEngine = class {
718
- /**
719
- * Compute diff between two strings
720
- */
721
- static diff(original, modified) {
722
- const changes = Diff.diffLines(original, modified);
723
- const diffs = [];
724
- let lineNumber = 1;
725
- for (const change of changes) {
726
- if (change.added) {
727
- diffs.push({
728
- type: "addition",
729
- modified: change.value.trimEnd(),
730
- lineNumber
731
- });
732
- } else if (change.removed) {
733
- diffs.push({
734
- type: "deletion",
735
- original: change.value.trimEnd(),
736
- lineNumber
737
- });
738
- } else {
739
- const lines = change.value.split("\n").length - 1;
740
- lineNumber += lines;
741
- }
742
- if (change.added) {
743
- lineNumber += change.value.split("\n").length - 1;
744
- }
745
- }
746
- return diffs;
747
- }
748
- /**
749
- * Compute word-level diff for more granular changes
750
- */
751
- static diffWords(original, modified) {
752
- const changes = Diff.diffWords(original, modified);
753
- const diffs = [];
754
- for (const change of changes) {
755
- if (change.added) {
756
- diffs.push({
757
- type: "addition",
758
- modified: change.value
759
- });
760
- } else if (change.removed) {
761
- diffs.push({
762
- type: "deletion",
763
- original: change.value
764
- });
765
- }
766
- }
767
- return diffs;
768
- }
769
- /**
770
- * Create a ComponentDiff from original and modified content
771
- */
772
- static createComponentDiff(componentName, original, modified) {
773
- const diffs = this.diff(original, modified);
774
- const hasChanges = diffs.length > 0;
775
- let summary;
776
- if (!hasChanges) {
777
- summary = "No changes";
778
- } else {
779
- const additions = diffs.filter((d) => d.type === "addition").length;
780
- const deletions = diffs.filter((d) => d.type === "deletion").length;
781
- const parts = [];
782
- if (additions > 0) parts.push(`${additions} addition${additions > 1 ? "s" : ""}`);
783
- if (deletions > 0) parts.push(`${deletions} deletion${deletions > 1 ? "s" : ""}`);
784
- summary = parts.join(", ");
785
- }
786
- return {
787
- componentName,
788
- diffs,
789
- summary,
790
- hasChanges
791
- };
792
- }
793
- /**
794
- * Format diffs for AI prompt consumption
795
- */
796
- static formatForPrompt(diffs) {
797
- if (diffs.length === 0) {
798
- return "No changes detected.";
799
- }
800
- const lines = [];
801
- for (const diff of diffs) {
802
- const linePrefix = diff.lineNumber ? `Line ${diff.lineNumber}: ` : "";
803
- if (diff.type === "addition") {
804
- lines.push(`${linePrefix}+ ${diff.modified}`);
805
- } else if (diff.type === "deletion") {
806
- lines.push(`${linePrefix}- ${diff.original}`);
807
- } else if (diff.type === "change") {
808
- lines.push(`${linePrefix}"${diff.original}" \u2192 "${diff.modified}"`);
809
- }
810
- }
811
- return lines.join("\n");
812
- }
813
- /**
814
- * Format component diffs for AI prompt
815
- */
816
- static formatComponentDiffsForPrompt(componentDiffs) {
817
- const sections = [];
818
- for (const cd of componentDiffs) {
819
- if (!cd.hasChanges) continue;
820
- sections.push(`## Changes to ${cd.componentName}:`);
821
- sections.push(this.formatForPrompt(cd.diffs));
822
- sections.push("");
823
- }
824
- return sections.join("\n");
825
- }
826
- /**
827
- * Create a unified diff view
828
- */
829
- static unifiedDiff(original, modified, options) {
830
- const filename = options?.filename || "content";
831
- const patch = Diff.createPatch(filename, original, modified, "", "", {
832
- context: options?.context ?? 3
833
- });
834
- return patch;
835
- }
836
- /**
837
- * Extract corrections from diffs (specific text replacements)
838
- */
839
- static extractCorrections(original, modified, sourceFile) {
840
- const wordDiffs = Diff.diffWords(original, modified);
841
- const corrections = [];
842
- let i = 0;
843
- while (i < wordDiffs.length) {
844
- const current = wordDiffs[i];
845
- if (current.removed && i + 1 < wordDiffs.length && wordDiffs[i + 1].added) {
846
- const removed = current.value.trim();
847
- const added = wordDiffs[i + 1].value.trim();
848
- if (removed && added && removed !== added) {
849
- corrections.push({
850
- original: removed,
851
- corrected: added,
852
- sourceFile
853
- });
854
- }
855
- i += 2;
856
- } else {
857
- i++;
858
- }
859
- }
860
- return corrections;
861
- }
862
- /**
863
- * Check if two strings are meaningfully different
864
- * (ignoring whitespace differences)
865
- */
866
- static hasSignificantChanges(original, modified) {
867
- const normalizedOriginal = original.replace(/\s+/g, " ").trim();
868
- const normalizedModified = modified.replace(/\s+/g, " ").trim();
869
- return normalizedOriginal !== normalizedModified;
870
- }
871
- };
872
-
873
- // src/edit/prompts.ts
874
- var PromptBuilder = class {
875
- /**
876
- * Build prompt for AI-first mode (user provides instructions)
877
- */
878
- static buildAIPrompt(userPrompt, component, entityContext, currentContent) {
879
- const sections = [];
880
- sections.push(`## Instructions for ${component}`);
881
- sections.push(userPrompt);
882
- sections.push("");
883
- sections.push("## Entity Context");
884
- sections.push(`- PI: ${entityContext.pi}`);
885
- sections.push(`- Current version: ${entityContext.ver}`);
886
- if (entityContext.parentPi) {
887
- sections.push(`- Parent: ${entityContext.parentPi}`);
888
- }
889
- if (entityContext.childrenCount > 0) {
890
- sections.push(`- Children: ${entityContext.childrenCount}`);
891
- }
892
- sections.push("");
893
- if (currentContent) {
894
- sections.push(`## Current ${component} content for reference:`);
895
- sections.push("```");
896
- sections.push(currentContent.slice(0, 2e3));
897
- if (currentContent.length > 2e3) {
898
- sections.push("... [truncated]");
899
- }
900
- sections.push("```");
901
- }
902
- return sections.join("\n");
903
- }
904
- /**
905
- * Build prompt incorporating manual edits and diffs
906
- */
907
- static buildEditReviewPrompt(componentDiffs, corrections, component, userInstructions) {
908
- const sections = [];
909
- sections.push("## Manual Edits Made");
910
- sections.push("");
911
- sections.push("The following manual edits were made to this entity:");
912
- sections.push("");
913
- const diffContent = DiffEngine.formatComponentDiffsForPrompt(componentDiffs);
914
- if (diffContent) {
915
- sections.push(diffContent);
916
- }
917
- if (corrections.length > 0) {
918
- sections.push("## Corrections Identified");
919
- sections.push("");
920
- for (const correction of corrections) {
921
- const source = correction.sourceFile ? ` (in ${correction.sourceFile})` : "";
922
- sections.push(`- "${correction.original}" \u2192 "${correction.corrected}"${source}`);
923
- }
924
- sections.push("");
925
- }
926
- sections.push("## Instructions");
927
- if (userInstructions) {
928
- sections.push(userInstructions);
929
- } else {
930
- sections.push(
931
- `Update the ${component} to accurately reflect these changes. Ensure any corrections are incorporated and the content is consistent.`
932
- );
933
- }
934
- sections.push("");
935
- sections.push("## Guidance");
936
- switch (component) {
937
- case "pinax":
938
- sections.push(
939
- "Update metadata fields to reflect any corrections. Pay special attention to dates, names, and other factual information that may have been corrected."
940
- );
941
- break;
942
- case "description":
943
- sections.push(
944
- "Regenerate the description incorporating the changes. Maintain the overall tone and structure while ensuring accuracy based on the corrections."
945
- );
946
- break;
947
- case "cheimarros":
948
- sections.push(
949
- "Update the knowledge graph to reflect any new or corrected entities, relationships, and facts identified in the changes."
950
- );
951
- break;
952
- }
953
- return sections.join("\n");
954
- }
955
- /**
956
- * Build cascade-aware prompt additions
957
- */
958
- static buildCascadePrompt(basePrompt, cascadeContext) {
959
- const sections = [basePrompt];
960
- sections.push("");
961
- sections.push("## Cascade Context");
962
- sections.push("");
963
- sections.push(
964
- "This edit is part of a cascading update. After updating this entity, parent entities will also be updated to reflect these changes."
965
- );
966
- sections.push("");
967
- if (cascadeContext.path.length > 1) {
968
- sections.push(`Cascade path: ${cascadeContext.path.join(" \u2192 ")}`);
969
- sections.push(`Depth: ${cascadeContext.depth}`);
970
- }
971
- if (cascadeContext.stopAtPi) {
972
- sections.push(`Cascade will stop at: ${cascadeContext.stopAtPi}`);
973
- }
974
- sections.push("");
975
- sections.push(
976
- "Ensure the content accurately represents the source material so parent aggregations will be correct."
977
- );
978
- return sections.join("\n");
979
- }
980
- /**
981
- * Build a general prompt combining multiple instructions
982
- */
983
- static buildCombinedPrompt(generalPrompt, componentPrompt, component) {
984
- const sections = [];
985
- if (generalPrompt) {
986
- sections.push("## General Instructions");
987
- sections.push(generalPrompt);
988
- sections.push("");
989
- }
990
- if (componentPrompt) {
991
- sections.push(`## Specific Instructions for ${component}`);
992
- sections.push(componentPrompt);
993
- sections.push("");
994
- }
995
- if (sections.length === 0) {
996
- return `Regenerate the ${component} based on the current entity content.`;
997
- }
998
- return sections.join("\n");
999
- }
1000
- /**
1001
- * Build prompt for correction-based updates
1002
- */
1003
- static buildCorrectionPrompt(corrections) {
1004
- if (corrections.length === 0) {
1005
- return "";
1006
- }
1007
- const sections = [];
1008
- sections.push("## Corrections Applied");
1009
- sections.push("");
1010
- sections.push("The following corrections were made to the source content:");
1011
- sections.push("");
1012
- for (const correction of corrections) {
1013
- const source = correction.sourceFile ? ` in ${correction.sourceFile}` : "";
1014
- sections.push(`- "${correction.original}" was corrected to "${correction.corrected}"${source}`);
1015
- if (correction.context) {
1016
- sections.push(` Context: ${correction.context}`);
1017
- }
1018
- }
1019
- sections.push("");
1020
- sections.push(
1021
- "Update the metadata and description to reflect these corrections. Previous content may have contained errors based on the incorrect text."
1022
- );
1023
- return sections.join("\n");
1024
- }
1025
- /**
1026
- * Get component-specific regeneration guidance
1027
- */
1028
- static getComponentGuidance(component) {
1029
- switch (component) {
1030
- case "pinax":
1031
- return "Extract and structure metadata including: institution, creator, title, date range, subjects, type, and other relevant fields. Ensure accuracy based on the source content.";
1032
- case "description":
1033
- return "Generate a clear, informative description that summarizes the entity content. Focus on what the material contains, its historical significance, and context. Write for a general audience unless otherwise specified.";
1034
- case "cheimarros":
1035
- return "Extract entities (people, places, organizations, events) and their relationships. Build a knowledge graph that captures the key facts and connections in the content.";
1036
- default:
1037
- return "";
1038
- }
1039
- }
1040
- };
1041
-
1042
- // src/edit/session.ts
1043
- var DEFAULT_SCOPE = {
1044
- components: [],
1045
- cascade: false
1046
- };
1047
- var DEFAULT_POLL_OPTIONS = {
1048
- intervalMs: 2e3,
1049
- timeoutMs: 3e5
1050
- // 5 minutes
1051
- };
1052
- var EditSession = class {
1053
- constructor(client, pi, config) {
1054
- this.entity = null;
1055
- this.loadedComponents = {};
1056
- // AI mode state
1057
- this.prompts = {};
1058
- // Manual mode state
1059
- this.editedContent = {};
1060
- this.corrections = [];
1061
- // Scope
1062
- this.scope = { ...DEFAULT_SCOPE };
1063
- // Execution state
1064
- this.submitting = false;
1065
- this.result = null;
1066
- this.statusUrl = null;
1067
- this.client = client;
1068
- this.pi = pi;
1069
- this.mode = config?.mode ?? "ai-prompt";
1070
- this.aiReviewEnabled = config?.aiReviewEnabled ?? true;
1071
- }
1072
- // ===========================================================================
1073
- // Loading
1074
- // ===========================================================================
1075
- /**
1076
- * Load the entity and its key components
1077
- */
1078
- async load() {
1079
- this.entity = await this.client.getEntity(this.pi);
1080
- const priorityComponents = ["description.md", "pinax.json", "cheimarros.json"];
1081
- await Promise.all(
1082
- priorityComponents.map(async (name) => {
1083
- const cid = this.entity.components[name];
1084
- if (cid) {
1085
- try {
1086
- this.loadedComponents[name] = await this.client.getContent(cid);
1087
- } catch {
1088
- }
1089
- }
1090
- })
1091
- );
1092
- }
1093
- /**
1094
- * Load a specific component on demand
1095
- */
1096
- async loadComponent(name) {
1097
- if (this.loadedComponents[name]) {
1098
- return this.loadedComponents[name];
1099
- }
1100
- if (!this.entity) {
1101
- throw new ValidationError("Session not loaded");
1102
- }
1103
- const cid = this.entity.components[name];
1104
- if (!cid) {
1105
- return void 0;
1106
- }
1107
- const content = await this.client.getContent(cid);
1108
- this.loadedComponents[name] = content;
1109
- return content;
1110
- }
1111
- /**
1112
- * Get the loaded entity
1113
- */
1114
- getEntity() {
1115
- if (!this.entity) {
1116
- throw new ValidationError("Session not loaded. Call load() first.");
1117
- }
1118
- return this.entity;
1119
- }
1120
- /**
1121
- * Get loaded component content
1122
- */
1123
- getComponents() {
1124
- return { ...this.loadedComponents };
1125
- }
1126
- // ===========================================================================
1127
- // AI Prompt Mode
1128
- // ===========================================================================
1129
- /**
1130
- * Set a prompt for AI regeneration
1131
- */
1132
- setPrompt(target, prompt) {
1133
- if (this.mode === "manual-only") {
1134
- throw new ValidationError("Cannot set prompts in manual-only mode");
1135
- }
1136
- this.prompts[target] = prompt;
1137
- }
1138
- /**
1139
- * Get all prompts
1140
- */
1141
- getPrompts() {
1142
- return { ...this.prompts };
1143
- }
1144
- /**
1145
- * Clear a prompt
1146
- */
1147
- clearPrompt(target) {
1148
- delete this.prompts[target];
1149
- }
1150
- // ===========================================================================
1151
- // Manual Edit Mode
1152
- // ===========================================================================
1153
- /**
1154
- * Set edited content for a component
1155
- */
1156
- setContent(componentName, content) {
1157
- if (this.mode === "ai-prompt") {
1158
- throw new ValidationError("Cannot set content in ai-prompt mode");
1159
- }
1160
- this.editedContent[componentName] = content;
1161
- }
1162
- /**
1163
- * Get all edited content
1164
- */
1165
- getEditedContent() {
1166
- return { ...this.editedContent };
1167
- }
1168
- /**
1169
- * Clear edited content for a component
1170
- */
1171
- clearContent(componentName) {
1172
- delete this.editedContent[componentName];
1173
- }
1174
- /**
1175
- * Add a correction (for OCR fixes, etc.)
1176
- */
1177
- addCorrection(original, corrected, sourceFile) {
1178
- this.corrections.push({ original, corrected, sourceFile });
1179
- }
1180
- /**
1181
- * Get all corrections
1182
- */
1183
- getCorrections() {
1184
- return [...this.corrections];
1185
- }
1186
- /**
1187
- * Clear corrections
1188
- */
1189
- clearCorrections() {
1190
- this.corrections = [];
1191
- }
1192
- // ===========================================================================
1193
- // Scope Configuration
1194
- // ===========================================================================
1195
- /**
1196
- * Set the edit scope
1197
- */
1198
- setScope(scope) {
1199
- this.scope = { ...this.scope, ...scope };
1200
- }
1201
- /**
1202
- * Get the current scope
1203
- */
1204
- getScope() {
1205
- return { ...this.scope };
1206
- }
1207
- // ===========================================================================
1208
- // Preview & Summary
1209
- // ===========================================================================
1210
- /**
1211
- * Get diffs for manual changes
1212
- */
1213
- getDiff() {
1214
- const diffs = [];
1215
- for (const [name, edited] of Object.entries(this.editedContent)) {
1216
- const original = this.loadedComponents[name] || "";
1217
- if (DiffEngine.hasSignificantChanges(original, edited)) {
1218
- diffs.push(DiffEngine.createComponentDiff(name, original, edited));
1219
- }
1220
- }
1221
- return diffs;
1222
- }
1223
- /**
1224
- * Preview what prompts will be sent to AI
1225
- */
1226
- previewPrompt() {
1227
- const result = {};
1228
- if (!this.entity) return result;
1229
- const entityContext = {
1230
- pi: this.entity.id,
1231
- ver: this.entity.ver,
1232
- parentPi: this.entity.parent_pi,
1233
- childrenCount: this.entity.children_pi?.length ?? 0,
1234
- currentContent: this.loadedComponents
1235
- };
1236
- for (const component of this.scope.components) {
1237
- let prompt;
1238
- if (this.mode === "ai-prompt") {
1239
- const componentPrompt = this.prompts[component];
1240
- const generalPrompt = this.prompts["general"];
1241
- const combined = PromptBuilder.buildCombinedPrompt(generalPrompt, componentPrompt, component);
1242
- prompt = PromptBuilder.buildAIPrompt(
1243
- combined,
1244
- component,
1245
- entityContext,
1246
- this.loadedComponents[`${component}.json`] || this.loadedComponents[`${component}.md`]
1247
- );
1248
- } else {
1249
- const diffs = this.getDiff();
1250
- const userInstructions = this.prompts["general"] || this.prompts[component];
1251
- prompt = PromptBuilder.buildEditReviewPrompt(diffs, this.corrections, component, userInstructions);
1252
- }
1253
- if (this.scope.cascade) {
1254
- prompt = PromptBuilder.buildCascadePrompt(prompt, {
1255
- path: [this.entity.id, this.entity.parent_pi || "root"].filter(Boolean),
1256
- depth: 0,
1257
- stopAtPi: this.scope.stopAtPi
1258
- });
1259
- }
1260
- result[component] = prompt;
1261
- }
1262
- return result;
1263
- }
1264
- /**
1265
- * Get a summary of pending changes
1266
- */
1267
- getChangeSummary() {
1268
- const diffs = this.getDiff();
1269
- const hasManualEdits = diffs.some((d) => d.hasChanges);
1270
- return {
1271
- mode: this.mode,
1272
- hasManualEdits,
1273
- editedComponents: Object.keys(this.editedContent),
1274
- corrections: [...this.corrections],
1275
- prompts: { ...this.prompts },
1276
- scope: { ...this.scope },
1277
- willRegenerate: [...this.scope.components],
1278
- willCascade: this.scope.cascade,
1279
- willSave: hasManualEdits,
1280
- willReprocess: this.scope.components.length > 0
1281
- };
1282
- }
1283
- // ===========================================================================
1284
- // Execution
1285
- // ===========================================================================
1286
- /**
1287
- * Submit changes (saves first if manual edits, then reprocesses)
1288
- */
1289
- async submit(note) {
1290
- if (this.submitting) {
1291
- throw new ValidationError("Submit already in progress");
1292
- }
1293
- if (!this.entity) {
1294
- throw new ValidationError("Session not loaded. Call load() first.");
1295
- }
1296
- this.submitting = true;
1297
- this.result = {};
1298
- try {
1299
- const diffs = this.getDiff();
1300
- const hasManualEdits = diffs.some((d) => d.hasChanges);
1301
- if (hasManualEdits) {
1302
- const componentUpdates = {};
1303
- for (const [name, content] of Object.entries(this.editedContent)) {
1304
- const original = this.loadedComponents[name] || "";
1305
- if (DiffEngine.hasSignificantChanges(original, content)) {
1306
- const cid = await this.client.uploadContent(content, name);
1307
- componentUpdates[name] = cid;
1308
- }
1309
- }
1310
- const version = await this.client.updateEntity(this.pi, {
1311
- expect_tip: this.entity.manifest_cid,
1312
- components: componentUpdates,
1313
- note
1314
- });
1315
- this.result.saved = {
1316
- pi: version.id,
1317
- newVersion: version.ver,
1318
- newTip: version.tip
1319
- };
1320
- this.entity.manifest_cid = version.tip;
1321
- this.entity.ver = version.ver;
1322
- }
1323
- if (this.scope.components.length > 0) {
1324
- const customPrompts = this.buildCustomPrompts();
1325
- const reprocessResult = await this.client.reprocess({
1326
- pi: this.pi,
1327
- phases: this.scope.components,
1328
- cascade: this.scope.cascade,
1329
- options: {
1330
- stop_at_pi: this.scope.stopAtPi,
1331
- custom_prompts: customPrompts,
1332
- custom_note: note
1333
- }
1334
- });
1335
- this.result.reprocess = reprocessResult;
1336
- this.statusUrl = reprocessResult.status_url;
1337
- }
1338
- return this.result;
1339
- } finally {
1340
- this.submitting = false;
1341
- }
1342
- }
1343
- /**
1344
- * Wait for reprocessing to complete
1345
- */
1346
- async waitForCompletion(options) {
1347
- const opts = { ...DEFAULT_POLL_OPTIONS, ...options };
1348
- if (!this.statusUrl) {
1349
- return {
1350
- phase: "complete",
1351
- saveComplete: true
1352
- };
1353
- }
1354
- const startTime = Date.now();
1355
- let isFirstPoll = true;
1356
- while (true) {
1357
- const status = await this.client.getReprocessStatus(this.statusUrl, isFirstPoll);
1358
- isFirstPoll = false;
1359
- const editStatus = {
1360
- phase: status.status === "DONE" ? "complete" : status.status === "ERROR" ? "error" : "reprocessing",
1361
- saveComplete: true,
1362
- reprocessStatus: status,
1363
- error: status.error
1364
- };
1365
- if (opts.onProgress) {
1366
- opts.onProgress(editStatus);
1367
- }
1368
- if (status.status === "DONE" || status.status === "ERROR") {
1369
- return editStatus;
1370
- }
1371
- if (Date.now() - startTime > opts.timeoutMs) {
1372
- return {
1373
- phase: "error",
1374
- saveComplete: true,
1375
- reprocessStatus: status,
1376
- error: "Timeout waiting for reprocessing to complete"
1377
- };
1378
- }
1379
- await new Promise((resolve) => setTimeout(resolve, opts.intervalMs));
1380
- }
1381
- }
1382
- /**
1383
- * Get current status without waiting
1384
- */
1385
- async getStatus() {
1386
- if (!this.statusUrl) {
1387
- return {
1388
- phase: this.result?.saved ? "complete" : "idle",
1389
- saveComplete: !!this.result?.saved
1390
- };
1391
- }
1392
- const status = await this.client.getReprocessStatus(this.statusUrl);
1393
- return {
1394
- phase: status.status === "DONE" ? "complete" : status.status === "ERROR" ? "error" : "reprocessing",
1395
- saveComplete: true,
1396
- reprocessStatus: status,
1397
- error: status.error
1398
- };
1399
- }
1400
- // ===========================================================================
1401
- // Private Helpers
1402
- // ===========================================================================
1403
- buildCustomPrompts() {
1404
- const custom = {};
1405
- if (this.mode === "ai-prompt") {
1406
- if (this.prompts["general"]) custom.general = this.prompts["general"];
1407
- if (this.prompts["pinax"]) custom.pinax = this.prompts["pinax"];
1408
- if (this.prompts["description"]) custom.description = this.prompts["description"];
1409
- if (this.prompts["cheimarros"]) custom.cheimarros = this.prompts["cheimarros"];
1410
- } else {
1411
- const diffs = this.getDiff();
1412
- const diffContext = DiffEngine.formatComponentDiffsForPrompt(diffs);
1413
- const correctionContext = PromptBuilder.buildCorrectionPrompt(this.corrections);
1414
- const basePrompt = [diffContext, correctionContext, this.prompts["general"]].filter(Boolean).join("\n\n");
1415
- if (basePrompt) {
1416
- custom.general = basePrompt;
1417
- }
1418
- if (this.prompts["pinax"]) custom.pinax = this.prompts["pinax"];
1419
- if (this.prompts["description"]) custom.description = this.prompts["description"];
1420
- if (this.prompts["cheimarros"]) custom.cheimarros = this.prompts["cheimarros"];
1421
- }
1422
- return custom;
1423
- }
1424
- };
1425
- export {
1426
- BackendError,
1427
- CASConflictError,
1428
- ContentNotFoundError,
1429
- DEFAULT_RETRY_CONFIG,
1430
- DeleteError,
1431
- DiffEngine,
1432
- EditClient,
1433
- EditError,
1434
- EditSession,
1435
- EntityExistsError,
1436
- EntityNotFoundError,
1437
- IPFSError,
1438
- MergeError,
1439
- NetworkError,
1440
- PermissionError,
1441
- PromptBuilder,
1442
- ReprocessError,
1443
- UndeleteError,
1444
- UnmergeError,
1445
- ValidationError
1446
- };
1447
- //# sourceMappingURL=index.js.map