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 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 simplifies the process by uploading your build folder, creating Arweave manifests, and updating 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 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
- Before using `permaweb-deploy`, you must:
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
- ⚠️ **Important:** Use a dedicated wallet for deployments to minimize security risks. Ensure your wallet has sufficient Turbo Credits for uploads.
44
+ 2. **For Ethereum/Polygon/KYVE signers:** Use your raw private key (no encoding needed) as the `DEPLOY_KEY`.
48
45
 
49
- ### CLI Options
46
+ 3. Ensure that the secret name for the encoded wallet or private key is `DEPLOY_KEY`.
50
47
 
51
- ```bash
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-main": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
57
+ "deploy": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
72
58
  }
73
59
  ```
74
60
 
75
- **Example with custom options:**
61
+ Replace `<ARNS_NAME>` with your ArNS name. To deploy to an undername, add `--undername <UNDERNAME>`.
76
62
 
77
- ```bash
78
- permaweb-deploy --arns-name "your-arns-name" --deploy-folder "./build" --undername "app"
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
- Replace `<ARNS_NAME>` with your ArNS name. You can also specify testnet, mainnet, and custom process IDs for the ARIO process to use.
101
+ Deploy with a custom TTL:
82
102
 
83
- **Mainnet (default) config:**
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": "your-build-command",
88
- "deploy-main": "npm run build && permaweb-deploy --arns-name <ARNS_NAME> --ario-process mainnet"
117
+ "build": "vite build",
118
+ "deploy": "npm run build && permaweb-deploy --arns-name <ARNS_NAME>"
89
119
  }
90
120
  ```
91
121
 
92
- **Testnet config:**
122
+ #### ARIO Process Examples
123
+
124
+ **Mainnet (default):**
93
125
 
94
126
  ```json
95
127
  "scripts": {
96
- "build": "your-build-command",
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
- **Custom process ID config:**
132
+ **Testnet:**
102
133
 
103
134
  ```json
104
135
  "scripts": {
105
- "build": "your-build-command",
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
- ### Manual CLI Deployment
140
+ **Custom process ID:**
111
141
 
112
- ```bash
113
- DEPLOY_KEY=$(base64 -i wallet.json) npx permaweb-deploy --arns-name <ARNS_NAME>
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: publish
132
-
153
+ name: Deploy to Permaweb
133
154
  on:
134
155
  push:
135
156
  branches:
136
- - 'main'
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-main
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:** The wallet must be base64 encoded to be used in the deployment script
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 _turbo = require("./turbo");
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.arnsName;
56
- var TTL_SECONDS = argv.ttlSeconds;
57
- var ARIO_PROCESS = argv.arioProcess;
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, ario, arnsNameRecord, txId, turbo, signer, ant, _t;
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
- if (!argv.deployFile) {
118
- _context.n = 4;
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
- _context.n = 5;
132
- return (0, _turbo.uploadDirectory)(argv, jwk);
148
+ signer = new _turboSdk.EthereumSigner(DEPLOY_KEY);
149
+ token = 'pol';
150
+ return _context.a(3, 8);
133
151
  case 5:
134
- txId = _context.v;
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(txId));
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 = 7;
272
+ _context.n = 14;
150
273
  return ant.setRecord({
151
274
  undername: argv.undername,
152
- transactionId: txId,
153
- ttlSeconds: TTL_SECONDS
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 7:
164
- console.log("Deployed TxId [".concat(txId, "] to name [").concat(ARNS_NAME, "] for ANT [").concat(arnsNameRecord.processId, "] using undername [").concat(argv.undername, "]"));
165
- _context.n = 9;
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 8:
168
- _context.p = 8;
169
- _t = _context.v;
170
- console.error('Deployment failed:', _t);
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 9:
295
+ case 16:
173
296
  return _context.a(2);
174
297
  }
175
- }, _callee, null, [[2, 8]]);
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.0",
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.17.0",
14
+ "@ardrive/turbo-sdk": "^1.28.2",
15
15
  "@permaweb/aoconnect": "^0.0.85",
16
- "mime-types": "^2.1.35",
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.arnsName;
55
- const TTL_SECONDS = argv.ttlSeconds;
56
- let ARIO_PROCESS = argv.arioProcess;
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 txId;
118
- if (argv.deployFile) {
119
- const turbo = TurboFactory.authenticated({ privateKey: jwk });
120
- txId = (await uploadFile(argv.deployFile, turbo)).id;
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
- else {
123
- txId = await uploadDirectory(argv, jwk);
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: ${txId}`);
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: txId,
143
- ttlSeconds: TTL_SECONDS,
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
- name: 'GIT-HASH',
153
- value: process.env.GITHUB_SHA,
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(`Deployed TxId [${txId}] to name [${ARNS_NAME}] for ANT [${arnsNameRecord.processId}] using undername [${argv.undername}]`);
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
@@ -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
- }