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