permaweb-deploy 2.2.0 → 2.4.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.
- package/README.md +86 -50
- package/dist/index.js +121 -35
- package/package.json +3 -3
- package/src/index.js +147 -29
- package/src/turbo/index.js +0 -121
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Permaweb Deployment Package
|
|
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
|
|
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.
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
|
|
6
7
|
- **Turbo SDK Integration:** Uses Turbo SDK for fast, reliable file uploads to Arweave
|
|
7
8
|
- **Arweave Manifest v0.2.0:** Creates manifests with fallback support for SPAs
|
|
8
9
|
- **ArNS Updates:** Updates ArNS records via ANT with new transaction IDs and metadata
|
|
@@ -10,6 +11,7 @@ Inspired by the [cookbook github action deployment guide](https://cookbook.arwea
|
|
|
10
11
|
- **Git Hash Tagging:** Automatically tags deployments with Git commit hashes
|
|
11
12
|
- **404 Fallback Detection:** Automatically detects and sets 404.html as fallback
|
|
12
13
|
- **Network Support:** Supports mainnet, testnet, and custom ARIO process IDs
|
|
14
|
+
- **Flexible Deployment:** Supports deploying a folder or a single file
|
|
13
15
|
|
|
14
16
|
### Installation
|
|
15
17
|
|
|
@@ -20,39 +22,30 @@ npm install permaweb-deploy
|
|
|
20
22
|
```
|
|
21
23
|
|
|
22
24
|
For development use:
|
|
25
|
+
|
|
23
26
|
```bash
|
|
24
27
|
npm install permaweb-deploy --save-dev
|
|
25
28
|
```
|
|
26
29
|
|
|
27
30
|
For Yarn users:
|
|
31
|
+
|
|
28
32
|
```bash
|
|
29
33
|
yarn add permaweb-deploy --dev --ignore-engines
|
|
30
34
|
```
|
|
31
35
|
|
|
32
36
|
### Prerequisites
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
2. **ArNS Name:** Own or control an ArNS name (which has an associated ANT process)
|
|
37
|
-
3. **Wallet Encoding:** Encode your Arweave wallet key in base64 format:
|
|
38
|
+
1. **For Arweave signer (default):** Encode your Arweave wallet key in base64 format and set it as a GitHub secret:
|
|
39
|
+
|
|
38
40
|
```bash
|
|
39
41
|
base64 -i wallet.json | pbcopy
|
|
40
42
|
```
|
|
41
|
-
4. **GitHub Secret:** Set the encoded wallet as a GitHub secret named `DEPLOY_KEY`
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
2. **For Ethereum/Polygon/KYVE signers:** Use your raw private key (no encoding needed) as the `DEPLOY_KEY`.
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
permaweb-deploy [options]
|
|
48
|
-
```
|
|
46
|
+
3. Ensure that the secret name for the encoded wallet or private key is `DEPLOY_KEY`.
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|--------|-------|-------------|---------|----------|
|
|
52
|
-
| `--arns-name` | `-n` | ArNS name for deployment | - | ✅ |
|
|
53
|
-
| `--ario-process` | `-p` | ARIO process ID or "mainnet"/"testnet" | `mainnet` | ❌ |
|
|
54
|
-
| `--deploy-folder` | `-d` | Folder to deploy | `./dist` | ❌ |
|
|
55
|
-
| `--undername` | `-u` | ANT undername to update | `@` | ❌ |
|
|
48
|
+
⚠️ **Important:** Use a dedicated wallet for deployments to minimize security risks. Ensure your wallet has sufficient Turbo Credits for uploads.
|
|
56
49
|
|
|
57
50
|
### Usage
|
|
58
51
|
|
|
@@ -61,67 +54,107 @@ To deploy your application, ensure you have a build script and a deployment scri
|
|
|
61
54
|
```json
|
|
62
55
|
"scripts": {
|
|
63
56
|
"build": "your-build-command",
|
|
64
|
-
"deploy
|
|
57
|
+
"deploy": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
|
|
65
58
|
}
|
|
66
59
|
```
|
|
67
60
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
61
|
+
Replace `<ARNS_NAME>` with your ArNS name. To deploy to an undername, add `--undername <UNDERNAME>`.
|
|
62
|
+
|
|
63
|
+
#### CLI Options
|
|
64
|
+
|
|
65
|
+
- `--arns-name, -n` (required): The ArNS name to update.
|
|
66
|
+
- `--ario-process, -p`: ARIO process to use (`mainnet`, `testnet`, or a custom process ID). Default: mainnet.
|
|
67
|
+
- `--deploy-folder, -d`: Folder to deploy. Default: `./dist`.
|
|
68
|
+
- `--deploy-file, -f`: Deploy a single file instead of a folder.
|
|
69
|
+
- `--undername, -u`: ANT undername to update. Default: `@`.
|
|
70
|
+
- `--ttl-seconds, -t`: TTL in seconds for the ANT record (60-86400). Default: `3600`.
|
|
71
|
+
- `--sig-type, -s`: Signer type for deployment. Choices: `arweave`, `ethereum`, `polygon`, `kyve`. Default: `arweave`.
|
|
72
|
+
- `--help`: Show all available options and usage examples.
|
|
73
|
+
- `--version`: Show the current version number.
|
|
74
|
+
|
|
75
|
+
#### Example CLI Usage
|
|
76
|
+
|
|
77
|
+
Deploy a folder (default):
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name my-app
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Deploy a specific folder:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name my-app --deploy-folder ./build
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Deploy a single file:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name my-app --deploy-file ./path/to/file.txt
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Deploy to an undername:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name my-app --undername staging
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Deploy with a custom TTL:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name my-app --ttl-seconds 7200
|
|
71
105
|
```
|
|
72
106
|
|
|
73
|
-
|
|
107
|
+
Deploy using a different signer (e.g., Ethereum):
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
DEPLOY_KEY=<ETH_PRIVATE_KEY> npx permaweb-deploy --arns-name my-app --sig-type ethereum
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### Example `package.json` Scripts
|
|
74
114
|
|
|
75
|
-
**Mainnet (default) config:**
|
|
76
115
|
```json
|
|
77
116
|
"scripts": {
|
|
78
|
-
"build": "
|
|
79
|
-
"deploy
|
|
117
|
+
"build": "vite build",
|
|
118
|
+
"deploy": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
|
|
80
119
|
}
|
|
81
120
|
```
|
|
82
121
|
|
|
83
|
-
|
|
122
|
+
#### ARIO Process Examples
|
|
123
|
+
|
|
124
|
+
**Mainnet (default):**
|
|
125
|
+
|
|
84
126
|
```json
|
|
85
127
|
"scripts": {
|
|
86
|
-
"
|
|
87
|
-
"deploy-main": "npm run build && permaweb-deploy --arns-name <ARNS_NAME> --ario-process testnet"
|
|
128
|
+
"deploy-main": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
|
|
88
129
|
}
|
|
89
130
|
```
|
|
90
131
|
|
|
91
|
-
**
|
|
132
|
+
**Testnet:**
|
|
133
|
+
|
|
92
134
|
```json
|
|
93
135
|
"scripts": {
|
|
94
|
-
"
|
|
95
|
-
"deploy-main": "npm run build && permaweb-deploy --arns-name <ARNS_NAME> --ario-process GaQrvEMKBpkjofgnBi_B3IgIDmY_XYelVLB6GcRGrHc"
|
|
136
|
+
"deploy-test": "npm run build && permaweb-deploy --arns-name <ARNS_NAME> --ario-process testnet"
|
|
96
137
|
}
|
|
97
138
|
```
|
|
98
139
|
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name <ARNS_NAME>
|
|
102
|
-
```
|
|
140
|
+
**Custom process ID:**
|
|
103
141
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- **ArNS Record TTL:** Sets 3600 seconds (1 hour) TTL for ArNS records via ANT
|
|
110
|
-
- **Deployment Tags:** Automatically adds `App-Name: Permaweb-Deploy` and Git hash tags
|
|
111
|
-
- **Network Support:** Supports mainnet, testnet, and custom ARIO process IDs
|
|
142
|
+
```json
|
|
143
|
+
"scripts": {
|
|
144
|
+
"deploy-custom": "npm run build && permaweb-deploy --arns-name <ARNS_NAME> --ario-process <PROCESS_ID>"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
112
147
|
|
|
113
148
|
### GitHub Actions Workflow
|
|
114
149
|
|
|
115
150
|
To automate the deployment, set up a GitHub Actions workflow as follows:
|
|
116
151
|
|
|
117
152
|
```yaml
|
|
118
|
-
name:
|
|
119
|
-
|
|
153
|
+
name: Deploy to Permaweb
|
|
120
154
|
on:
|
|
121
155
|
push:
|
|
122
156
|
branches:
|
|
123
|
-
-
|
|
124
|
-
|
|
157
|
+
- main
|
|
125
158
|
jobs:
|
|
126
159
|
publish:
|
|
127
160
|
runs-on: ubuntu-latest
|
|
@@ -131,20 +164,23 @@ jobs:
|
|
|
131
164
|
with:
|
|
132
165
|
node-version: 20.x
|
|
133
166
|
- run: npm install
|
|
134
|
-
- run: npm run deploy
|
|
167
|
+
- run: npm run deploy
|
|
135
168
|
env:
|
|
136
169
|
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
|
137
170
|
```
|
|
138
171
|
|
|
172
|
+
|
|
139
173
|
### Security & Best Practices
|
|
174
|
+
|
|
140
175
|
- **Dedicated Wallet:** Always use a dedicated wallet for deployments to minimize security risks
|
|
141
|
-
- **Wallet Encoding:**
|
|
176
|
+
- **Wallet Encoding:** Arweave wallets must be base64 encoded to be used in the deployment script
|
|
142
177
|
- **ArNS Name:** The ArNS Name must be passed so that the ANT Process can be resolved to update the target undername or root record
|
|
143
178
|
- **Turbo Credits:** Ensure your wallet has sufficient Turbo Credits before deployment
|
|
144
179
|
- **Secret Management:** Keep your `DEPLOY_KEY` secret secure and never commit it to your repository
|
|
145
180
|
- **Build Security:** Always check your build for exposed environmental secrets before deployment, as data on Arweave is permanent
|
|
146
181
|
|
|
147
182
|
### Troubleshooting
|
|
183
|
+
|
|
148
184
|
- **Error: "ARNS_NAME not configured":** Ensure you're passing the `--arns-name` flag with a valid ArNS name
|
|
149
185
|
- **Error: "DEPLOY_KEY not configured":** Verify your base64 encoded wallet is set as the `DEPLOY_KEY` environment variable
|
|
150
186
|
- **Error: "deploy-folder does not exist":** Check that your build folder exists and the path is correct
|
|
@@ -154,8 +190,8 @@ jobs:
|
|
|
154
190
|
- **Insufficient Turbo Credits:** Ensure your wallet has enough Turbo Credits for the deployment
|
|
155
191
|
|
|
156
192
|
### Dependencies
|
|
193
|
+
|
|
157
194
|
- **@ar.io/sdk:** - For ANT operations and ArNS management
|
|
158
195
|
- **@ardrive/turbo-sdk:** - For fast file uploads to Arweave
|
|
159
196
|
- **@permaweb/aoconnect:** - For AO network connectivity
|
|
160
|
-
- **mime-types:** - For automatic content type detection
|
|
161
197
|
- **yargs:** - For CLI argument parsing
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
var _turboSdk = require("@ardrive/turbo-sdk");
|
|
4
5
|
var _fs = _interopRequireDefault(require("fs"));
|
|
5
6
|
var _yargs = _interopRequireDefault(require("yargs"));
|
|
6
7
|
var _helpers = require("yargs/helpers");
|
|
8
|
+
var _mimeTypes = _interopRequireDefault(require("mime-types"));
|
|
7
9
|
var _sdk = require("@ar.io/sdk");
|
|
8
|
-
var _turboSdk = require("@ardrive/turbo-sdk");
|
|
9
10
|
var _aoconnect = require("@permaweb/aoconnect");
|
|
10
|
-
var _turbo = require("./turbo");
|
|
11
11
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
12
12
|
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
13
13
|
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { if (r) i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n;else { var o = function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); }; o("next", 0), o("throw", 1), o("return", 2); } }, _regeneratorDefine2(e, r, n, t); }
|
|
@@ -20,7 +20,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
20
20
|
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
21
21
|
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
22
22
|
var arweaveTxIdRegex = /^[a-zA-Z0-9-_]{43}$/;
|
|
23
|
-
var argv = (0, _yargs["default"])((0, _helpers.hideBin)(process.argv)).option('ario-process', {
|
|
23
|
+
var argv = (0, _yargs["default"])((0, _helpers.hideBin)(process.argv)).version('2.1.0').help().usage('Usage: $0 --arns-name <name> [options]').example('$0 --arns-name my-app', 'Deploy to my-app.arweave.dev').example('$0 --arns-name my-app --undername staging', 'Deploy to staging.my-app.arweave.dev').option('ario-process', {
|
|
24
24
|
alias: 'p',
|
|
25
25
|
type: 'string',
|
|
26
26
|
description: 'The ARIO process to use',
|
|
@@ -40,22 +40,41 @@ var argv = (0, _yargs["default"])((0, _helpers.hideBin)(process.argv)).option('a
|
|
|
40
40
|
alias: 'f',
|
|
41
41
|
type: 'string',
|
|
42
42
|
description: 'File to deploy.'
|
|
43
|
+
}).option('ttl-seconds', {
|
|
44
|
+
alias: 't',
|
|
45
|
+
type: 'number',
|
|
46
|
+
description: 'ArNS TTL Seconds',
|
|
47
|
+
"default": 3600
|
|
43
48
|
}).option('undername', {
|
|
44
49
|
alias: 'u',
|
|
45
50
|
type: 'string',
|
|
46
51
|
description: 'ANT undername to update.',
|
|
47
52
|
"default": '@'
|
|
53
|
+
}).option('sig-type', {
|
|
54
|
+
alias: 's',
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'The type of signer to be used for deployment.',
|
|
57
|
+
choices: ['arweave', 'ethereum', 'polygon',
|
|
58
|
+
// 'solana',
|
|
59
|
+
'kyve'],
|
|
60
|
+
"default": 'arweave'
|
|
61
|
+
}).check(function (argv) {
|
|
62
|
+
if (argv.ttl < 60 || argv.ttl > 86400) {
|
|
63
|
+
throw new Error('TTL must be between 60 seconds (1 minute) and 86400 seconds (1 day)');
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
48
66
|
}).argv;
|
|
49
67
|
var DEPLOY_KEY = process.env.DEPLOY_KEY;
|
|
50
|
-
var ARNS_NAME = argv
|
|
51
|
-
var ARIO_PROCESS = argv
|
|
68
|
+
var ARNS_NAME = argv['arns-name'];
|
|
69
|
+
var ARIO_PROCESS = argv['ario-process'];
|
|
70
|
+
var TTL_SECONDS = argv['ttl-seconds'];
|
|
52
71
|
if (ARIO_PROCESS === 'mainnet') {
|
|
53
72
|
ARIO_PROCESS = _sdk.ARIO_MAINNET_PROCESS_ID;
|
|
54
73
|
} else if (ARIO_PROCESS === 'testnet') {
|
|
55
74
|
ARIO_PROCESS = _sdk.ARIO_TESTNET_PROCESS_ID;
|
|
56
75
|
}
|
|
57
76
|
_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
58
|
-
var
|
|
77
|
+
var ario, arnsNameRecord, signer, token, jwk, turbo, uploadResult, txOrManifestId, mimeType, ant, _t, _t2;
|
|
59
78
|
return _regenerator().w(function (_context) {
|
|
60
79
|
while (1) switch (_context.n) {
|
|
61
80
|
case 0:
|
|
@@ -71,6 +90,10 @@ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
|
71
90
|
console.error('ARNS_NAME not configured');
|
|
72
91
|
process.exit(1);
|
|
73
92
|
}
|
|
93
|
+
if (!Number.isFinite(TTL_SECONDS) || TTL_SECONDS < 60 || TTL_SECONDS > 86400) {
|
|
94
|
+
console.error('TTL_SECONDS must be a number between 60 and 86400 seconds');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
74
97
|
if (argv.deployFile && !_fs["default"].existsSync(argv.deployFile)) {
|
|
75
98
|
console.error("deploy-file [".concat(argv.deployFolder, "] does not exist"));
|
|
76
99
|
process.exit(1);
|
|
@@ -84,7 +107,6 @@ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
|
84
107
|
console.error('undername must be set');
|
|
85
108
|
process.exit(1);
|
|
86
109
|
}
|
|
87
|
-
jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
88
110
|
ario = _sdk.ARIO.init({
|
|
89
111
|
process: new _sdk.AOProcess({
|
|
90
112
|
processId: ARIO_PROCESS,
|
|
@@ -104,35 +126,99 @@ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
|
104
126
|
case 1:
|
|
105
127
|
arnsNameRecord = _context.v;
|
|
106
128
|
_context.p = 2;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
turbo = _turboSdk.TurboFactory.authenticated({
|
|
112
|
-
privateKey: jwk
|
|
113
|
-
});
|
|
114
|
-
_context.n = 3;
|
|
115
|
-
return (0, _turbo.uploadFile)(argv.deployFile, turbo);
|
|
116
|
-
case 3:
|
|
117
|
-
txId = _context.v.id;
|
|
118
|
-
_context.n = 6;
|
|
129
|
+
_t = argv['sig-type'];
|
|
130
|
+
_context.n = _t === 'ethereum' ? 3 : _t === 'polygon' ? 4 : _t === 'arweave' ? 5 : _t === 'kyve' ? 6 : 7;
|
|
119
131
|
break;
|
|
132
|
+
case 3:
|
|
133
|
+
signer = new _turboSdk.EthereumSigner(DEPLOY_KEY);
|
|
134
|
+
token = 'ethereum';
|
|
135
|
+
return _context.a(3, 8);
|
|
120
136
|
case 4:
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
signer = new _turboSdk.EthereumSigner(DEPLOY_KEY);
|
|
138
|
+
token = 'pol';
|
|
139
|
+
return _context.a(3, 8);
|
|
123
140
|
case 5:
|
|
124
|
-
|
|
125
|
-
case 6:
|
|
141
|
+
jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
126
142
|
signer = new _sdk.ArweaveSigner(jwk);
|
|
143
|
+
token = 'arweave';
|
|
144
|
+
return _context.a(3, 8);
|
|
145
|
+
case 6:
|
|
146
|
+
signer = new _turboSdk.EthereumSigner(DEPLOY_KEY);
|
|
147
|
+
token = 'kyve';
|
|
148
|
+
return _context.a(3, 8);
|
|
149
|
+
case 7:
|
|
150
|
+
throw new Error("Invalid sig-type provided: ".concat(argv['sig-type'], ". Allowed values are 'arweave', 'ethereum', 'polygon', or 'kyve'."));
|
|
151
|
+
case 8:
|
|
152
|
+
turbo = _turboSdk.TurboFactory.authenticated({
|
|
153
|
+
signer: signer,
|
|
154
|
+
token: token
|
|
155
|
+
});
|
|
156
|
+
if (!argv['deploy-file']) {
|
|
157
|
+
_context.n = 10;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
// Detect MIME type for the file
|
|
161
|
+
mimeType = _mimeTypes["default"].lookup(argv['deploy-file']) || 'application/octet-stream';
|
|
162
|
+
_context.n = 9;
|
|
163
|
+
return turbo.uploadFile({
|
|
164
|
+
file: argv['deploy-file'],
|
|
165
|
+
dataItemOpts: {
|
|
166
|
+
tags: [{
|
|
167
|
+
name: 'App-Name',
|
|
168
|
+
value: 'Permaweb-Deploy'
|
|
169
|
+
},
|
|
170
|
+
// prevents identical transaction Ids from eth wallets
|
|
171
|
+
{
|
|
172
|
+
name: 'anchor',
|
|
173
|
+
value: new Date().toISOString()
|
|
174
|
+
}, {
|
|
175
|
+
name: 'Content-Type',
|
|
176
|
+
value: mimeType
|
|
177
|
+
}]
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
case 9:
|
|
181
|
+
uploadResult = _context.v;
|
|
182
|
+
txOrManifestId = uploadResult.id;
|
|
183
|
+
_context.n = 12;
|
|
184
|
+
break;
|
|
185
|
+
case 10:
|
|
186
|
+
_context.n = 11;
|
|
187
|
+
return turbo.uploadFolder({
|
|
188
|
+
folderPath: argv['deploy-folder'],
|
|
189
|
+
dataItemOpts: {
|
|
190
|
+
tags: [{
|
|
191
|
+
name: 'App-Name',
|
|
192
|
+
value: 'Permaweb-Deploy'
|
|
193
|
+
},
|
|
194
|
+
// prevents identical transaction Ids from eth wallets
|
|
195
|
+
{
|
|
196
|
+
name: 'anchor',
|
|
197
|
+
value: new Date().toISOString()
|
|
198
|
+
}]
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
case 11:
|
|
202
|
+
uploadResult = _context.v;
|
|
203
|
+
txOrManifestId = uploadResult.manifestResponse.id;
|
|
204
|
+
case 12:
|
|
205
|
+
console.log('-------------------- DEPLOY DETAILS --------------------');
|
|
206
|
+
console.log("Tx ID: ".concat(txOrManifestId));
|
|
207
|
+
console.log("ArNS Name: ".concat(ARNS_NAME));
|
|
208
|
+
console.log("Undername: ".concat(argv.undername));
|
|
209
|
+
console.log("ANT: ".concat(arnsNameRecord.processId));
|
|
210
|
+
console.log("AR IO Process: ".concat(ARIO_PROCESS));
|
|
211
|
+
console.log("TTL Seconds: ".concat(TTL_SECONDS));
|
|
212
|
+
console.log('--------------------------------------------------------');
|
|
127
213
|
ant = _sdk.ANT.init({
|
|
128
214
|
processId: arnsNameRecord.processId,
|
|
129
215
|
signer: signer
|
|
130
216
|
}); // Update the ANT record (assumes the JWK is a controller or owner)
|
|
131
|
-
_context.n =
|
|
217
|
+
_context.n = 13;
|
|
132
218
|
return ant.setRecord({
|
|
133
219
|
undername: argv.undername,
|
|
134
|
-
transactionId:
|
|
135
|
-
ttlSeconds:
|
|
220
|
+
transactionId: txOrManifestId,
|
|
221
|
+
ttlSeconds: argv['ttl-seconds']
|
|
136
222
|
}, {
|
|
137
223
|
tags: [{
|
|
138
224
|
name: 'App-Name',
|
|
@@ -142,17 +228,17 @@ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
|
142
228
|
value: process.env.GITHUB_SHA
|
|
143
229
|
}] : []))
|
|
144
230
|
});
|
|
145
|
-
case
|
|
146
|
-
console.log("Deployed TxId [".concat(
|
|
147
|
-
_context.n =
|
|
231
|
+
case 13:
|
|
232
|
+
console.log("Deployed TxId [".concat(txOrManifestId, "] to name [").concat(ARNS_NAME, "] for ANT [").concat(arnsNameRecord.processId, "] using undername [").concat(argv.undername, "]"));
|
|
233
|
+
_context.n = 15;
|
|
148
234
|
break;
|
|
149
|
-
case
|
|
150
|
-
_context.p =
|
|
151
|
-
|
|
152
|
-
console.error('Deployment failed:',
|
|
235
|
+
case 14:
|
|
236
|
+
_context.p = 14;
|
|
237
|
+
_t2 = _context.v;
|
|
238
|
+
console.error('Deployment failed:', _t2);
|
|
153
239
|
process.exit(1); // Exit with error code
|
|
154
|
-
case
|
|
240
|
+
case 15:
|
|
155
241
|
return _context.a(2);
|
|
156
242
|
}
|
|
157
|
-
}, _callee, null, [[2,
|
|
243
|
+
}, _callee, null, [[2, 14]]);
|
|
158
244
|
}))();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "permaweb-deploy",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Permaweb App Deployment Package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@ar.io/sdk": "^3.10.1",
|
|
14
|
-
"@ardrive/turbo-sdk": "^1.
|
|
14
|
+
"@ardrive/turbo-sdk": "^1.28.2",
|
|
15
15
|
"@permaweb/aoconnect": "^0.0.85",
|
|
16
|
-
"mime-types": "^
|
|
16
|
+
"mime-types": "^3.0.1",
|
|
17
17
|
"yargs": "17.7.2"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
package/src/index.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import { EthereumSigner, TurboFactory } from '@ardrive/turbo-sdk';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import yargs from 'yargs';
|
|
5
5
|
import { hideBin } from 'yargs/helpers';
|
|
6
|
+
import mime from 'mime-types';
|
|
6
7
|
|
|
7
8
|
import { ANT, AOProcess, ARIO, ARIO_MAINNET_PROCESS_ID, ARIO_TESTNET_PROCESS_ID, ArweaveSigner } from '@ar.io/sdk';
|
|
8
|
-
import { TurboFactory } from '@ardrive/turbo-sdk';
|
|
9
9
|
import { connect } from '@permaweb/aoconnect';
|
|
10
10
|
|
|
11
|
-
import { uploadDirectory, uploadFile } from './turbo';
|
|
12
|
-
|
|
13
11
|
const arweaveTxIdRegex = /^[a-zA-Z0-9-_]{43}$/;
|
|
14
12
|
|
|
15
13
|
const argv = yargs(hideBin(process.argv))
|
|
14
|
+
.version('2.1.0')
|
|
15
|
+
.help()
|
|
16
|
+
.usage('Usage: $0 --arns-name <name> [options]')
|
|
17
|
+
.example('$0 --arns-name my-app', 'Deploy to my-app.arweave.dev')
|
|
18
|
+
.example('$0 --arns-name my-app --undername staging', 'Deploy to staging.my-app.arweave.dev')
|
|
16
19
|
.option('ario-process', {
|
|
17
20
|
alias: 'p',
|
|
18
21
|
type: 'string',
|
|
19
22
|
description: 'The ARIO process to use',
|
|
20
23
|
demandOption: true,
|
|
21
|
-
default: ARIO_MAINNET_PROCESS_ID
|
|
24
|
+
default: ARIO_MAINNET_PROCESS_ID,
|
|
22
25
|
})
|
|
23
26
|
.option('arns-name', {
|
|
24
27
|
alias: 'n',
|
|
@@ -35,18 +38,45 @@ const argv = yargs(hideBin(process.argv))
|
|
|
35
38
|
.option('deploy-file', {
|
|
36
39
|
alias: 'f',
|
|
37
40
|
type: 'string',
|
|
38
|
-
description: 'File to deploy.'
|
|
41
|
+
description: 'File to deploy.',
|
|
42
|
+
})
|
|
43
|
+
.option('ttl-seconds', {
|
|
44
|
+
alias: 't',
|
|
45
|
+
type: 'number',
|
|
46
|
+
description: 'ArNS TTL Seconds',
|
|
47
|
+
default: 3600,
|
|
39
48
|
})
|
|
40
49
|
.option('undername', {
|
|
41
50
|
alias: 'u',
|
|
42
51
|
type: 'string',
|
|
43
52
|
description: 'ANT undername to update.',
|
|
44
53
|
default: '@',
|
|
54
|
+
})
|
|
55
|
+
.option('sig-type', {
|
|
56
|
+
alias: 's',
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'The type of signer to be used for deployment.',
|
|
59
|
+
choices: [
|
|
60
|
+
'arweave',
|
|
61
|
+
'ethereum',
|
|
62
|
+
'polygon',
|
|
63
|
+
// 'solana',
|
|
64
|
+
'kyve',
|
|
65
|
+
],
|
|
66
|
+
default: 'arweave',
|
|
67
|
+
})
|
|
68
|
+
.check((argv) => {
|
|
69
|
+
if (argv.ttl < 60 || argv.ttl > 86400) {
|
|
70
|
+
throw new Error('TTL must be between 60 seconds (1 minute) and 86400 seconds (1 day)');
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
45
73
|
}).argv;
|
|
46
74
|
|
|
47
75
|
const DEPLOY_KEY = process.env.DEPLOY_KEY;
|
|
48
|
-
const ARNS_NAME = argv
|
|
49
|
-
let ARIO_PROCESS = argv
|
|
76
|
+
const ARNS_NAME = argv['arns-name'];
|
|
77
|
+
let ARIO_PROCESS = argv['ario-process'];
|
|
78
|
+
const TTL_SECONDS = argv['ttl-seconds'];
|
|
79
|
+
|
|
50
80
|
if (ARIO_PROCESS === 'mainnet') {
|
|
51
81
|
ARIO_PROCESS = ARIO_MAINNET_PROCESS_ID;
|
|
52
82
|
} else if (ARIO_PROCESS === 'testnet') {
|
|
@@ -69,11 +99,15 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
69
99
|
process.exit(1);
|
|
70
100
|
}
|
|
71
101
|
|
|
102
|
+
if (!Number.isFinite(TTL_SECONDS) || TTL_SECONDS < 60 || TTL_SECONDS > 86400) {
|
|
103
|
+
console.error('TTL_SECONDS must be a number between 60 and 86400 seconds');
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
72
107
|
if (argv.deployFile && !fs.existsSync(argv.deployFile)) {
|
|
73
108
|
console.error(`deploy-file [${argv.deployFolder}] does not exist`);
|
|
74
109
|
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
110
|
+
} else {
|
|
77
111
|
if (!fs.existsSync(argv.deployFolder)) {
|
|
78
112
|
console.error(`deploy-folder [${argv.deployFolder}] does not exist`);
|
|
79
113
|
process.exit(1);
|
|
@@ -85,15 +119,14 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
85
119
|
process.exit(1);
|
|
86
120
|
}
|
|
87
121
|
|
|
88
|
-
const jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
89
122
|
const ario = ARIO.init({
|
|
90
123
|
process: new AOProcess({
|
|
91
124
|
processId: ARIO_PROCESS,
|
|
92
125
|
ao: connect({
|
|
93
126
|
MODE: 'legacy',
|
|
94
|
-
CU_URL: 'https://cu.ardrive.io'
|
|
95
|
-
})
|
|
96
|
-
})
|
|
127
|
+
CU_URL: 'https://cu.ardrive.io',
|
|
128
|
+
}),
|
|
129
|
+
}),
|
|
97
130
|
});
|
|
98
131
|
|
|
99
132
|
const arnsNameRecord = await ario.getArNSRecord({ name: ARNS_NAME }).catch((e) => {
|
|
@@ -102,24 +135,103 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
102
135
|
});
|
|
103
136
|
|
|
104
137
|
try {
|
|
105
|
-
let
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
138
|
+
let signer;
|
|
139
|
+
let token;
|
|
140
|
+
|
|
141
|
+
// Creates the proper signer based on the sig-type value
|
|
142
|
+
switch (argv['sig-type']) {
|
|
143
|
+
case 'ethereum':
|
|
144
|
+
signer = new EthereumSigner(DEPLOY_KEY);
|
|
145
|
+
token = 'ethereum';
|
|
146
|
+
break;
|
|
147
|
+
case 'polygon':
|
|
148
|
+
signer = new EthereumSigner(DEPLOY_KEY);
|
|
149
|
+
token = 'pol';
|
|
150
|
+
break;
|
|
151
|
+
case 'arweave':
|
|
152
|
+
const jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
153
|
+
signer = new ArweaveSigner(jwk);
|
|
154
|
+
token = 'arweave';
|
|
155
|
+
break;
|
|
156
|
+
case 'kyve':
|
|
157
|
+
signer = new EthereumSigner(DEPLOY_KEY);
|
|
158
|
+
token = 'kyve';
|
|
159
|
+
break;
|
|
160
|
+
default:
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Invalid sig-type provided: ${argv['sig-type']}. Allowed values are 'arweave', 'ethereum', 'polygon', or 'kyve'.`
|
|
163
|
+
);
|
|
109
164
|
}
|
|
110
|
-
|
|
111
|
-
|
|
165
|
+
|
|
166
|
+
const turbo = TurboFactory.authenticated({
|
|
167
|
+
signer: signer,
|
|
168
|
+
token: token,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
let uploadResult;
|
|
172
|
+
let txOrManifestId;
|
|
173
|
+
if (argv['deploy-file']) {
|
|
174
|
+
// Detect MIME type for the file
|
|
175
|
+
const mimeType = mime.lookup(argv['deploy-file']) || 'application/octet-stream';
|
|
176
|
+
|
|
177
|
+
uploadResult = await turbo.uploadFile({
|
|
178
|
+
file: argv['deploy-file'],
|
|
179
|
+
dataItemOpts: {
|
|
180
|
+
tags: [
|
|
181
|
+
{
|
|
182
|
+
name: 'App-Name',
|
|
183
|
+
value: 'Permaweb-Deploy',
|
|
184
|
+
},
|
|
185
|
+
// prevents identical transaction Ids from eth wallets
|
|
186
|
+
{
|
|
187
|
+
name: 'anchor',
|
|
188
|
+
value: new Date().toISOString(),
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'Content-Type',
|
|
192
|
+
value: mimeType,
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
txOrManifestId = uploadResult.id;
|
|
198
|
+
} else {
|
|
199
|
+
uploadResult = await turbo.uploadFolder({
|
|
200
|
+
folderPath: argv['deploy-folder'],
|
|
201
|
+
dataItemOpts: {
|
|
202
|
+
tags: [
|
|
203
|
+
{
|
|
204
|
+
name: 'App-Name',
|
|
205
|
+
value: 'Permaweb-Deploy',
|
|
206
|
+
},
|
|
207
|
+
// prevents identical transaction Ids from eth wallets
|
|
208
|
+
{
|
|
209
|
+
name: 'anchor',
|
|
210
|
+
value: new Date().toISOString(),
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
txOrManifestId = uploadResult.manifestResponse.id;
|
|
112
216
|
}
|
|
113
217
|
|
|
114
|
-
|
|
218
|
+
console.log('-------------------- DEPLOY DETAILS --------------------');
|
|
219
|
+
console.log(`Tx ID: ${txOrManifestId}`);
|
|
220
|
+
console.log(`ArNS Name: ${ARNS_NAME}`);
|
|
221
|
+
console.log(`Undername: ${argv.undername}`);
|
|
222
|
+
console.log(`ANT: ${arnsNameRecord.processId}`);
|
|
223
|
+
console.log(`AR IO Process: ${ARIO_PROCESS}`);
|
|
224
|
+
console.log(`TTL Seconds: ${TTL_SECONDS}`);
|
|
225
|
+
console.log('--------------------------------------------------------');
|
|
226
|
+
|
|
115
227
|
const ant = ANT.init({ processId: arnsNameRecord.processId, signer });
|
|
116
228
|
|
|
117
229
|
// Update the ANT record (assumes the JWK is a controller or owner)
|
|
118
230
|
await ant.setRecord(
|
|
119
231
|
{
|
|
120
232
|
undername: argv.undername,
|
|
121
|
-
transactionId:
|
|
122
|
-
ttlSeconds:
|
|
233
|
+
transactionId: txOrManifestId,
|
|
234
|
+
ttlSeconds: argv['ttl-seconds'],
|
|
123
235
|
},
|
|
124
236
|
{
|
|
125
237
|
tags: [
|
|
@@ -127,15 +239,21 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
127
239
|
name: 'App-Name',
|
|
128
240
|
value: 'Permaweb-Deploy',
|
|
129
241
|
},
|
|
130
|
-
...(process.env.GITHUB_SHA
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
242
|
+
...(process.env.GITHUB_SHA
|
|
243
|
+
? [
|
|
244
|
+
{
|
|
245
|
+
name: 'GIT-HASH',
|
|
246
|
+
value: process.env.GITHUB_SHA,
|
|
247
|
+
},
|
|
248
|
+
]
|
|
249
|
+
: []),
|
|
250
|
+
],
|
|
135
251
|
}
|
|
136
252
|
);
|
|
137
253
|
|
|
138
|
-
console.log(
|
|
254
|
+
console.log(
|
|
255
|
+
`Deployed TxId [${txOrManifestId}] to name [${ARNS_NAME}] for ANT [${arnsNameRecord.processId}] using undername [${argv.undername}]`
|
|
256
|
+
);
|
|
139
257
|
} catch (e) {
|
|
140
258
|
console.error('Deployment failed:', e);
|
|
141
259
|
process.exit(1); // Exit with error code
|
package/src/turbo/index.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import mime from 'mime-types';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { Readable } from 'stream';
|
|
5
|
-
|
|
6
|
-
import { TurboFactory } from '@ardrive/turbo-sdk';
|
|
7
|
-
|
|
8
|
-
// Gets MIME types for each file to tag the upload
|
|
9
|
-
function getContentType(filePath) {
|
|
10
|
-
const res = mime.lookup(filePath);
|
|
11
|
-
return res || 'application/octet-stream';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export async function uploadFile(path, turbo) {
|
|
15
|
-
console.log(`Uploading file: ${path}...`);
|
|
16
|
-
try {
|
|
17
|
-
const fileSize = fs.statSync(path).size;
|
|
18
|
-
const contentType = getContentType(path);
|
|
19
|
-
const uploadResult = await turbo.uploadFile({
|
|
20
|
-
fileStreamFactory: () => fs.createReadStream(path),
|
|
21
|
-
fileSizeFactory: () => fileSize,
|
|
22
|
-
signal: AbortSignal.timeout(10_000), // Cancel the upload after 10 seconds
|
|
23
|
-
dataItemOpts: {
|
|
24
|
-
tags: [
|
|
25
|
-
{ name: 'Content-Type', value: contentType },
|
|
26
|
-
{ name: 'App-Name', value: 'Permaweb-Deploy' },
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
console.log(`Uploaded ${path} with id:`, uploadResult.id);
|
|
32
|
-
|
|
33
|
-
return uploadResult;
|
|
34
|
-
} catch (err) {
|
|
35
|
-
console.error(`Error uploading file ${path}:`, err);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export async function uploadDirectory(argv, jwk) {
|
|
40
|
-
const turbo = TurboFactory.authenticated({ privateKey: jwk });
|
|
41
|
-
|
|
42
|
-
const deployFolder = argv.deployFolder;
|
|
43
|
-
|
|
44
|
-
// Uses Arweave manifest version 0.2.0, which supports fallbacks
|
|
45
|
-
let newManifest = {
|
|
46
|
-
manifest: 'arweave/paths',
|
|
47
|
-
version: '0.2.0',
|
|
48
|
-
index: { path: 'index.html' },
|
|
49
|
-
fallback: {},
|
|
50
|
-
paths: {},
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
async function processFiles(dir) {
|
|
54
|
-
const files = fs.readdirSync(dir);
|
|
55
|
-
|
|
56
|
-
for (const file of files) {
|
|
57
|
-
try {
|
|
58
|
-
const filePath = path.join(dir, file);
|
|
59
|
-
const relativePath = path.relative(deployFolder, filePath);
|
|
60
|
-
|
|
61
|
-
if (fs.statSync(filePath).isDirectory()) {
|
|
62
|
-
// Recursively process all files in a directory
|
|
63
|
-
await processFiles(filePath);
|
|
64
|
-
} else {
|
|
65
|
-
const uploadResult = await uploadFile(filePath, turbo);
|
|
66
|
-
|
|
67
|
-
// Adds uploaded file txId to the new manifest json
|
|
68
|
-
newManifest.paths[relativePath] = { id: uploadResult.id };
|
|
69
|
-
|
|
70
|
-
if (file === '404.html') {
|
|
71
|
-
// Sets manifest fallback to 404.html if found
|
|
72
|
-
newManifest.fallback.id = uploadResult.id;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
} catch (err) {
|
|
76
|
-
console.error('ERROR:', err);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async function uploadManifest(manifest) {
|
|
82
|
-
try {
|
|
83
|
-
const manifestString = JSON.stringify(manifest);
|
|
84
|
-
const uploadResult = await turbo.uploadFile({
|
|
85
|
-
fileStreamFactory: () => Readable.from(Buffer.from(manifestString)),
|
|
86
|
-
fileSizeFactory: () => Buffer.byteLength(manifestString),
|
|
87
|
-
signal: AbortSignal.timeout(10_000),
|
|
88
|
-
dataItemOpts: {
|
|
89
|
-
tags: [
|
|
90
|
-
{
|
|
91
|
-
name: 'Content-Type',
|
|
92
|
-
value: 'application/x.arweave-manifest+json',
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
name: 'App-Name',
|
|
96
|
-
value: 'Permaweb-Deploy',
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
return uploadResult.id;
|
|
102
|
-
} catch (error) {
|
|
103
|
-
console.error('Error uploading manifest:', error);
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Starts processing files in the selected directory
|
|
109
|
-
await processFiles(deployFolder);
|
|
110
|
-
|
|
111
|
-
if (!newManifest.fallback.id) {
|
|
112
|
-
// If no 404.html file is found, manifest fallback is set to the txId of index.html
|
|
113
|
-
newManifest.fallback.id = newManifest.paths['index.html'].id;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const manifestId = await uploadManifest(newManifest);
|
|
117
|
-
if (manifestId) {
|
|
118
|
-
console.log(`Manifest uploaded with Id: ${manifestId}`);
|
|
119
|
-
return manifestId;
|
|
120
|
-
}
|
|
121
|
-
}
|