permaweb-deploy 3.4.2 → 3.4.4

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 (37) hide show
  1. package/README.md +75 -20
  2. package/bin/run.js +0 -0
  3. package/dist/chunks/display-BgIiyBIu.js +60 -0
  4. package/dist/chunks/display-BgIiyBIu.js.map +1 -0
  5. package/dist/chunks/upload-workflow-DMKlwZve.js +1067 -0
  6. package/dist/chunks/upload-workflow-DMKlwZve.js.map +1 -0
  7. package/dist/chunks/{uploader-DDS_d-O_.js → uploader-CIHu22Fw.js} +5 -1
  8. package/dist/chunks/uploader-CIHu22Fw.js.map +1 -0
  9. package/dist/commands/deploy.js +115 -29
  10. package/dist/commands/deploy.js.map +1 -1
  11. package/dist/commands/upload.js +49 -7
  12. package/dist/commands/upload.js.map +1 -1
  13. package/dist/constants/flags.js +78 -1
  14. package/dist/constants/flags.js.map +1 -1
  15. package/dist/src/commands/deploy.d.ts.map +1 -1
  16. package/dist/src/commands/upload.d.ts.map +1 -1
  17. package/dist/src/constants/flags.d.ts +40 -1
  18. package/dist/src/constants/flags.d.ts.map +1 -1
  19. package/dist/src/types/index.d.ts +1 -1
  20. package/dist/src/types/index.d.ts.map +1 -1
  21. package/dist/src/utils/__tests__/display.test.d.ts +2 -0
  22. package/dist/src/utils/__tests__/display.test.d.ts.map +1 -0
  23. package/dist/src/utils/__tests__/hyperbeam-uploader.test.d.ts +2 -0
  24. package/dist/src/utils/__tests__/hyperbeam-uploader.test.d.ts.map +1 -0
  25. package/dist/src/utils/display.d.ts +5 -0
  26. package/dist/src/utils/display.d.ts.map +1 -0
  27. package/dist/src/utils/hyperbeam-uploader.d.ts +93 -0
  28. package/dist/src/utils/hyperbeam-uploader.d.ts.map +1 -0
  29. package/dist/src/utils/uploader.d.ts +11 -3
  30. package/dist/src/utils/uploader.d.ts.map +1 -1
  31. package/dist/src/workflows/upload-workflow.d.ts +14 -1
  32. package/dist/src/workflows/upload-workflow.d.ts.map +1 -1
  33. package/dist/utils/uploader.js +1 -1
  34. package/dist/workflows/upload-workflow.js +9 -146
  35. package/dist/workflows/upload-workflow.js.map +1 -1
  36. package/package.json +27 -24
  37. package/dist/chunks/uploader-DDS_d-O_.js.map +0 -1
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Permaweb Deploy
2
2
 
3
- Inspired by the [cookbook github action deployment guide](https://cookbook.arweave.dev/guides/deployment/github-action.html), `permaweb-deploy` is a Node.js command-line tool designed to streamline the deployment of web applications to the permaweb using Arweave. It uploads your build folder or a single file, creates Arweave manifests, and updates ArNS (Arweave Name Service) records via ANT (Arweave Name Token) with the transaction ID.
3
+ Inspired by the [cookbook github action deployment guide](https://cookbook.arweave.dev/guides/deployment/github-action.html), `permaweb-deploy` is a Node.js command-line tool designed to streamline the deployment of web applications to the permaweb using Arweave. It uploads your build folder or a single file, creates Arweave manifests, and can optionally update ArNS (Arweave Name Service) records via ANT (Arweave Name Token) with the transaction ID.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - **Turbo SDK Integration:** Uses Turbo SDK for fast, reliable file uploads to Arweave
8
8
  - **On-Demand Payment:** Pay with ARIO or Base-ETH tokens on-demand during upload
9
9
  - **Arweave Manifest v0.2.0:** Creates manifests with fallback support for SPAs
10
- - **ArNS Updates:** Updates ArNS records via ANT with new transaction IDs and metadata
10
+ - **Optional ArNS Updates:** Updates ArNS records via ANT with new transaction IDs and metadata
11
11
  - **Automated Workflow:** Integrates with GitHub Actions for continuous deployment
12
12
  - **Git Hash Tagging:** Automatically tags deployments with Git commit hashes
13
13
  - **404 Fallback Detection:** Automatically detects and sets 404.html as fallback
@@ -77,7 +77,7 @@ Run the deploy command without arguments to be guided through all deployment opt
77
77
  permaweb-deploy deploy
78
78
  ```
79
79
 
80
- This will prompt you for:
80
+ This uploads to the permaweb by default. Use `--use-arns` or `--arns-name` to run the guided ArNS update flow, which will prompt you for:
81
81
 
82
82
  - ArNS name
83
83
  - Wallet method (file, string, or environment variable)
@@ -91,7 +91,10 @@ Use flags for faster, scriptable deployments:
91
91
 
92
92
  ```bash
93
93
  # Basic deployment with wallet file
94
- permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json
94
+ permaweb-deploy deploy --wallet ./wallet.json
95
+
96
+ # Deployment with ArNS update
97
+ permaweb-deploy deploy --use-arns --arns-name my-app --wallet ./wallet.json
95
98
  ```
96
99
 
97
100
  Deploy using private key directly:
@@ -118,11 +121,12 @@ Deploy a single file:
118
121
  permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --deploy-file ./path/to/file.txt
119
122
  ```
120
123
 
121
- ### Upload only (no ArNS)
124
+ ### Upload/deploy without ArNS
122
125
 
123
- To upload a folder or file to Arweave **without** updating an ArNS name, use the `upload` command (same Turbo upload, dedupe cache, and payment options as deploy, minus ArNS flags):
126
+ `deploy` uploads without updating ArNS by default. You can also use the `upload` command explicitly for the same Turbo upload, dedupe cache, and payment options as deploy, minus ArNS flags:
124
127
 
125
128
  ```bash
129
+ permaweb-deploy deploy --wallet ./wallet.json --deploy-folder ./dist
126
130
  permaweb-deploy upload --wallet ./wallet.json --deploy-folder ./dist
127
131
  permaweb-deploy upload --wallet ./wallet.json --deploy-file ./dist/index.html
128
132
  DEPLOY_KEY=$(base64 -i wallet.json) permaweb-deploy upload --deploy-folder ./dist
@@ -189,14 +193,14 @@ permaweb-deploy deploy --arns-name my-app --sig-type ethereum --private-key "0x.
189
193
 
190
194
  ### Bundler service
191
195
 
192
- Uploads go through a [Turbo](https://docs.ardrive.io/docs/turbo/) **bundler service** (HTTP API that bundles data for Arweave). By default, permaweb-deploy uses ArDrive’s production bundler (`https://upload.ardrive.io`). **`--uploader`** sets the **base URL** of the bundler service to use (scheme + host; typically no path).
196
+ Uploads go through a bundler service that accepts signed data items and posts them to Arweave. By default, permaweb-deploy uses the [Turbo](https://docs.ardrive.io/docs/turbo/) API and ArDrive’s production bundler (`https://upload.ardrive.io`). **`--uploader`** sets the **base URL** of the bundler service to use (scheme + host; typically no path).
193
197
 
194
- | When to use | Example value |
195
- | ------------------------- | ------------------------------------------------------------- |
196
- | **Default** (omit flag) | ArDrive production bundler — same as Turbo CLI defaults |
197
- | **Arweave bundler** | `https://up.arweave.net` |
198
- | **Development / staging** | `https://upload.ardrive.dev` |
199
- | **Custom or self-hosted** | Your own base URL if it implements the Turbo bundler protocol |
198
+ | When to use | Example value |
199
+ | ------------------------- | ----------------------------------------------------------------- |
200
+ | **Default** (omit flag) | ArDrive production bundler — same as Turbo CLI defaults |
201
+ | **Arweave bundler** | `https://up.arweave.net` |
202
+ | **Development / staging** | `https://upload.ardrive.dev` |
203
+ | **Custom or self-hosted** | Your own base URL if it implements the selected uploader protocol |
200
204
 
201
205
  **Examples:**
202
206
 
@@ -207,16 +211,46 @@ permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --uploader http
207
211
  permaweb-deploy upload --wallet ./wallet.json --deploy-folder ./dist --uploader https://up.arweave.net
208
212
  ```
209
213
 
214
+ To upload through a HyperBEAM bundler, set `--uploader-type hyperbeam` and pass the node URL:
215
+
216
+ ```bash
217
+ permaweb-deploy upload \
218
+ --wallet ./wallet.json \
219
+ --deploy-folder ./dist \
220
+ --uploader-type hyperbeam \
221
+ --uploader https://hyperbeam.example.com
222
+
223
+ permaweb-deploy deploy \
224
+ --wallet ./wallet.json \
225
+ --deploy-folder ./dist \
226
+ --uploader-type hyperbeam \
227
+ --uploader https://hyperbeam.example.com
228
+ ```
229
+
230
+ If the node follows the standard AO-paid HyperBEAM bundler flow, either command can fund the uploader wallet before uploading:
231
+
232
+ ```bash
233
+ permaweb-deploy upload \
234
+ --wallet ./wallet.json \
235
+ --deploy-folder ./dist \
236
+ --uploader-type hyperbeam \
237
+ --uploader https://hyperbeam.example.com \
238
+ --hyperbeam-auto-fund
239
+ ```
240
+
210
241
  **Notes:**
211
242
 
212
- - Billing and signer behavior still follow Turbo; if an alternate bundler has different rules, check that provider’s docs.
213
- - Use a **base URL only** (e.g. `https://up.arweave.net`), not a path to a specific file or route.
243
+ - Turbo billing and signer behavior follow Turbo.
244
+ - HyperBEAM uploads require an Arweave JWK signer. Before uploading, the CLI checks the node address from `/~meta@1.0/info/address` against `https://arweave.net/wallet/<address>/balance` and aborts if the bundler wallet has 0 AR. With `--hyperbeam-auto-fund`, the CLI signs each data item, asks the node's byte-pricing profile for a quote, sends AO to the node deposit address, imports that deposit through `/~ao-payment@1.0/ingest`, and waits for the uploader's balance at `/ledger~node-process@1.0/now/balance/<address>` before uploading. The default route is `/~bundler@1.0/item?codec-device=ans104@1.0`; override it with `--hyperbeam-upload-path` if your node exposes a different bundler route.
245
+ - `--hyperbeam-fund-amount` is an optional override for the minimum local ledger balance to ensure, in AO base units. Without it, `--hyperbeam-auto-fund` uses the node's byte-pricing quote for the signed byte count. Use `--hyperbeam-token-id` only for a non-default AO token process, and `--hyperbeam-ledger-id` only for a non-default local ledger profile.
246
+ - Use a **base URL only** (e.g. `https://up.arweave.net` or `https://hyperbeam.example.com`), not a path to a specific file or route.
214
247
 
215
248
  ### Command Options
216
249
 
217
- **`deploy`** (ArNS update):
250
+ **`deploy`** (upload by default, optional ArNS update):
218
251
 
219
- - `--arns-name, -n` (required): The ArNS name to update
252
+ - `--use-arns`: Update an ArNS/ANT record after upload
253
+ - `--arns-name, -n`: The ArNS name to update. Required when using `--use-arns`; also implies ArNS mode for backwards compatibility.
220
254
  - `--ario-process, -p`: ARIO process to use (`mainnet`, `testnet`, or a custom process ID). Default: `mainnet`
221
255
  - `--deploy-folder, -d`: Folder to deploy. Default: `./dist`
222
256
  - `--deploy-file, -f`: Deploy a single file instead of a folder
@@ -229,9 +263,16 @@ permaweb-deploy upload --wallet ./wallet.json --deploy-folder ./dist --uploader
229
263
  - `--max-token-amount`: Maximum token amount for on-demand payment (used with `--on-demand`)
230
264
  - `--no-dedupe`: Disable deduplication (do not cache or reuse previous uploads)
231
265
  - `--dedupe-cache-max-entries`: Maximum number of entries to keep in the dedupe cache (LRU). Default: `10000`
232
- - `--uploader`: Base URL of the Turbo **bundler service** to use (default: `https://upload.ardrive.io`). See [Bundler service](#bundler-service) above.
266
+ - `--uploader`: Base URL of the bundler service to use. See [Bundler service](#bundler-service) above.
267
+ - `--uploader-type`: Upload protocol to use (`turbo` or `hyperbeam`). Default: `turbo`
268
+ - `--hyperbeam-upload-path`: HyperBEAM bundler route. Default: `/~bundler@1.0/item?codec-device=ans104@1.0`
269
+ - `--hyperbeam-auto-fund`: Automatically fund the HyperBEAM local ledger before upload
270
+ - `--hyperbeam-fund-amount`: Optional minimum HyperBEAM local ledger balance override, in token base units
271
+ - `--hyperbeam-token-id`: Advanced AO token process ID override
272
+ - `--hyperbeam-ledger-id`: Advanced local HyperBEAM ledger ID override
273
+ - `--hyperbeam-ao-state-url`: AO state endpoint used while waiting for auto-fund transfer assignment. Default: `https://state.forward.computer`
233
274
 
234
- **`upload`** (no ArNS): accepts `--deploy-folder`, `--deploy-file`, wallet/signer flags, `--uploader`, `--on-demand` / `--max-token-amount`, and dedupe flags only.
275
+ **`upload`** (explicit upload without ArNS): accepts `--deploy-folder`, `--deploy-file`, wallet/signer flags, uploader flags, `--on-demand` / `--max-token-amount`, and dedupe flags only.
235
276
 
236
277
  ### Deduplication
237
278
 
@@ -405,6 +446,20 @@ jobs:
405
446
  max-token-amount: '2.0'
406
447
  ```
407
448
 
449
+ ### With HyperBEAM
450
+
451
+ ```yaml
452
+ - name: Deploy through a HyperBEAM bundler
453
+ uses: permaweb/permaweb-deploy@v1
454
+ with:
455
+ deploy-key: ${{ secrets.DEPLOY_KEY }}
456
+ arns-name: myapp
457
+ deploy-folder: ./dist
458
+ uploader-type: hyperbeam
459
+ uploader: https://hyperbeam.example.com
460
+ hyperbeam-auto-fund: 'true'
461
+ ```
462
+
408
463
  ### Disabling Deduplication
409
464
 
410
465
  By default, the action caches transaction IDs to avoid re-uploading unchanged files. To disable this:
@@ -566,7 +621,7 @@ permaweb-deploy/
566
621
 
567
622
  - **Dedicated Wallet:** Always use a dedicated wallet for deployments to minimize security risks
568
623
  - **Wallet Encoding:** Arweave wallets must be base64 encoded to be used in the deployment script
569
- - **ArNS Name:** The ArNS Name must be passed so that the ANT Process can be resolved to update the target undername or root record
624
+ - **ArNS Name:** Required only when updating an ANT/ArNS target undername or root record
570
625
  - **Turbo Credits:** Ensure your wallet has sufficient Turbo Credits, or use on-demand payment for automatic funding
571
626
  - **On-Demand Limits:** Set reasonable `--max-token-amount` limits to prevent unexpected costs
572
627
  - **Secret Management:** Keep your `DEPLOY_KEY` secret secure and never commit it to your repository
package/bin/run.js CHANGED
File without changes
@@ -0,0 +1,60 @@
1
+ import boxen from 'boxen';
2
+ import chalk from 'chalk';
3
+ import Table from 'cli-table3';
4
+
5
+ const AO_BASE_UNITS = 1000000000000n;
6
+ function formatUploadSize(size) {
7
+ return `${(size.signedBytes ?? size.payloadBytes).toLocaleString()} bytes`;
8
+ }
9
+ function formatUploadCost(cost) {
10
+ if (cost.token !== "AO") {
11
+ return `${cost.amount.toString()}`;
12
+ }
13
+ const whole = cost.amount / AO_BASE_UNITS;
14
+ const fraction = cost.amount % AO_BASE_UNITS;
15
+ const decimal = fraction === 0n ? whole.toString() : `${whole.toString()}.${fraction.toString().padStart(12, "0").replaceAll(/0+$/g, "")}`;
16
+ return `${decimal} AO`;
17
+ }
18
+ function fundingDisplay(section) {
19
+ const fundingLine = section.split("\n").map((line) => line.trim()).find((line) => line.startsWith("- "))?.replace(/^- /, "");
20
+ if (!fundingLine) {
21
+ return section;
22
+ }
23
+ return fundingLine.replace(/^AO: send funds to /, "Sending AO to ").replace(/\. Local ledger:.*$/, "");
24
+ }
25
+ function uploadErrorTable(message, title = "Upload failed") {
26
+ const table = new Table({
27
+ style: { head: [] }
28
+ });
29
+ const sections = message.split(/\n{2,}/).map((section) => section.trim()).filter(Boolean);
30
+ for (const [index, section] of sections.entries()) {
31
+ if (index === 0) {
32
+ table.push(["Error", chalk.red(section)]);
33
+ continue;
34
+ }
35
+ if (section.startsWith("Required upload credit:")) {
36
+ table.push([
37
+ "Required upload credit",
38
+ chalk.blue(section.replace(/^Required upload credit:\s*/, ""))
39
+ ]);
40
+ continue;
41
+ }
42
+ if (section.startsWith("The HyperBEAM node requires AO")) {
43
+ table.push(["Funding", fundingDisplay(section)]);
44
+ continue;
45
+ }
46
+ table.push(["Note", section]);
47
+ }
48
+ return boxen(`${chalk.red.bold(title)}
49
+
50
+ ${table.toString()}`, {
51
+ borderColor: "red",
52
+ borderStyle: "round",
53
+ padding: 1,
54
+ title: chalk.bold("Permaweb Deploy"),
55
+ titleAlignment: "center"
56
+ });
57
+ }
58
+
59
+ export { formatUploadCost as a, formatUploadSize as f, uploadErrorTable as u };
60
+ //# sourceMappingURL=display-BgIiyBIu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-BgIiyBIu.js","sources":["../../src/utils/display.ts"],"sourcesContent":["import boxen from 'boxen'\nimport chalk from 'chalk'\n// eslint-disable-next-line import/no-named-as-default\nimport Table from 'cli-table3'\n\nimport type { UploadCost, UploadSize } from './hyperbeam-uploader.js'\n\nconst AO_BASE_UNITS = 1_000_000_000_000n\n\nexport function formatUploadSize(size: UploadSize): string {\n return `${(size.signedBytes ?? size.payloadBytes).toLocaleString()} bytes`\n}\n\nexport function formatUploadCost(cost: UploadCost): string {\n if (cost.token !== 'AO') {\n return `${cost.amount.toString()}`\n }\n\n const whole = cost.amount / AO_BASE_UNITS\n const fraction = cost.amount % AO_BASE_UNITS\n const decimal =\n fraction === 0n\n ? whole.toString()\n : `${whole.toString()}.${fraction.toString().padStart(12, '0').replaceAll(/0+$/g, '')}`\n\n return `${decimal} AO`\n}\n\nfunction fundingDisplay(section: string): string {\n const fundingLine = section\n .split('\\n')\n .map((line) => line.trim())\n .find((line) => line.startsWith('- '))\n ?.replace(/^- /, '')\n\n if (!fundingLine) {\n return section\n }\n\n return fundingLine\n .replace(/^AO: send funds to /, 'Sending AO to ')\n .replace(/\\. Local ledger:.*$/, '')\n}\n\nexport function uploadErrorTable(message: string, title = 'Upload failed'): string {\n const table = new Table({\n style: { head: [] },\n })\n const sections = message\n .split(/\\n{2,}/)\n .map((section) => section.trim())\n .filter(Boolean)\n\n for (const [index, section] of sections.entries()) {\n if (index === 0) {\n table.push(['Error', chalk.red(section)])\n continue\n }\n\n if (section.startsWith('Required upload credit:')) {\n table.push([\n 'Required upload credit',\n chalk.blue(section.replace(/^Required upload credit:\\s*/, '')),\n ])\n continue\n }\n\n if (section.startsWith('The HyperBEAM node requires AO')) {\n table.push(['Funding', fundingDisplay(section)])\n continue\n }\n\n table.push(['Note', section])\n }\n\n return boxen(`${chalk.red.bold(title)}\\n\\n${table.toString()}`, {\n borderColor: 'red',\n borderStyle: 'round',\n padding: 1,\n title: chalk.bold('Permaweb Deploy'),\n titleAlignment: 'center',\n })\n}\n"],"names":[],"mappings":"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"}