@ar.io/deploy 0.1.0-alpha.20260610213851.5857f96

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 (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +753 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.js +5 -0
  5. package/dist/chunks/cache-C1tEeUx2.js +6 -0
  6. package/dist/chunks/cache-C1tEeUx2.js.map +1 -0
  7. package/dist/chunks/display-DRcjDj9k.js +104 -0
  8. package/dist/chunks/display-DRcjDj9k.js.map +1 -0
  9. package/dist/chunks/upload-workflow-DSS5FIa5.js +204 -0
  10. package/dist/chunks/upload-workflow-DSS5FIa5.js.map +1 -0
  11. package/dist/chunks/uploader-B2tC-1Qw.js +472 -0
  12. package/dist/chunks/uploader-B2tC-1Qw.js.map +1 -0
  13. package/dist/commands/deploy.js +238 -0
  14. package/dist/commands/deploy.js.map +1 -0
  15. package/dist/commands/upload.js +126 -0
  16. package/dist/commands/upload.js.map +1 -0
  17. package/dist/constants/flags.js +268 -0
  18. package/dist/constants/flags.js.map +1 -0
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/prompts/arns.js +86 -0
  22. package/dist/prompts/arns.js.map +1 -0
  23. package/dist/prompts/deployment.js +27 -0
  24. package/dist/prompts/deployment.js.map +1 -0
  25. package/dist/prompts/wallet.js +55 -0
  26. package/dist/prompts/wallet.js.map +1 -0
  27. package/dist/src/commands/deploy.d.ts +9 -0
  28. package/dist/src/commands/deploy.d.ts.map +1 -0
  29. package/dist/src/commands/upload.d.ts +9 -0
  30. package/dist/src/commands/upload.d.ts.map +1 -0
  31. package/dist/src/constants/cache.d.ts +4 -0
  32. package/dist/src/constants/cache.d.ts.map +1 -0
  33. package/dist/src/constants/flags.d.ts +132 -0
  34. package/dist/src/constants/flags.d.ts.map +1 -0
  35. package/dist/src/index.d.ts +2 -0
  36. package/dist/src/index.d.ts.map +1 -0
  37. package/dist/src/prompts/arns.d.ts +14 -0
  38. package/dist/src/prompts/arns.d.ts.map +1 -0
  39. package/dist/src/prompts/deployment.d.ts +6 -0
  40. package/dist/src/prompts/deployment.d.ts.map +1 -0
  41. package/dist/src/prompts/wallet.d.ts +26 -0
  42. package/dist/src/prompts/wallet.d.ts.map +1 -0
  43. package/dist/src/types/index.d.ts +31 -0
  44. package/dist/src/types/index.d.ts.map +1 -0
  45. package/dist/src/utils/__tests__/cache.test.d.ts +2 -0
  46. package/dist/src/utils/__tests__/cache.test.d.ts.map +1 -0
  47. package/dist/src/utils/__tests__/constants.test.d.ts +2 -0
  48. package/dist/src/utils/__tests__/constants.test.d.ts.map +1 -0
  49. package/dist/src/utils/__tests__/display.test.d.ts +2 -0
  50. package/dist/src/utils/__tests__/display.test.d.ts.map +1 -0
  51. package/dist/src/utils/cache.d.ts +48 -0
  52. package/dist/src/utils/cache.d.ts.map +1 -0
  53. package/dist/src/utils/chalk.d.ts +9 -0
  54. package/dist/src/utils/chalk.d.ts.map +1 -0
  55. package/dist/src/utils/config-resolver.d.ts +72 -0
  56. package/dist/src/utils/config-resolver.d.ts.map +1 -0
  57. package/dist/src/utils/constants.d.ts +4 -0
  58. package/dist/src/utils/constants.d.ts.map +1 -0
  59. package/dist/src/utils/deploy-key.d.ts +15 -0
  60. package/dist/src/utils/deploy-key.d.ts.map +1 -0
  61. package/dist/src/utils/display.d.ts +7 -0
  62. package/dist/src/utils/display.d.ts.map +1 -0
  63. package/dist/src/utils/path.d.ts +5 -0
  64. package/dist/src/utils/path.d.ts.map +1 -0
  65. package/dist/src/utils/signer.d.ts +19 -0
  66. package/dist/src/utils/signer.d.ts.map +1 -0
  67. package/dist/src/utils/solana.d.ts +29 -0
  68. package/dist/src/utils/solana.d.ts.map +1 -0
  69. package/dist/src/utils/upload-types.d.ts +35 -0
  70. package/dist/src/utils/upload-types.d.ts.map +1 -0
  71. package/dist/src/utils/uploader.d.ts +50 -0
  72. package/dist/src/utils/uploader.d.ts.map +1 -0
  73. package/dist/src/utils/validators.d.ts +21 -0
  74. package/dist/src/utils/validators.d.ts.map +1 -0
  75. package/dist/src/workflows/upload-workflow.d.ts +28 -0
  76. package/dist/src/workflows/upload-workflow.d.ts.map +1 -0
  77. package/dist/tests/constants.d.ts +11 -0
  78. package/dist/tests/constants.d.ts.map +1 -0
  79. package/dist/tests/e2e/deploy-command.test.d.ts +2 -0
  80. package/dist/tests/e2e/deploy-command.test.d.ts.map +1 -0
  81. package/dist/tests/global-setup.d.ts +6 -0
  82. package/dist/tests/global-setup.d.ts.map +1 -0
  83. package/dist/tests/mocks/turbo-handlers.d.ts +106 -0
  84. package/dist/tests/mocks/turbo-handlers.d.ts.map +1 -0
  85. package/dist/tests/setup.d.ts +11 -0
  86. package/dist/tests/setup.d.ts.map +1 -0
  87. package/dist/tests/types/payment-service.d.ts +218 -0
  88. package/dist/tests/types/payment-service.d.ts.map +1 -0
  89. package/dist/tests/types/upload-service.d.ts +168 -0
  90. package/dist/tests/types/upload-service.d.ts.map +1 -0
  91. package/dist/tests/unit/deploy-key.test.d.ts +2 -0
  92. package/dist/tests/unit/deploy-key.test.d.ts.map +1 -0
  93. package/dist/tests/unit/signer.test.d.ts +2 -0
  94. package/dist/tests/unit/signer.test.d.ts.map +1 -0
  95. package/dist/tests/unit/solana.test.d.ts +2 -0
  96. package/dist/tests/unit/solana.test.d.ts.map +1 -0
  97. package/dist/tests/unit/uploader-tags.test.d.ts +2 -0
  98. package/dist/tests/unit/uploader-tags.test.d.ts.map +1 -0
  99. package/dist/tests/unit/validators.test.d.ts +2 -0
  100. package/dist/tests/unit/validators.test.d.ts.map +1 -0
  101. package/dist/types/index.js +2 -0
  102. package/dist/types/index.js.map +1 -0
  103. package/dist/utils/config-resolver.js +39 -0
  104. package/dist/utils/config-resolver.js.map +1 -0
  105. package/dist/utils/constants.js +6 -0
  106. package/dist/utils/constants.js.map +1 -0
  107. package/dist/utils/path.js +15 -0
  108. package/dist/utils/path.js.map +1 -0
  109. package/dist/utils/signer.js +45 -0
  110. package/dist/utils/signer.js.map +1 -0
  111. package/dist/utils/uploader.js +5 -0
  112. package/dist/utils/uploader.js.map +1 -0
  113. package/dist/utils/validators.js +43 -0
  114. package/dist/utils/validators.js.map +1 -0
  115. package/dist/workflows/upload-workflow.js +9 -0
  116. package/dist/workflows/upload-workflow.js.map +1 -0
  117. package/package.json +111 -0
@@ -0,0 +1,472 @@
1
+ import path from 'node:path';
2
+ import { Readable } from 'node:stream';
3
+ import * as mime from 'mime-types';
4
+ import crypto from 'node:crypto';
5
+ import fs from 'node:fs';
6
+ import { C as CACHE_DIR, a as CACHE_FILE } from './cache-C1tEeUx2.js';
7
+
8
+ function getCachePath() {
9
+ return path.join(process.cwd(), CACHE_DIR, CACHE_FILE);
10
+ }
11
+ function loadCache() {
12
+ const cachePath = getCachePath();
13
+ try {
14
+ if (!fs.existsSync(cachePath)) {
15
+ return {};
16
+ }
17
+ const content = fs.readFileSync(cachePath, "utf8");
18
+ return JSON.parse(content);
19
+ } catch {
20
+ return {};
21
+ }
22
+ }
23
+ function saveCache(cache) {
24
+ const cachePath = getCachePath();
25
+ const cacheDir = path.dirname(cachePath);
26
+ if (!fs.existsSync(cacheDir)) {
27
+ fs.mkdirSync(cacheDir, { recursive: true });
28
+ }
29
+ fs.writeFileSync(cachePath, JSON.stringify(cache, null, 2), "utf8");
30
+ }
31
+ async function hashFile(filePath) {
32
+ return new Promise((resolve, reject) => {
33
+ const hash = crypto.createHash("sha256");
34
+ const stream = fs.createReadStream(filePath);
35
+ stream.on("data", (chunk) => hash.update(chunk));
36
+ stream.on("end", () => resolve(hash.digest("hex")));
37
+ stream.on("error", reject);
38
+ });
39
+ }
40
+ function getAllFiles(dirPath, basePath = dirPath) {
41
+ const files = [];
42
+ for (const item of fs.readdirSync(dirPath)) {
43
+ const fullPath = path.join(dirPath, item);
44
+ const stats = fs.statSync(fullPath);
45
+ if (stats.isDirectory()) {
46
+ files.push(...getAllFiles(fullPath, basePath));
47
+ } else {
48
+ files.push(path.relative(basePath, fullPath));
49
+ }
50
+ }
51
+ return files;
52
+ }
53
+ function getCachedTransaction(cache, hash) {
54
+ return cache[hash];
55
+ }
56
+ function setCachedTransaction(cache, hash, transactionId) {
57
+ const now = Date.now();
58
+ const existing = cache[hash];
59
+ return {
60
+ ...cache,
61
+ [hash]: {
62
+ createdAtTimestamp: existing?.createdAtTimestamp ?? now,
63
+ lastUsedTimestamp: now,
64
+ transactionId
65
+ }
66
+ };
67
+ }
68
+ function touchCacheEntry(cache, hash) {
69
+ const existing = cache[hash];
70
+ if (!existing) {
71
+ return cache;
72
+ }
73
+ return {
74
+ ...cache,
75
+ [hash]: {
76
+ ...existing,
77
+ lastUsedTimestamp: Date.now()
78
+ }
79
+ };
80
+ }
81
+ function cleanupCache(cache, maxEntries) {
82
+ const entries = Object.entries(cache);
83
+ if (entries.length <= maxEntries) {
84
+ return cache;
85
+ }
86
+ const sorted = entries.sort(([, a], [, b]) => b.lastUsedTimestamp - a.lastUsedTimestamp);
87
+ const kept = sorted.slice(0, maxEntries);
88
+ return Object.fromEntries(kept);
89
+ }
90
+
91
+ /*
92
+ How it works:
93
+ `this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value.
94
+ */
95
+
96
+ class Node {
97
+ value;
98
+ next;
99
+
100
+ constructor(value) {
101
+ this.value = value;
102
+ }
103
+ }
104
+
105
+ class Queue {
106
+ #head;
107
+ #tail;
108
+ #size;
109
+
110
+ constructor() {
111
+ this.clear();
112
+ }
113
+
114
+ enqueue(value) {
115
+ const node = new Node(value);
116
+
117
+ if (this.#head) {
118
+ this.#tail.next = node;
119
+ this.#tail = node;
120
+ } else {
121
+ this.#head = node;
122
+ this.#tail = node;
123
+ }
124
+
125
+ this.#size++;
126
+ }
127
+
128
+ dequeue() {
129
+ const current = this.#head;
130
+ if (!current) {
131
+ return;
132
+ }
133
+
134
+ this.#head = this.#head.next;
135
+ this.#size--;
136
+
137
+ // Clean up tail reference when queue becomes empty
138
+ if (!this.#head) {
139
+ this.#tail = undefined;
140
+ }
141
+
142
+ return current.value;
143
+ }
144
+
145
+ peek() {
146
+ if (!this.#head) {
147
+ return;
148
+ }
149
+
150
+ return this.#head.value;
151
+
152
+ // TODO: Node.js 18.
153
+ // return this.#head?.value;
154
+ }
155
+
156
+ clear() {
157
+ this.#head = undefined;
158
+ this.#tail = undefined;
159
+ this.#size = 0;
160
+ }
161
+
162
+ get size() {
163
+ return this.#size;
164
+ }
165
+
166
+ * [Symbol.iterator]() {
167
+ let current = this.#head;
168
+
169
+ while (current) {
170
+ yield current.value;
171
+ current = current.next;
172
+ }
173
+ }
174
+
175
+ * drain() {
176
+ while (this.#head) {
177
+ yield this.dequeue();
178
+ }
179
+ }
180
+ }
181
+
182
+ function pLimit(concurrency) {
183
+ let rejectOnClear = false;
184
+
185
+ if (typeof concurrency === 'object') {
186
+ ({concurrency, rejectOnClear = false} = concurrency);
187
+ }
188
+
189
+ validateConcurrency(concurrency);
190
+
191
+ if (typeof rejectOnClear !== 'boolean') {
192
+ throw new TypeError('Expected `rejectOnClear` to be a boolean');
193
+ }
194
+
195
+ const queue = new Queue();
196
+ let activeCount = 0;
197
+
198
+ const resumeNext = () => {
199
+ // Process the next queued function if we're under the concurrency limit
200
+ if (activeCount < concurrency && queue.size > 0) {
201
+ activeCount++;
202
+ queue.dequeue().run();
203
+ }
204
+ };
205
+
206
+ const next = () => {
207
+ activeCount--;
208
+ resumeNext();
209
+ };
210
+
211
+ const run = async (function_, resolve, arguments_) => {
212
+ // Execute the function and capture the result promise
213
+ const result = (async () => function_(...arguments_))();
214
+
215
+ // Resolve immediately with the promise (don't wait for completion)
216
+ resolve(result);
217
+
218
+ // Wait for the function to complete (success or failure)
219
+ // We catch errors here to prevent unhandled rejections,
220
+ // but the original promise rejection is preserved for the caller
221
+ try {
222
+ await result;
223
+ } catch {}
224
+
225
+ // Decrement active count and process next queued function
226
+ next();
227
+ };
228
+
229
+ const enqueue = (function_, resolve, reject, arguments_) => {
230
+ const queueItem = {reject};
231
+
232
+ // Queue the internal resolve function instead of the run function
233
+ // to preserve the asynchronous execution context.
234
+ new Promise(internalResolve => { // eslint-disable-line promise/param-names
235
+ queueItem.run = internalResolve;
236
+ queue.enqueue(queueItem);
237
+ }).then(run.bind(undefined, function_, resolve, arguments_)); // eslint-disable-line promise/prefer-await-to-then
238
+
239
+ // Start processing immediately if we haven't reached the concurrency limit
240
+ if (activeCount < concurrency) {
241
+ resumeNext();
242
+ }
243
+ };
244
+
245
+ const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
246
+ enqueue(function_, resolve, reject, arguments_);
247
+ });
248
+
249
+ Object.defineProperties(generator, {
250
+ activeCount: {
251
+ get: () => activeCount,
252
+ },
253
+ pendingCount: {
254
+ get: () => queue.size,
255
+ },
256
+ clearQueue: {
257
+ value() {
258
+ if (!rejectOnClear) {
259
+ queue.clear();
260
+ return;
261
+ }
262
+
263
+ const abortError = AbortSignal.abort().reason;
264
+
265
+ while (queue.size > 0) {
266
+ queue.dequeue().reject(abortError);
267
+ }
268
+ },
269
+ },
270
+ concurrency: {
271
+ get: () => concurrency,
272
+
273
+ set(newConcurrency) {
274
+ validateConcurrency(newConcurrency);
275
+ concurrency = newConcurrency;
276
+
277
+ queueMicrotask(() => {
278
+ // eslint-disable-next-line no-unmodified-loop-condition
279
+ while (activeCount < concurrency && queue.size > 0) {
280
+ resumeNext();
281
+ }
282
+ });
283
+ },
284
+ },
285
+ map: {
286
+ async value(iterable, function_) {
287
+ const promises = Array.from(iterable, (value, index) => this(function_, value, index));
288
+ return Promise.all(promises);
289
+ },
290
+ },
291
+ });
292
+
293
+ return generator;
294
+ }
295
+
296
+ function validateConcurrency(concurrency) {
297
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
298
+ throw new TypeError('Expected `concurrency` to be a number from 1 and up');
299
+ }
300
+ }
301
+
302
+ function provenanceTags() {
303
+ const tags = [{ name: "App-Name", value: "ARIO-Deploy" }];
304
+ if (process.env.GITHUB_SHA) {
305
+ tags.push({ name: "GIT-HASH", value: process.env.GITHUB_SHA });
306
+ }
307
+ return tags;
308
+ }
309
+ async function uploadFile(turbo, filePath, options) {
310
+ const mimeType = mime.lookup(filePath) || "application/octet-stream";
311
+ const fileHash = options?.cache ? await hashFile(filePath) : void 0;
312
+ if (fileHash && options?.cache) {
313
+ const cached = getCachedTransaction(options.cache, fileHash);
314
+ if (cached) {
315
+ const updatedCache = touchCacheEntry(options.cache, fileHash);
316
+ return {
317
+ cacheHit: true,
318
+ transactionId: cached.transactionId,
319
+ updatedCache
320
+ };
321
+ }
322
+ }
323
+ const uploadResult = await turbo.uploadFile({
324
+ dataItemOpts: {
325
+ tags: [
326
+ ...provenanceTags(),
327
+ {
328
+ name: "anchor",
329
+ value: (/* @__PURE__ */ new Date()).toISOString()
330
+ },
331
+ {
332
+ name: "Content-Type",
333
+ value: mimeType
334
+ }
335
+ ]
336
+ },
337
+ file: filePath,
338
+ ...options?.fundingMode && { fundingMode: options.fundingMode }
339
+ });
340
+ if (!uploadResult?.id) {
341
+ throw new Error("Failed to upload file: upload result missing transaction ID");
342
+ }
343
+ if (fileHash && options?.cache) {
344
+ const updatedCache = setCachedTransaction(options.cache, fileHash, uploadResult.id);
345
+ return {
346
+ cacheHit: false,
347
+ cost: uploadResult.cost,
348
+ size: uploadResult.size,
349
+ transactionId: uploadResult.id,
350
+ updatedCache
351
+ };
352
+ }
353
+ return {
354
+ cacheHit: false,
355
+ cost: uploadResult.cost,
356
+ size: uploadResult.size,
357
+ transactionId: uploadResult.id
358
+ };
359
+ }
360
+ const DEFAULT_UPLOAD_CONCURRENCY = 10;
361
+ async function uploadFolder(turbo, folderPath, options) {
362
+ const concurrency = options?.concurrency ?? DEFAULT_UPLOAD_CONCURRENCY;
363
+ const useCache = options?.cache !== void 0;
364
+ const relativePaths = getAllFiles(folderPath);
365
+ if (relativePaths.length === 0) {
366
+ throw new Error("Folder is empty, nothing to upload");
367
+ }
368
+ const tasks = await Promise.all(
369
+ relativePaths.map(async (relativePath) => {
370
+ const fullPath = path.join(folderPath, relativePath);
371
+ const hash = useCache ? await hashFile(fullPath) : "";
372
+ return { fullPath, hash, relativePath };
373
+ })
374
+ );
375
+ let cache = options?.cache ?? {};
376
+ let cacheHits = 0;
377
+ for (const task of tasks) {
378
+ if (useCache && task.hash) {
379
+ const cached = getCachedTransaction(cache, task.hash);
380
+ if (cached) {
381
+ task.cached = { transactionId: cached.transactionId };
382
+ cache = touchCacheEntry(cache, task.hash);
383
+ cacheHits++;
384
+ }
385
+ }
386
+ }
387
+ const uncachedTasks = tasks.filter((t) => !t.cached);
388
+ const limit = pLimit(concurrency);
389
+ const uploadResults = await Promise.all(
390
+ uncachedTasks.map(
391
+ (task) => limit(async () => {
392
+ const mimeType = mime.lookup(task.fullPath) || "application/octet-stream";
393
+ const uploadResult = await turbo.uploadFile({
394
+ dataItemOpts: {
395
+ tags: [...provenanceTags(), { name: "Content-Type", value: mimeType }]
396
+ },
397
+ file: task.fullPath,
398
+ ...options?.fundingMode && { fundingMode: options.fundingMode }
399
+ });
400
+ if (!uploadResult?.id) {
401
+ if (options?.throwOnFailure) {
402
+ throw new Error(`Failed to upload file: ${task.relativePath}`);
403
+ }
404
+ return { hash: task.hash, task, transactionId: null };
405
+ }
406
+ return { hash: task.hash, task, transactionId: uploadResult.id };
407
+ })
408
+ )
409
+ );
410
+ for (const result of uploadResults) {
411
+ if (useCache && result.hash && result.transactionId) {
412
+ cache = setCachedTransaction(cache, result.hash, result.transactionId);
413
+ }
414
+ }
415
+ const failedUploads = uploadResults.filter((r) => r.transactionId === null);
416
+ if (failedUploads.length > 0 && options?.throwOnFailure) {
417
+ throw new Error(
418
+ `Failed to upload ${failedUploads.length} file(s): ${failedUploads.map((f) => f.task.relativePath).join(", ")}`
419
+ );
420
+ }
421
+ const manifestPaths = {};
422
+ for (const task of tasks) {
423
+ let transactionId = null;
424
+ if (task.cached) {
425
+ transactionId = task.cached.transactionId;
426
+ } else {
427
+ const uploadResult = uploadResults.find((r) => r.task === task);
428
+ transactionId = uploadResult?.transactionId ?? null;
429
+ }
430
+ if (transactionId) {
431
+ manifestPaths[task.relativePath] = { id: transactionId };
432
+ if (task.relativePath.endsWith("/index.html")) {
433
+ const dirPath = task.relativePath.replace(/\/index\.html$/, "");
434
+ manifestPaths[dirPath] = { id: transactionId };
435
+ }
436
+ }
437
+ }
438
+ const indexPath = relativePaths.includes("index.html") ? "index.html" : void 0;
439
+ const manifest = {
440
+ manifest: "arweave/paths",
441
+ version: "0.2.0",
442
+ ...indexPath && { index: { path: indexPath } },
443
+ paths: manifestPaths
444
+ };
445
+ const manifestBuffer = Buffer.from(JSON.stringify(manifest));
446
+ const manifestUploadResult = await turbo.uploadFile({
447
+ dataItemOpts: {
448
+ tags: [
449
+ ...provenanceTags(),
450
+ { name: "Content-Type", value: "application/x.arweave-manifest+json" },
451
+ { name: "Device", value: "manifest@1.0" }
452
+ ]
453
+ },
454
+ fileSizeFactory: () => manifestBuffer.length,
455
+ fileStreamFactory: () => Readable.from(manifestBuffer),
456
+ ...options?.fundingMode && { fundingMode: options.fundingMode }
457
+ });
458
+ if (!manifestUploadResult?.id) {
459
+ throw new Error("Failed to upload manifest: upload result missing transaction ID");
460
+ }
461
+ return {
462
+ cacheHit: cacheHits === tasks.length,
463
+ cacheHits,
464
+ totalFiles: tasks.length,
465
+ transactionId: manifestUploadResult.id,
466
+ updatedCache: useCache ? cache : void 0,
467
+ uploaded: uncachedTasks.length - failedUploads.length
468
+ };
469
+ }
470
+
471
+ export { uploadFolder as a, cleanupCache as c, loadCache as l, provenanceTags as p, saveCache as s, uploadFile as u };
472
+ //# sourceMappingURL=uploader-B2tC-1Qw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploader-B2tC-1Qw.js","sources":["../../src/utils/cache.ts","../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js","../../node_modules/.pnpm/p-limit@7.3.0/node_modules/p-limit/index.js","../../src/utils/uploader.ts"],"sourcesContent":["import crypto from 'node:crypto'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { CACHE_DIR, CACHE_FILE } from '../constants/cache.js'\n\nexport interface TransactionCacheEntry {\n createdAtTimestamp: number\n lastUsedTimestamp: number\n transactionId: string\n}\n\nexport type TransactionCache = Record<string, TransactionCacheEntry>\n\n/**\n * Get the path to the cache file in the current working directory\n */\nexport function getCachePath(): string {\n return path.join(process.cwd(), CACHE_DIR, CACHE_FILE)\n}\n\n/**\n * Load the transaction cache from disk\n * Returns an empty object if the cache file doesn't exist or is invalid\n */\nexport function loadCache(): TransactionCache {\n const cachePath = getCachePath()\n\n try {\n if (!fs.existsSync(cachePath)) {\n return {}\n }\n\n const content = fs.readFileSync(cachePath, 'utf8')\n return JSON.parse(content) as TransactionCache\n } catch {\n // If the cache is corrupted or unreadable, start fresh\n return {}\n }\n}\n\n/**\n * Save the transaction cache to disk\n * Creates the cache directory if it doesn't exist\n */\nexport function saveCache(cache: TransactionCache): void {\n const cachePath = getCachePath()\n const cacheDir = path.dirname(cachePath)\n\n if (!fs.existsSync(cacheDir)) {\n fs.mkdirSync(cacheDir, { recursive: true })\n }\n\n fs.writeFileSync(cachePath, JSON.stringify(cache, null, 2), 'utf8')\n}\n\n/**\n * Compute the SHA-256 hash of a file using streaming\n */\nexport async function hashFile(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = crypto.createHash('sha256')\n const stream = fs.createReadStream(filePath)\n\n stream.on('data', (chunk) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n}\n\n/**\n * Recursively get all files in a directory\n * Returns relative paths from the base directory\n */\nexport function getAllFiles(dirPath: string, basePath: string = dirPath): string[] {\n const files: string[] = []\n\n for (const item of fs.readdirSync(dirPath)) {\n const fullPath = path.join(dirPath, item)\n const stats = fs.statSync(fullPath)\n\n if (stats.isDirectory()) {\n files.push(...getAllFiles(fullPath, basePath))\n } else {\n // Store relative path for consistent hashing\n files.push(path.relative(basePath, fullPath))\n }\n }\n\n return files\n}\n\n/**\n * Get a cached transaction entry by its file hash\n */\nexport function getCachedTransaction(\n cache: TransactionCache,\n hash: string,\n): TransactionCacheEntry | undefined {\n return cache[hash]\n}\n\n/**\n * Add or update a cache entry for a file hash\n * Updates lastUsedTimestamp if the entry already exists\n */\nexport function setCachedTransaction(\n cache: TransactionCache,\n hash: string,\n transactionId: string,\n): TransactionCache {\n const now = Date.now()\n const existing = cache[hash]\n\n return {\n ...cache,\n [hash]: {\n createdAtTimestamp: existing?.createdAtTimestamp ?? now,\n lastUsedTimestamp: now,\n transactionId,\n },\n }\n}\n\n/**\n * Update the lastUsedTimestamp for an existing cache entry\n */\nexport function touchCacheEntry(cache: TransactionCache, hash: string): TransactionCache {\n const existing = cache[hash]\n if (!existing) {\n return cache\n }\n\n return {\n ...cache,\n [hash]: {\n ...existing,\n lastUsedTimestamp: Date.now(),\n },\n }\n}\n\n/**\n * Clean up the cache by keeping only the most recently used entries\n * Entries are sorted by lastUsedTimestamp descending, keeping the newest maxEntries\n */\nexport function cleanupCache(cache: TransactionCache, maxEntries: number): TransactionCache {\n const entries = Object.entries(cache)\n\n if (entries.length <= maxEntries) {\n return cache\n }\n\n // Sort by lastUsedTimestamp descending (newest first)\n const sorted = entries.sort(([, a], [, b]) => b.lastUsedTimestamp - a.lastUsedTimestamp)\n\n // Keep only the newest maxEntries\n const kept = sorted.slice(0, maxEntries)\n\n return Object.fromEntries(kept)\n}\n","/*\nHow it works:\n`this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value.\n*/\n\nclass Node {\n\tvalue;\n\tnext;\n\n\tconstructor(value) {\n\t\tthis.value = value;\n\t}\n}\n\nexport default class Queue {\n\t#head;\n\t#tail;\n\t#size;\n\n\tconstructor() {\n\t\tthis.clear();\n\t}\n\n\tenqueue(value) {\n\t\tconst node = new Node(value);\n\n\t\tif (this.#head) {\n\t\t\tthis.#tail.next = node;\n\t\t\tthis.#tail = node;\n\t\t} else {\n\t\t\tthis.#head = node;\n\t\t\tthis.#tail = node;\n\t\t}\n\n\t\tthis.#size++;\n\t}\n\n\tdequeue() {\n\t\tconst current = this.#head;\n\t\tif (!current) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#head = this.#head.next;\n\t\tthis.#size--;\n\n\t\t// Clean up tail reference when queue becomes empty\n\t\tif (!this.#head) {\n\t\t\tthis.#tail = undefined;\n\t\t}\n\n\t\treturn current.value;\n\t}\n\n\tpeek() {\n\t\tif (!this.#head) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this.#head.value;\n\n\t\t// TODO: Node.js 18.\n\t\t// return this.#head?.value;\n\t}\n\n\tclear() {\n\t\tthis.#head = undefined;\n\t\tthis.#tail = undefined;\n\t\tthis.#size = 0;\n\t}\n\n\tget size() {\n\t\treturn this.#size;\n\t}\n\n\t* [Symbol.iterator]() {\n\t\tlet current = this.#head;\n\n\t\twhile (current) {\n\t\t\tyield current.value;\n\t\t\tcurrent = current.next;\n\t\t}\n\t}\n\n\t* drain() {\n\t\twhile (this.#head) {\n\t\t\tyield this.dequeue();\n\t\t}\n\t}\n}\n","import Queue from 'yocto-queue';\n\nexport default function pLimit(concurrency) {\n\tlet rejectOnClear = false;\n\n\tif (typeof concurrency === 'object') {\n\t\t({concurrency, rejectOnClear = false} = concurrency);\n\t}\n\n\tvalidateConcurrency(concurrency);\n\n\tif (typeof rejectOnClear !== 'boolean') {\n\t\tthrow new TypeError('Expected `rejectOnClear` to be a boolean');\n\t}\n\n\tconst queue = new Queue();\n\tlet activeCount = 0;\n\n\tconst resumeNext = () => {\n\t\t// Process the next queued function if we're under the concurrency limit\n\t\tif (activeCount < concurrency && queue.size > 0) {\n\t\t\tactiveCount++;\n\t\t\tqueue.dequeue().run();\n\t\t}\n\t};\n\n\tconst next = () => {\n\t\tactiveCount--;\n\t\tresumeNext();\n\t};\n\n\tconst run = async (function_, resolve, arguments_) => {\n\t\t// Execute the function and capture the result promise\n\t\tconst result = (async () => function_(...arguments_))();\n\n\t\t// Resolve immediately with the promise (don't wait for completion)\n\t\tresolve(result);\n\n\t\t// Wait for the function to complete (success or failure)\n\t\t// We catch errors here to prevent unhandled rejections,\n\t\t// but the original promise rejection is preserved for the caller\n\t\ttry {\n\t\t\tawait result;\n\t\t} catch {}\n\n\t\t// Decrement active count and process next queued function\n\t\tnext();\n\t};\n\n\tconst enqueue = (function_, resolve, reject, arguments_) => {\n\t\tconst queueItem = {reject};\n\n\t\t// Queue the internal resolve function instead of the run function\n\t\t// to preserve the asynchronous execution context.\n\t\tnew Promise(internalResolve => { // eslint-disable-line promise/param-names\n\t\t\tqueueItem.run = internalResolve;\n\t\t\tqueue.enqueue(queueItem);\n\t\t}).then(run.bind(undefined, function_, resolve, arguments_)); // eslint-disable-line promise/prefer-await-to-then\n\n\t\t// Start processing immediately if we haven't reached the concurrency limit\n\t\tif (activeCount < concurrency) {\n\t\t\tresumeNext();\n\t\t}\n\t};\n\n\tconst generator = (function_, ...arguments_) => new Promise((resolve, reject) => {\n\t\tenqueue(function_, resolve, reject, arguments_);\n\t});\n\n\tObject.defineProperties(generator, {\n\t\tactiveCount: {\n\t\t\tget: () => activeCount,\n\t\t},\n\t\tpendingCount: {\n\t\t\tget: () => queue.size,\n\t\t},\n\t\tclearQueue: {\n\t\t\tvalue() {\n\t\t\t\tif (!rejectOnClear) {\n\t\t\t\t\tqueue.clear();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst abortError = AbortSignal.abort().reason;\n\n\t\t\t\twhile (queue.size > 0) {\n\t\t\t\t\tqueue.dequeue().reject(abortError);\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tconcurrency: {\n\t\t\tget: () => concurrency,\n\n\t\t\tset(newConcurrency) {\n\t\t\t\tvalidateConcurrency(newConcurrency);\n\t\t\t\tconcurrency = newConcurrency;\n\n\t\t\t\tqueueMicrotask(() => {\n\t\t\t\t\t// eslint-disable-next-line no-unmodified-loop-condition\n\t\t\t\t\twhile (activeCount < concurrency && queue.size > 0) {\n\t\t\t\t\t\tresumeNext();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t},\n\t\tmap: {\n\t\t\tasync value(iterable, function_) {\n\t\t\t\tconst promises = Array.from(iterable, (value, index) => this(function_, value, index));\n\t\t\t\treturn Promise.all(promises);\n\t\t\t},\n\t\t},\n\t});\n\n\treturn generator;\n}\n\nexport function limitFunction(function_, options) {\n\tconst limit = pLimit(options);\n\n\treturn (...arguments_) => limit(() => function_(...arguments_));\n}\n\nfunction validateConcurrency(concurrency) {\n\tif (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {\n\t\tthrow new TypeError('Expected `concurrency` to be a number from 1 and up');\n\t}\n}\n","import path from 'node:path'\nimport { Readable } from 'node:stream'\n\nimport { OnDemandFunding } from '@ardrive/turbo-sdk'\nimport * as mime from 'mime-types'\nimport pLimit from 'p-limit'\n\nimport {\n getAllFiles,\n getCachedTransaction,\n hashFile,\n setCachedTransaction,\n touchCacheEntry,\n type TransactionCache,\n} from './cache.js'\nimport type { UploadClient, UploadCost, UploadSize } from './upload-types.js'\n\ntype DataItemTag = { name: string; value: string }\n\n/**\n * Provenance tags stamped on every uploaded data item. In CI (GitHub Actions)\n * the deploying commit SHA is attached as a GIT-HASH tag; locally, where\n * GITHUB_SHA is unset, it is omitted.\n */\nexport function provenanceTags(): DataItemTag[] {\n const tags: DataItemTag[] = [{ name: 'App-Name', value: 'ARIO-Deploy' }]\n if (process.env.GITHUB_SHA) {\n tags.push({ name: 'GIT-HASH', value: process.env.GITHUB_SHA })\n }\n\n return tags\n}\n\nexport interface UploadResult {\n cacheHit: boolean\n cost?: UploadCost\n size?: UploadSize\n transactionId: string\n updatedCache?: TransactionCache\n}\n\nexport interface FolderUploadResult extends UploadResult {\n /** Number of files that were cache hits (not re-uploaded) */\n cacheHits: number\n /** Total number of files in the folder */\n totalFiles: number\n /** Number of files that were uploaded */\n uploaded: number\n}\n\nexport async function uploadFile(\n turbo: UploadClient,\n filePath: string,\n options?: {\n cache?: TransactionCache\n fundingMode?: OnDemandFunding\n },\n): Promise<UploadResult> {\n const mimeType = mime.lookup(filePath) || 'application/octet-stream'\n\n // Compute hash if cache is provided\n const fileHash = options?.cache ? await hashFile(filePath) : undefined\n\n // Check cache for hit\n if (fileHash && options?.cache) {\n const cached = getCachedTransaction(options.cache, fileHash)\n if (cached) {\n const updatedCache = touchCacheEntry(options.cache, fileHash)\n return {\n cacheHit: true,\n transactionId: cached.transactionId,\n updatedCache,\n }\n }\n }\n\n // Upload file\n const uploadResult = await turbo.uploadFile({\n dataItemOpts: {\n tags: [\n ...provenanceTags(),\n {\n name: 'anchor',\n value: new Date().toISOString(),\n },\n {\n name: 'Content-Type',\n value: mimeType,\n },\n ],\n },\n file: filePath,\n ...(options?.fundingMode && { fundingMode: options.fundingMode }),\n })\n\n if (!uploadResult?.id) {\n throw new Error('Failed to upload file: upload result missing transaction ID')\n }\n\n // Store in cache if provided\n if (fileHash && options?.cache) {\n const updatedCache = setCachedTransaction(options.cache, fileHash, uploadResult.id)\n return {\n cacheHit: false,\n cost: uploadResult.cost,\n size: uploadResult.size,\n transactionId: uploadResult.id,\n updatedCache,\n }\n }\n\n return {\n cacheHit: false,\n cost: uploadResult.cost,\n size: uploadResult.size,\n transactionId: uploadResult.id,\n }\n}\n\n/** Default concurrency for parallel file uploads */\nconst DEFAULT_UPLOAD_CONCURRENCY = 10\n\ninterface FileUploadTask {\n cached?: { transactionId: string }\n fullPath: string\n hash: string\n relativePath: string\n}\n\n/**\n * Upload a folder with per-file deduplication.\n * Each file is checked against the cache individually, and only uncached files are uploaded.\n * A manifest is then constructed and uploaded to create the folder structure.\n *\n * @param turbo - Upload client used for file and manifest uploads.\n * @param folderPath - Folder to upload.\n * @param options - Upload options for caching, concurrency, funding, and failure handling.\n * @returns Folder upload result including manifest transaction ID and cache stats.\n */\nexport async function uploadFolder(\n turbo: UploadClient,\n folderPath: string,\n options?: {\n cache?: TransactionCache\n concurrency?: number\n fundingMode?: OnDemandFunding\n throwOnFailure?: boolean\n },\n): Promise<FolderUploadResult> {\n const concurrency = options?.concurrency ?? DEFAULT_UPLOAD_CONCURRENCY\n const useCache = options?.cache !== undefined\n\n // Get all files in the folder\n const relativePaths = getAllFiles(folderPath)\n\n if (relativePaths.length === 0) {\n throw new Error('Folder is empty, nothing to upload')\n }\n\n // Prepare file tasks with hashes (if caching is enabled)\n const tasks: FileUploadTask[] = await Promise.all(\n relativePaths.map(async (relativePath) => {\n const fullPath = path.join(folderPath, relativePath)\n const hash = useCache ? await hashFile(fullPath) : ''\n return { fullPath, hash, relativePath }\n }),\n )\n\n // Check cache for each file\n let cache = options?.cache ?? {}\n let cacheHits = 0\n\n for (const task of tasks) {\n if (useCache && task.hash) {\n const cached = getCachedTransaction(cache, task.hash)\n if (cached) {\n task.cached = { transactionId: cached.transactionId }\n cache = touchCacheEntry(cache, task.hash)\n cacheHits++\n }\n }\n }\n\n // If all files are cached, we still need to build and upload a new manifest\n // (because the manifest itself has a unique transaction ID each time)\n const uncachedTasks = tasks.filter((t) => !t.cached)\n\n // Upload uncached files with concurrency control using p-limit\n const limit = pLimit(concurrency)\n\n const uploadResults = await Promise.all(\n uncachedTasks.map((task) =>\n limit(async () => {\n const mimeType = mime.lookup(task.fullPath) || 'application/octet-stream'\n\n const uploadResult = await turbo.uploadFile({\n dataItemOpts: {\n tags: [...provenanceTags(), { name: 'Content-Type', value: mimeType }],\n },\n file: task.fullPath,\n ...(options?.fundingMode && { fundingMode: options.fundingMode }),\n })\n\n if (!uploadResult?.id) {\n if (options?.throwOnFailure) {\n throw new Error(`Failed to upload file: ${task.relativePath}`)\n }\n\n return { hash: task.hash, task, transactionId: null }\n }\n\n return { hash: task.hash, task, transactionId: uploadResult.id }\n }),\n ),\n )\n\n // Update cache with all successful uploads (done sequentially to avoid race conditions)\n for (const result of uploadResults) {\n if (useCache && result.hash && result.transactionId) {\n cache = setCachedTransaction(cache, result.hash, result.transactionId)\n }\n }\n\n // Check for any failed uploads\n const failedUploads = uploadResults.filter((r) => r.transactionId === null)\n if (failedUploads.length > 0 && options?.throwOnFailure) {\n throw new Error(\n `Failed to upload ${failedUploads.length} file(s): ${failedUploads.map((f) => f.task.relativePath).join(', ')}`,\n )\n }\n\n // Build manifest paths from cached and newly uploaded files\n const manifestPaths: Record<string, { id: string }> = {}\n\n for (const task of tasks) {\n let transactionId: string | null = null\n\n if (task.cached) {\n transactionId = task.cached.transactionId\n } else {\n const uploadResult = uploadResults.find((r) => r.task === task)\n transactionId = uploadResult?.transactionId ?? null\n }\n\n if (transactionId) {\n manifestPaths[task.relativePath] = { id: transactionId }\n\n // Add directory index support: if file is dir/index.html, also add dir → same ID\n if (task.relativePath.endsWith('/index.html')) {\n const dirPath = task.relativePath.replace(/\\/index\\.html$/, '')\n manifestPaths[dirPath] = { id: transactionId }\n }\n }\n }\n\n // Determine the index path (root index.html)\n const indexPath = relativePaths.includes('index.html') ? 'index.html' : undefined\n\n // Build the manifest\n const manifest = {\n manifest: 'arweave/paths',\n version: '0.2.0',\n ...(indexPath && { index: { path: indexPath } }),\n paths: manifestPaths,\n }\n\n // Upload the manifest\n const manifestBuffer = Buffer.from(JSON.stringify(manifest))\n const manifestUploadResult = await turbo.uploadFile({\n dataItemOpts: {\n tags: [\n ...provenanceTags(),\n { name: 'Content-Type', value: 'application/x.arweave-manifest+json' },\n { name: 'Device', value: 'manifest@1.0' },\n ],\n },\n fileSizeFactory: () => manifestBuffer.length,\n fileStreamFactory: () => Readable.from(manifestBuffer),\n ...(options?.fundingMode && { fundingMode: options.fundingMode }),\n })\n\n if (!manifestUploadResult?.id) {\n throw new Error('Failed to upload manifest: upload result missing transaction ID')\n }\n\n return {\n cacheHit: cacheHits === tasks.length,\n cacheHits,\n totalFiles: tasks.length,\n transactionId: manifestUploadResult.id,\n updatedCache: useCache ? cache : undefined,\n uploaded: uncachedTasks.length - failedUploads.length,\n }\n}\n"],"names":[],"mappings":"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","x_google_ignoreList":[1,2]}