permaweb-deploy 2.3.0 → 2.5.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 +74 -54
- package/dist/index.js +161 -38
- package/package.json +3 -3
- package/src/index.js +155 -32
- package/src/turbo/index.js +0 -121
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
|
@@ -11,6 +11,7 @@ Inspired by the [cookbook github action deployment guide](https://cookbook.arwea
|
|
|
11
11
|
- **Git Hash Tagging:** Automatically tags deployments with Git commit hashes
|
|
12
12
|
- **404 Fallback Detection:** Automatically detects and sets 404.html as fallback
|
|
13
13
|
- **Network Support:** Supports mainnet, testnet, and custom ARIO process IDs
|
|
14
|
+
- **Flexible Deployment:** Supports deploying a folder or a single file
|
|
14
15
|
|
|
15
16
|
### Installation
|
|
16
17
|
|
|
@@ -34,32 +35,17 @@ yarn add permaweb-deploy --dev --ignore-engines
|
|
|
34
35
|
|
|
35
36
|
### Prerequisites
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
1. **For Arweave signer (default):** Encode your Arweave wallet key in base64 format and set it as a GitHub secret:
|
|
38
39
|
|
|
39
|
-
1. **Arweave Wallet:** Have an Arweave wallet with Turbo Credits for uploading
|
|
40
|
-
2. **ArNS Name:** Own or control an ArNS name (which has an associated ANT process)
|
|
41
|
-
3. **Wallet Encoding:** Encode your Arweave wallet key in base64 format:
|
|
42
40
|
```bash
|
|
43
41
|
base64 -i wallet.json | pbcopy
|
|
44
42
|
```
|
|
45
|
-
4. **GitHub Secret:** Set the encoded wallet as a GitHub secret named `DEPLOY_KEY`
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
2. **For Ethereum/Polygon/KYVE signers:** Use your raw private key (no encoding needed) as the `DEPLOY_KEY`.
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
3. Ensure that the secret name for the encoded wallet or private key is `DEPLOY_KEY`.
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
permaweb-deploy [options]
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
| Option | Alias | Description | Default | Required |
|
|
56
|
-
| ----------------- | ----- | -------------------------------------- | --------- | -------- |
|
|
57
|
-
| `--arns-name` | `-n` | ArNS name for deployment | - | ✅ |
|
|
58
|
-
| `--ario-process` | `-p` | ARIO process ID or "mainnet"/"testnet" | `mainnet` | ❌ |
|
|
59
|
-
| `--deploy-folder` | `-d` | Folder to deploy | `./dist` | ❌ |
|
|
60
|
-
| `--deploy-file` | `-f` | File to deploy | `./dist` | ❌ |
|
|
61
|
-
| `--undername` | `-u` | ANT undername to update | `@` | ❌ |
|
|
62
|
-
| `--ttl-seconds` | `-t` | ArNS TTL Seconds | `3600` | ❌ |
|
|
48
|
+
⚠️ **Important:** Use a dedicated wallet for deployments to minimize security risks. Ensure your wallet has sufficient Turbo Credits for uploads.
|
|
63
49
|
|
|
64
50
|
### Usage
|
|
65
51
|
|
|
@@ -68,73 +54,107 @@ To deploy your application, ensure you have a build script and a deployment scri
|
|
|
68
54
|
```json
|
|
69
55
|
"scripts": {
|
|
70
56
|
"build": "your-build-command",
|
|
71
|
-
"deploy
|
|
57
|
+
"deploy": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
|
|
72
58
|
}
|
|
73
59
|
```
|
|
74
60
|
|
|
75
|
-
|
|
61
|
+
Replace `<ARNS_NAME>` with your ArNS name. To deploy to an undername, add `--undername <UNDERNAME>`.
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
79
99
|
```
|
|
80
100
|
|
|
81
|
-
|
|
101
|
+
Deploy with a custom TTL:
|
|
82
102
|
|
|
83
|
-
|
|
103
|
+
```sh
|
|
104
|
+
DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name my-app --ttl-seconds 7200
|
|
105
|
+
```
|
|
106
|
+
|
|
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
|
|
84
114
|
|
|
85
115
|
```json
|
|
86
116
|
"scripts": {
|
|
87
|
-
"build": "
|
|
88
|
-
"deploy
|
|
117
|
+
"build": "vite build",
|
|
118
|
+
"deploy": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
|
|
89
119
|
}
|
|
90
120
|
```
|
|
91
121
|
|
|
92
|
-
|
|
122
|
+
#### ARIO Process Examples
|
|
123
|
+
|
|
124
|
+
**Mainnet (default):**
|
|
93
125
|
|
|
94
126
|
```json
|
|
95
127
|
"scripts": {
|
|
96
|
-
"
|
|
97
|
-
"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>"
|
|
98
129
|
}
|
|
99
130
|
```
|
|
100
131
|
|
|
101
|
-
**
|
|
132
|
+
**Testnet:**
|
|
102
133
|
|
|
103
134
|
```json
|
|
104
135
|
"scripts": {
|
|
105
|
-
"
|
|
106
|
-
"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"
|
|
107
137
|
}
|
|
108
138
|
```
|
|
109
139
|
|
|
110
|
-
|
|
140
|
+
**Custom process ID:**
|
|
111
141
|
|
|
112
|
-
```
|
|
113
|
-
|
|
142
|
+
```json
|
|
143
|
+
"scripts": {
|
|
144
|
+
"deploy-custom": "npm run build && permaweb-deploy --arns-name <ARNS_NAME> --ario-process <PROCESS_ID>"
|
|
145
|
+
}
|
|
114
146
|
```
|
|
115
147
|
|
|
116
|
-
### Technical Details
|
|
117
|
-
|
|
118
|
-
- **Upload Service:** Uses Turbo SDK for fast, reliable file uploads to Arweave
|
|
119
|
-
- **Manifest Format:** Creates Arweave manifests using version 0.2.0 specification
|
|
120
|
-
- **Fallback Support:** Automatically detects `404.html` and sets it as fallback, otherwise uses `index.html`
|
|
121
|
-
- **Upload Timeout:** 10-second timeout per file upload for reliability
|
|
122
|
-
- **ArNS Record TTL:** Sets 3600 seconds (1 hour) TTL for ArNS records via ANT
|
|
123
|
-
- **Deployment Tags:** Automatically adds `App-Name: Permaweb-Deploy` and Git hash tags
|
|
124
|
-
- **Network Support:** Supports mainnet, testnet, and custom ARIO process IDs
|
|
125
|
-
|
|
126
148
|
### GitHub Actions Workflow
|
|
127
149
|
|
|
128
150
|
To automate the deployment, set up a GitHub Actions workflow as follows:
|
|
129
151
|
|
|
130
152
|
```yaml
|
|
131
|
-
name:
|
|
132
|
-
|
|
153
|
+
name: Deploy to Permaweb
|
|
133
154
|
on:
|
|
134
155
|
push:
|
|
135
156
|
branches:
|
|
136
|
-
-
|
|
137
|
-
|
|
157
|
+
- main
|
|
138
158
|
jobs:
|
|
139
159
|
publish:
|
|
140
160
|
runs-on: ubuntu-latest
|
|
@@ -144,15 +164,16 @@ jobs:
|
|
|
144
164
|
with:
|
|
145
165
|
node-version: 20.x
|
|
146
166
|
- run: npm install
|
|
147
|
-
- run: npm run deploy
|
|
167
|
+
- run: npm run deploy
|
|
148
168
|
env:
|
|
149
169
|
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
|
150
170
|
```
|
|
151
171
|
|
|
172
|
+
|
|
152
173
|
### Security & Best Practices
|
|
153
174
|
|
|
154
175
|
- **Dedicated Wallet:** Always use a dedicated wallet for deployments to minimize security risks
|
|
155
|
-
- **Wallet Encoding:**
|
|
176
|
+
- **Wallet Encoding:** Arweave wallets must be base64 encoded to be used in the deployment script
|
|
156
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
|
|
157
178
|
- **Turbo Credits:** Ensure your wallet has sufficient Turbo Credits before deployment
|
|
158
179
|
- **Secret Management:** Keep your `DEPLOY_KEY` secret secure and never commit it to your repository
|
|
@@ -173,5 +194,4 @@ jobs:
|
|
|
173
194
|
- **@ar.io/sdk:** - For ANT operations and ArNS management
|
|
174
195
|
- **@ardrive/turbo-sdk:** - For fast file uploads to Arweave
|
|
175
196
|
- **@permaweb/aoconnect:** - For AO network connectivity
|
|
176
|
-
- **mime-types:** - For automatic content type detection
|
|
177
197
|
- **yargs:** - For CLI argument parsing
|
package/dist/index.js
CHANGED
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
5
|
+
var _turboSdk = require("@ardrive/turbo-sdk");
|
|
4
6
|
var _fs = _interopRequireDefault(require("fs"));
|
|
5
7
|
var _yargs = _interopRequireDefault(require("yargs"));
|
|
6
8
|
var _helpers = require("yargs/helpers");
|
|
9
|
+
var _mimeTypes = _interopRequireDefault(require("mime-types"));
|
|
7
10
|
var _sdk = require("@ar.io/sdk");
|
|
8
|
-
var _turboSdk = require("@ardrive/turbo-sdk");
|
|
9
11
|
var _aoconnect = require("@permaweb/aoconnect");
|
|
10
|
-
var
|
|
12
|
+
var _nodeStream = require("node:stream");
|
|
11
13
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
12
14
|
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
15
|
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); }
|
|
14
16
|
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
15
17
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
16
|
-
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
17
18
|
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
18
19
|
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
20
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
21
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
22
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
23
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
24
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
25
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
26
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
27
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
19
28
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
29
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
30
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
20
31
|
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
32
|
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
33
|
var arweaveTxIdRegex = /^[a-zA-Z0-9-_]{43}$/;
|
|
23
|
-
var argv = (0, _yargs["default"])((0, _helpers.hideBin)(process.argv)).option('ario-process', {
|
|
34
|
+
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
35
|
alias: 'p',
|
|
25
36
|
type: 'string',
|
|
26
37
|
description: 'The ARIO process to use',
|
|
@@ -50,18 +61,31 @@ var argv = (0, _yargs["default"])((0, _helpers.hideBin)(process.argv)).option('a
|
|
|
50
61
|
type: 'string',
|
|
51
62
|
description: 'ANT undername to update.',
|
|
52
63
|
"default": '@'
|
|
64
|
+
}).option('sig-type', {
|
|
65
|
+
alias: 's',
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'The type of signer to be used for deployment.',
|
|
68
|
+
choices: ['arweave', 'ethereum', 'polygon',
|
|
69
|
+
// 'solana',
|
|
70
|
+
'kyve'],
|
|
71
|
+
"default": 'arweave'
|
|
72
|
+
}).check(function (argv) {
|
|
73
|
+
if (argv.ttl < 60 || argv.ttl > 86400) {
|
|
74
|
+
throw new Error('TTL must be between 60 seconds (1 minute) and 86400 seconds (1 day)');
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
53
77
|
}).argv;
|
|
54
78
|
var DEPLOY_KEY = process.env.DEPLOY_KEY;
|
|
55
|
-
var ARNS_NAME = argv
|
|
56
|
-
var
|
|
57
|
-
var
|
|
79
|
+
var ARNS_NAME = argv['arns-name'];
|
|
80
|
+
var ARIO_PROCESS = argv['ario-process'];
|
|
81
|
+
var TTL_SECONDS = argv['ttl-seconds'];
|
|
58
82
|
if (ARIO_PROCESS === 'mainnet') {
|
|
59
83
|
ARIO_PROCESS = _sdk.ARIO_MAINNET_PROCESS_ID;
|
|
60
84
|
} else if (ARIO_PROCESS === 'testnet') {
|
|
61
85
|
ARIO_PROCESS = _sdk.ARIO_TESTNET_PROCESS_ID;
|
|
62
86
|
}
|
|
63
87
|
_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
64
|
-
var jwk,
|
|
88
|
+
var ario, arnsNameRecord, signer, token, jwk, turbo, uploadResult, txOrManifestId, mimeType, origPaths, newPaths, replaceManifest, _i, _Object$entries, _Object$entries$_i, key, value, newKey, newManifest, buffer, _yield$turbo$uploadFi, id, ant, _t, _t2;
|
|
65
89
|
return _regenerator().w(function (_context) {
|
|
66
90
|
while (1) switch (_context.n) {
|
|
67
91
|
case 0:
|
|
@@ -94,7 +118,6 @@ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
|
94
118
|
console.error('undername must be set');
|
|
95
119
|
process.exit(1);
|
|
96
120
|
}
|
|
97
|
-
jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
98
121
|
ario = _sdk.ARIO.init({
|
|
99
122
|
process: new _sdk.AOProcess({
|
|
100
123
|
processId: ARIO_PROCESS,
|
|
@@ -114,43 +137,143 @@ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
|
114
137
|
case 1:
|
|
115
138
|
arnsNameRecord = _context.v;
|
|
116
139
|
_context.p = 2;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
turbo = _turboSdk.TurboFactory.authenticated({
|
|
122
|
-
privateKey: jwk
|
|
123
|
-
});
|
|
124
|
-
_context.n = 3;
|
|
125
|
-
return (0, _turbo.uploadFile)(argv.deployFile, turbo);
|
|
126
|
-
case 3:
|
|
127
|
-
txId = _context.v.id;
|
|
128
|
-
_context.n = 6;
|
|
140
|
+
_t = argv['sig-type'];
|
|
141
|
+
_context.n = _t === 'ethereum' ? 3 : _t === 'polygon' ? 4 : _t === 'arweave' ? 5 : _t === 'kyve' ? 6 : 7;
|
|
129
142
|
break;
|
|
143
|
+
case 3:
|
|
144
|
+
signer = new _turboSdk.EthereumSigner(DEPLOY_KEY);
|
|
145
|
+
token = 'ethereum';
|
|
146
|
+
return _context.a(3, 8);
|
|
130
147
|
case 4:
|
|
131
|
-
|
|
132
|
-
|
|
148
|
+
signer = new _turboSdk.EthereumSigner(DEPLOY_KEY);
|
|
149
|
+
token = 'pol';
|
|
150
|
+
return _context.a(3, 8);
|
|
133
151
|
case 5:
|
|
134
|
-
|
|
152
|
+
jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
153
|
+
signer = new _sdk.ArweaveSigner(jwk);
|
|
154
|
+
token = 'arweave';
|
|
155
|
+
return _context.a(3, 8);
|
|
135
156
|
case 6:
|
|
157
|
+
signer = new _turboSdk.EthereumSigner(DEPLOY_KEY);
|
|
158
|
+
token = 'kyve';
|
|
159
|
+
return _context.a(3, 8);
|
|
160
|
+
case 7:
|
|
161
|
+
throw new Error("Invalid sig-type provided: ".concat(argv['sig-type'], ". Allowed values are 'arweave', 'ethereum', 'polygon', or 'kyve'."));
|
|
162
|
+
case 8:
|
|
163
|
+
turbo = _turboSdk.TurboFactory.authenticated({
|
|
164
|
+
signer: signer,
|
|
165
|
+
token: token
|
|
166
|
+
});
|
|
167
|
+
if (!argv['deploy-file']) {
|
|
168
|
+
_context.n = 10;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
// Detect MIME type for the file
|
|
172
|
+
mimeType = _mimeTypes["default"].lookup(argv['deploy-file']) || 'application/octet-stream';
|
|
173
|
+
_context.n = 9;
|
|
174
|
+
return turbo.uploadFile({
|
|
175
|
+
file: argv['deploy-file'],
|
|
176
|
+
dataItemOpts: {
|
|
177
|
+
tags: [{
|
|
178
|
+
name: 'App-Name',
|
|
179
|
+
value: 'Permaweb-Deploy'
|
|
180
|
+
},
|
|
181
|
+
// prevents identical transaction Ids from eth wallets
|
|
182
|
+
{
|
|
183
|
+
name: 'anchor',
|
|
184
|
+
value: new Date().toISOString()
|
|
185
|
+
}, {
|
|
186
|
+
name: 'Content-Type',
|
|
187
|
+
value: mimeType
|
|
188
|
+
}]
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
case 9:
|
|
192
|
+
uploadResult = _context.v;
|
|
193
|
+
txOrManifestId = uploadResult.id;
|
|
194
|
+
_context.n = 13;
|
|
195
|
+
break;
|
|
196
|
+
case 10:
|
|
197
|
+
_context.n = 11;
|
|
198
|
+
return turbo.uploadFolder({
|
|
199
|
+
folderPath: argv['deploy-folder'],
|
|
200
|
+
dataItemOpts: {
|
|
201
|
+
tags: [{
|
|
202
|
+
name: 'App-Name',
|
|
203
|
+
value: 'Permaweb-Deploy'
|
|
204
|
+
},
|
|
205
|
+
// prevents identical transaction Ids from eth wallets
|
|
206
|
+
{
|
|
207
|
+
name: 'anchor',
|
|
208
|
+
value: new Date().toISOString()
|
|
209
|
+
}]
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
case 11:
|
|
213
|
+
uploadResult = _context.v;
|
|
214
|
+
txOrManifestId = uploadResult.manifestResponse.id; //might replace now
|
|
215
|
+
|
|
216
|
+
// Make default folder paths work by adding extra path entries
|
|
217
|
+
origPaths = uploadResult.manifest.paths;
|
|
218
|
+
newPaths = {};
|
|
219
|
+
replaceManifest = false;
|
|
220
|
+
for (_i = 0, _Object$entries = Object.entries(origPaths); _i < _Object$entries.length; _i++) {
|
|
221
|
+
_Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), key = _Object$entries$_i[0], value = _Object$entries$_i[1];
|
|
222
|
+
newPaths[key] = value;
|
|
223
|
+
if (key.endsWith('/index.html')) {
|
|
224
|
+
newKey = key.replace(/\/index\.html$/, '');
|
|
225
|
+
newPaths[newKey] = value;
|
|
226
|
+
replaceManifest = true;
|
|
227
|
+
}
|
|
228
|
+
;
|
|
229
|
+
}
|
|
230
|
+
;
|
|
231
|
+
if (!replaceManifest) {
|
|
232
|
+
_context.n = 13;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
console.info('replacing manifest');
|
|
236
|
+
newManifest = _objectSpread(_objectSpread({}, uploadResult.manifest), {}, {
|
|
237
|
+
paths: newPaths
|
|
238
|
+
});
|
|
239
|
+
buffer = Buffer.from(JSON.stringify(newManifest));
|
|
240
|
+
_context.n = 12;
|
|
241
|
+
return turbo.uploadFile({
|
|
242
|
+
fileStreamFactory: function fileStreamFactory() {
|
|
243
|
+
return _nodeStream.Readable.from(buffer);
|
|
244
|
+
},
|
|
245
|
+
fileSizeFactory: function fileSizeFactory() {
|
|
246
|
+
return buffer.length;
|
|
247
|
+
},
|
|
248
|
+
dataItemOpts: {
|
|
249
|
+
tags: [{
|
|
250
|
+
name: 'Content-Type',
|
|
251
|
+
value: 'application/x.arweave-manifest+json'
|
|
252
|
+
}]
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
case 12:
|
|
256
|
+
_yield$turbo$uploadFi = _context.v;
|
|
257
|
+
id = _yield$turbo$uploadFi.id;
|
|
258
|
+
txOrManifestId = id;
|
|
259
|
+
case 13:
|
|
136
260
|
console.log('-------------------- DEPLOY DETAILS --------------------');
|
|
137
|
-
console.log("Tx ID: ".concat(
|
|
261
|
+
console.log("Tx ID: ".concat(txOrManifestId));
|
|
138
262
|
console.log("ArNS Name: ".concat(ARNS_NAME));
|
|
139
263
|
console.log("Undername: ".concat(argv.undername));
|
|
140
264
|
console.log("ANT: ".concat(arnsNameRecord.processId));
|
|
141
265
|
console.log("AR IO Process: ".concat(ARIO_PROCESS));
|
|
142
266
|
console.log("TTL Seconds: ".concat(TTL_SECONDS));
|
|
143
267
|
console.log('--------------------------------------------------------');
|
|
144
|
-
signer = new _sdk.ArweaveSigner(jwk);
|
|
145
268
|
ant = _sdk.ANT.init({
|
|
146
269
|
processId: arnsNameRecord.processId,
|
|
147
270
|
signer: signer
|
|
148
271
|
}); // Update the ANT record (assumes the JWK is a controller or owner)
|
|
149
|
-
_context.n =
|
|
272
|
+
_context.n = 14;
|
|
150
273
|
return ant.setRecord({
|
|
151
274
|
undername: argv.undername,
|
|
152
|
-
transactionId:
|
|
153
|
-
ttlSeconds:
|
|
275
|
+
transactionId: txOrManifestId,
|
|
276
|
+
ttlSeconds: argv['ttl-seconds']
|
|
154
277
|
}, {
|
|
155
278
|
tags: [{
|
|
156
279
|
name: 'App-Name',
|
|
@@ -160,17 +283,17 @@ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
|
160
283
|
value: process.env.GITHUB_SHA
|
|
161
284
|
}] : []))
|
|
162
285
|
});
|
|
163
|
-
case
|
|
164
|
-
console.log("Deployed TxId [".concat(
|
|
165
|
-
_context.n =
|
|
286
|
+
case 14:
|
|
287
|
+
console.log("Deployed TxId [".concat(txOrManifestId, "] to name [").concat(ARNS_NAME, "] for ANT [").concat(arnsNameRecord.processId, "] using undername [").concat(argv.undername, "]"));
|
|
288
|
+
_context.n = 16;
|
|
166
289
|
break;
|
|
167
|
-
case
|
|
168
|
-
_context.p =
|
|
169
|
-
|
|
170
|
-
console.error('Deployment failed:',
|
|
290
|
+
case 15:
|
|
291
|
+
_context.p = 15;
|
|
292
|
+
_t2 = _context.v;
|
|
293
|
+
console.error('Deployment failed:', _t2);
|
|
171
294
|
process.exit(1); // Exit with error code
|
|
172
|
-
case
|
|
295
|
+
case 16:
|
|
173
296
|
return _context.a(2);
|
|
174
297
|
}
|
|
175
|
-
}, _callee, null, [[2,
|
|
298
|
+
}, _callee, null, [[2, 15]]);
|
|
176
299
|
}))();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "permaweb-deploy",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.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,28 @@
|
|
|
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
|
-
|
|
11
|
-
import { uploadDirectory, uploadFile } from './turbo';
|
|
10
|
+
import { Readable } from 'node:stream';
|
|
12
11
|
|
|
13
12
|
const arweaveTxIdRegex = /^[a-zA-Z0-9-_]{43}$/;
|
|
14
13
|
|
|
15
14
|
const argv = yargs(hideBin(process.argv))
|
|
15
|
+
.version('2.1.0')
|
|
16
|
+
.help()
|
|
17
|
+
.usage('Usage: $0 --arns-name <name> [options]')
|
|
18
|
+
.example('$0 --arns-name my-app', 'Deploy to my-app.arweave.dev')
|
|
19
|
+
.example('$0 --arns-name my-app --undername staging', 'Deploy to staging.my-app.arweave.dev')
|
|
16
20
|
.option('ario-process', {
|
|
17
21
|
alias: 'p',
|
|
18
22
|
type: 'string',
|
|
19
23
|
description: 'The ARIO process to use',
|
|
20
24
|
demandOption: true,
|
|
21
|
-
default: ARIO_MAINNET_PROCESS_ID
|
|
25
|
+
default: ARIO_MAINNET_PROCESS_ID,
|
|
22
26
|
})
|
|
23
27
|
.option('arns-name', {
|
|
24
28
|
alias: 'n',
|
|
@@ -35,25 +39,45 @@ const argv = yargs(hideBin(process.argv))
|
|
|
35
39
|
.option('deploy-file', {
|
|
36
40
|
alias: 'f',
|
|
37
41
|
type: 'string',
|
|
38
|
-
description: 'File to deploy.'
|
|
42
|
+
description: 'File to deploy.',
|
|
39
43
|
})
|
|
40
44
|
.option('ttl-seconds', {
|
|
41
45
|
alias: 't',
|
|
42
46
|
type: 'number',
|
|
43
47
|
description: 'ArNS TTL Seconds',
|
|
44
|
-
default: 3600
|
|
48
|
+
default: 3600,
|
|
45
49
|
})
|
|
46
50
|
.option('undername', {
|
|
47
51
|
alias: 'u',
|
|
48
52
|
type: 'string',
|
|
49
53
|
description: 'ANT undername to update.',
|
|
50
54
|
default: '@',
|
|
55
|
+
})
|
|
56
|
+
.option('sig-type', {
|
|
57
|
+
alias: 's',
|
|
58
|
+
type: 'string',
|
|
59
|
+
description: 'The type of signer to be used for deployment.',
|
|
60
|
+
choices: [
|
|
61
|
+
'arweave',
|
|
62
|
+
'ethereum',
|
|
63
|
+
'polygon',
|
|
64
|
+
// 'solana',
|
|
65
|
+
'kyve',
|
|
66
|
+
],
|
|
67
|
+
default: 'arweave',
|
|
68
|
+
})
|
|
69
|
+
.check((argv) => {
|
|
70
|
+
if (argv.ttl < 60 || argv.ttl > 86400) {
|
|
71
|
+
throw new Error('TTL must be between 60 seconds (1 minute) and 86400 seconds (1 day)');
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
51
74
|
}).argv;
|
|
52
75
|
|
|
53
76
|
const DEPLOY_KEY = process.env.DEPLOY_KEY;
|
|
54
|
-
const ARNS_NAME = argv
|
|
55
|
-
|
|
56
|
-
|
|
77
|
+
const ARNS_NAME = argv['arns-name'];
|
|
78
|
+
let ARIO_PROCESS = argv['ario-process'];
|
|
79
|
+
const TTL_SECONDS = argv['ttl-seconds'];
|
|
80
|
+
|
|
57
81
|
if (ARIO_PROCESS === 'mainnet') {
|
|
58
82
|
ARIO_PROCESS = ARIO_MAINNET_PROCESS_ID;
|
|
59
83
|
} else if (ARIO_PROCESS === 'testnet') {
|
|
@@ -84,8 +108,7 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
84
108
|
if (argv.deployFile && !fs.existsSync(argv.deployFile)) {
|
|
85
109
|
console.error(`deploy-file [${argv.deployFolder}] does not exist`);
|
|
86
110
|
process.exit(1);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
111
|
+
} else {
|
|
89
112
|
if (!fs.existsSync(argv.deployFolder)) {
|
|
90
113
|
console.error(`deploy-folder [${argv.deployFolder}] does not exist`);
|
|
91
114
|
process.exit(1);
|
|
@@ -97,15 +120,14 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
97
120
|
process.exit(1);
|
|
98
121
|
}
|
|
99
122
|
|
|
100
|
-
const jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
101
123
|
const ario = ARIO.init({
|
|
102
124
|
process: new AOProcess({
|
|
103
125
|
processId: ARIO_PROCESS,
|
|
104
126
|
ao: connect({
|
|
105
127
|
MODE: 'legacy',
|
|
106
|
-
CU_URL: 'https://cu.ardrive.io'
|
|
107
|
-
})
|
|
108
|
-
})
|
|
128
|
+
CU_URL: 'https://cu.ardrive.io',
|
|
129
|
+
}),
|
|
130
|
+
}),
|
|
109
131
|
});
|
|
110
132
|
|
|
111
133
|
const arnsNameRecord = await ario.getArNSRecord({ name: ARNS_NAME }).catch((e) => {
|
|
@@ -114,17 +136,113 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
114
136
|
});
|
|
115
137
|
|
|
116
138
|
try {
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
139
|
+
let signer;
|
|
140
|
+
let token;
|
|
141
|
+
|
|
142
|
+
// Creates the proper signer based on the sig-type value
|
|
143
|
+
switch (argv['sig-type']) {
|
|
144
|
+
case 'ethereum':
|
|
145
|
+
signer = new EthereumSigner(DEPLOY_KEY);
|
|
146
|
+
token = 'ethereum';
|
|
147
|
+
break;
|
|
148
|
+
case 'polygon':
|
|
149
|
+
signer = new EthereumSigner(DEPLOY_KEY);
|
|
150
|
+
token = 'pol';
|
|
151
|
+
break;
|
|
152
|
+
case 'arweave':
|
|
153
|
+
const jwk = JSON.parse(Buffer.from(DEPLOY_KEY, 'base64').toString('utf-8'));
|
|
154
|
+
signer = new ArweaveSigner(jwk);
|
|
155
|
+
token = 'arweave';
|
|
156
|
+
break;
|
|
157
|
+
case 'kyve':
|
|
158
|
+
signer = new EthereumSigner(DEPLOY_KEY);
|
|
159
|
+
token = 'kyve';
|
|
160
|
+
break;
|
|
161
|
+
default:
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Invalid sig-type provided: ${argv['sig-type']}. Allowed values are 'arweave', 'ethereum', 'polygon', or 'kyve'.`
|
|
164
|
+
);
|
|
121
165
|
}
|
|
122
|
-
|
|
123
|
-
|
|
166
|
+
|
|
167
|
+
const turbo = TurboFactory.authenticated({
|
|
168
|
+
signer: signer,
|
|
169
|
+
token: token,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
let uploadResult;
|
|
173
|
+
let txOrManifestId;
|
|
174
|
+
if (argv['deploy-file']) {
|
|
175
|
+
// Detect MIME type for the file
|
|
176
|
+
const mimeType = mime.lookup(argv['deploy-file']) || 'application/octet-stream';
|
|
177
|
+
|
|
178
|
+
uploadResult = await turbo.uploadFile({
|
|
179
|
+
file: argv['deploy-file'],
|
|
180
|
+
dataItemOpts: {
|
|
181
|
+
tags: [
|
|
182
|
+
{
|
|
183
|
+
name: 'App-Name',
|
|
184
|
+
value: 'Permaweb-Deploy',
|
|
185
|
+
},
|
|
186
|
+
// prevents identical transaction Ids from eth wallets
|
|
187
|
+
{
|
|
188
|
+
name: 'anchor',
|
|
189
|
+
value: new Date().toISOString(),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'Content-Type',
|
|
193
|
+
value: mimeType,
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
txOrManifestId = uploadResult.id;
|
|
199
|
+
} else {
|
|
200
|
+
uploadResult = await turbo.uploadFolder({
|
|
201
|
+
folderPath: argv['deploy-folder'],
|
|
202
|
+
dataItemOpts: {
|
|
203
|
+
tags: [
|
|
204
|
+
{
|
|
205
|
+
name: 'App-Name',
|
|
206
|
+
value: 'Permaweb-Deploy',
|
|
207
|
+
},
|
|
208
|
+
// prevents identical transaction Ids from eth wallets
|
|
209
|
+
{
|
|
210
|
+
name: 'anchor',
|
|
211
|
+
value: new Date().toISOString(),
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
txOrManifestId = uploadResult.manifestResponse.id; //might replace now
|
|
217
|
+
|
|
218
|
+
// Make default folder paths work by adding extra path entries
|
|
219
|
+
const origPaths = uploadResult.manifest.paths;
|
|
220
|
+
const newPaths = {};
|
|
221
|
+
let replaceManifest = false;
|
|
222
|
+
for (const [key, value] of Object.entries(origPaths)) {
|
|
223
|
+
newPaths[key] = value;
|
|
224
|
+
if (key.endsWith('/index.html')) {
|
|
225
|
+
const newKey = key.replace(/\/index\.html$/, '');
|
|
226
|
+
newPaths[newKey] = value;
|
|
227
|
+
replaceManifest = true;
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
if (replaceManifest) {
|
|
232
|
+
console.info('replacing manifest');
|
|
233
|
+
const newManifest = { ...uploadResult.manifest, paths: newPaths };
|
|
234
|
+
const buffer = Buffer.from(JSON.stringify(newManifest));
|
|
235
|
+
const { id } = await turbo.uploadFile({
|
|
236
|
+
fileStreamFactory: () => Readable.from(buffer),
|
|
237
|
+
fileSizeFactory: () => buffer.length,
|
|
238
|
+
dataItemOpts: { tags: [{ name: 'Content-Type', value: 'application/x.arweave-manifest+json' }] },
|
|
239
|
+
});
|
|
240
|
+
txOrManifestId = id;
|
|
241
|
+
}
|
|
124
242
|
}
|
|
125
243
|
|
|
126
244
|
console.log('-------------------- DEPLOY DETAILS --------------------');
|
|
127
|
-
console.log(`Tx ID: ${
|
|
245
|
+
console.log(`Tx ID: ${txOrManifestId}`);
|
|
128
246
|
console.log(`ArNS Name: ${ARNS_NAME}`);
|
|
129
247
|
console.log(`Undername: ${argv.undername}`);
|
|
130
248
|
console.log(`ANT: ${arnsNameRecord.processId}`);
|
|
@@ -132,15 +250,14 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
132
250
|
console.log(`TTL Seconds: ${TTL_SECONDS}`);
|
|
133
251
|
console.log('--------------------------------------------------------');
|
|
134
252
|
|
|
135
|
-
const signer = new ArweaveSigner(jwk);
|
|
136
253
|
const ant = ANT.init({ processId: arnsNameRecord.processId, signer });
|
|
137
254
|
|
|
138
255
|
// Update the ANT record (assumes the JWK is a controller or owner)
|
|
139
256
|
await ant.setRecord(
|
|
140
257
|
{
|
|
141
258
|
undername: argv.undername,
|
|
142
|
-
transactionId:
|
|
143
|
-
ttlSeconds:
|
|
259
|
+
transactionId: txOrManifestId,
|
|
260
|
+
ttlSeconds: argv['ttl-seconds'],
|
|
144
261
|
},
|
|
145
262
|
{
|
|
146
263
|
tags: [
|
|
@@ -148,15 +265,21 @@ if (ARIO_PROCESS === 'mainnet') {
|
|
|
148
265
|
name: 'App-Name',
|
|
149
266
|
value: 'Permaweb-Deploy',
|
|
150
267
|
},
|
|
151
|
-
...(process.env.GITHUB_SHA
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
268
|
+
...(process.env.GITHUB_SHA
|
|
269
|
+
? [
|
|
270
|
+
{
|
|
271
|
+
name: 'GIT-HASH',
|
|
272
|
+
value: process.env.GITHUB_SHA,
|
|
273
|
+
},
|
|
274
|
+
]
|
|
275
|
+
: []),
|
|
276
|
+
],
|
|
156
277
|
}
|
|
157
278
|
);
|
|
158
279
|
|
|
159
|
-
console.log(
|
|
280
|
+
console.log(
|
|
281
|
+
`Deployed TxId [${txOrManifestId}] to name [${ARNS_NAME}] for ANT [${arnsNameRecord.processId}] using undername [${argv.undername}]`
|
|
282
|
+
);
|
|
160
283
|
} catch (e) {
|
|
161
284
|
console.error('Deployment failed:', e);
|
|
162
285
|
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
|
-
}
|