pockethost 4.0.0 → 4.1.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/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  Formerly published as `phio`. Versions below 3.0.0 are phio's history.
4
4
 
5
+ ## 4.1.0
6
+
7
+ ### Minor Changes
8
+
9
+ - New file commands that work over HTTPS with your token, replacing SFTP:
10
+ - `pockethost files [path] [-r]` lists files on the instance.
11
+ - `pockethost pull [paths...]` downloads files into the current folder (everything except `pb_data` by default;
12
+ `--data` includes it, and `node_modules` is skipped unless you name it). Files that haven't changed since the last
13
+ pull are skipped.
14
+ - `pockethost upload <local> [remote]` uploads a file or folder, for example an existing `pb_data` or your
15
+ `node_modules` (deploys never touch `node_modules`). Large files go up in 32 MB chunks, eight files at a time.
16
+ - `pockethost rm <paths...> [-r]` deletes files, for example a migration that keeps the instance from starting.
17
+ - Add `-I <instance>` to target an instance other than the linked one. `pb_data` needs the instance powered off.
18
+ - `pockethost sftp`, `deploy --sftp` and `dev --sftp` print a notice: SFTP shuts down on February 6, 2027.
19
+
5
20
  ## 4.0.0
6
21
 
7
22
  ### Major Changes
package/LICENSE.md ADDED
@@ -0,0 +1,16 @@
1
+ The MIT License (MIT)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4
+ and associated documentation files (the "Software"), to deal in the Software without restriction,
5
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
6
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
7
+ is furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or
10
+ substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13
+ BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -31,7 +31,11 @@ pockethost list # alias: pockethost ls
31
31
  pockethost link [instance]
32
32
  pockethost dev [instance]
33
33
  pockethost deploy [instance]
34
- pockethost sftp [instance]
34
+ pockethost files [path]
35
+ pockethost pull [paths...]
36
+ pockethost upload <local> [remote]
37
+ pockethost rm <paths...>
38
+ pockethost sftp [instance] # shuts down Feb 6, 2027
35
39
  pockethost logs [instance]
36
40
  ```
37
41
 
@@ -39,7 +43,11 @@ pockethost logs [instance]
39
43
  - **`pockethost deploy`**: deploy once
40
44
  - **`pockethost login`**: open Account → API Tokens and save the token you paste
41
45
  - **`pockethost token`**: save, clear, or check the token
42
- - **`pockethost sftp`**: interactive SFTP session (uses system `sftp` when available)
46
+ - **`pockethost files`**: list files on the instance (`-r` for everything below a folder)
47
+ - **`pockethost pull`**: download instance files into this folder (`--data` includes `pb_data`)
48
+ - **`pockethost upload`**: upload a file or folder, such as an existing `pb_data`
49
+ - **`pockethost rm`**: delete files on the instance
50
+ - **`pockethost sftp`**: interactive SFTP session. SFTP shuts down on February 6, 2027
43
51
  - **`pockethost logs`**: tail instance logs
44
52
 
45
53
  `dev` and `deploy` accept `-v/--verbose`, `-i/--include`, `-e/--exclude`, and `--sftp` (sync over SFTP instead of
package/dist/cli.js CHANGED
@@ -156,7 +156,7 @@ var require_DLList = __commonJS({
156
156
  var require_Events = __commonJS({
157
157
  "../../node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/lib/Events.js"(exports2, module2) {
158
158
  "use strict";
159
- function asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, key, arg) {
159
+ function asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, key, arg) {
160
160
  try {
161
161
  var info = gen[key](arg);
162
162
  var value = info.value;
@@ -165,7 +165,7 @@ var require_Events = __commonJS({
165
165
  return;
166
166
  }
167
167
  if (info.done) {
168
- resolve3(value);
168
+ resolve4(value);
169
169
  } else {
170
170
  Promise.resolve(value).then(_next, _throw);
171
171
  }
@@ -173,13 +173,13 @@ var require_Events = __commonJS({
173
173
  function _asyncToGenerator2(fn) {
174
174
  return function() {
175
175
  var self = this, args = arguments;
176
- return new Promise(function(resolve3, reject) {
176
+ return new Promise(function(resolve4, reject) {
177
177
  var gen = fn.apply(self, args);
178
178
  function _next(value) {
179
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "next", value);
179
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "next", value);
180
180
  }
181
181
  function _throw(err) {
182
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "throw", err);
182
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "throw", err);
183
183
  }
184
184
  _next(void 0);
185
185
  });
@@ -371,7 +371,7 @@ var require_BottleneckError = __commonJS({
371
371
  var require_Job = __commonJS({
372
372
  "../../node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/lib/Job.js"(exports2, module2) {
373
373
  "use strict";
374
- function asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, key, arg) {
374
+ function asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, key, arg) {
375
375
  try {
376
376
  var info = gen[key](arg);
377
377
  var value = info.value;
@@ -380,7 +380,7 @@ var require_Job = __commonJS({
380
380
  return;
381
381
  }
382
382
  if (info.done) {
383
- resolve3(value);
383
+ resolve4(value);
384
384
  } else {
385
385
  Promise.resolve(value).then(_next, _throw);
386
386
  }
@@ -388,13 +388,13 @@ var require_Job = __commonJS({
388
388
  function _asyncToGenerator2(fn) {
389
389
  return function() {
390
390
  var self = this, args = arguments;
391
- return new Promise(function(resolve3, reject) {
391
+ return new Promise(function(resolve4, reject) {
392
392
  var gen = fn.apply(self, args);
393
393
  function _next(value) {
394
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "next", value);
394
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "next", value);
395
395
  }
396
396
  function _throw(err) {
397
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "throw", err);
397
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "throw", err);
398
398
  }
399
399
  _next(void 0);
400
400
  });
@@ -575,7 +575,7 @@ var require_Job = __commonJS({
575
575
  var require_LocalDatastore = __commonJS({
576
576
  "../../node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/lib/LocalDatastore.js"(exports2, module2) {
577
577
  "use strict";
578
- function asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, key, arg) {
578
+ function asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, key, arg) {
579
579
  try {
580
580
  var info = gen[key](arg);
581
581
  var value = info.value;
@@ -584,7 +584,7 @@ var require_LocalDatastore = __commonJS({
584
584
  return;
585
585
  }
586
586
  if (info.done) {
587
- resolve3(value);
587
+ resolve4(value);
588
588
  } else {
589
589
  Promise.resolve(value).then(_next, _throw);
590
590
  }
@@ -592,13 +592,13 @@ var require_LocalDatastore = __commonJS({
592
592
  function _asyncToGenerator2(fn) {
593
593
  return function() {
594
594
  var self = this, args = arguments;
595
- return new Promise(function(resolve3, reject) {
595
+ return new Promise(function(resolve4, reject) {
596
596
  var gen = fn.apply(self, args);
597
597
  function _next(value) {
598
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "next", value);
598
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "next", value);
599
599
  }
600
600
  function _throw(err) {
601
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "throw", err);
601
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "throw", err);
602
602
  }
603
603
  _next(void 0);
604
604
  });
@@ -667,8 +667,8 @@ var require_LocalDatastore = __commonJS({
667
667
  })();
668
668
  }
669
669
  yieldLoop(t = 0) {
670
- return new this.Promise(function(resolve3, reject) {
671
- return setTimeout(resolve3, t);
670
+ return new this.Promise(function(resolve4, reject) {
671
+ return setTimeout(resolve4, t);
672
672
  });
673
673
  }
674
674
  computePenalty() {
@@ -1138,7 +1138,7 @@ var require_Scripts = __commonJS({
1138
1138
  var require_RedisConnection = __commonJS({
1139
1139
  "../../node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisConnection.js"(exports, module) {
1140
1140
  "use strict";
1141
- function asyncGeneratorStep(gen, resolve3, reject, _next, _throw, key, arg) {
1141
+ function asyncGeneratorStep(gen, resolve4, reject, _next, _throw, key, arg) {
1142
1142
  try {
1143
1143
  var info = gen[key](arg);
1144
1144
  var value = info.value;
@@ -1147,7 +1147,7 @@ var require_RedisConnection = __commonJS({
1147
1147
  return;
1148
1148
  }
1149
1149
  if (info.done) {
1150
- resolve3(value);
1150
+ resolve4(value);
1151
1151
  } else {
1152
1152
  Promise.resolve(value).then(_next, _throw);
1153
1153
  }
@@ -1155,13 +1155,13 @@ var require_RedisConnection = __commonJS({
1155
1155
  function _asyncToGenerator(fn) {
1156
1156
  return function() {
1157
1157
  var self = this, args = arguments;
1158
- return new Promise(function(resolve3, reject) {
1158
+ return new Promise(function(resolve4, reject) {
1159
1159
  var gen = fn.apply(self, args);
1160
1160
  function _next(value) {
1161
- asyncGeneratorStep(gen, resolve3, reject, _next, _throw, "next", value);
1161
+ asyncGeneratorStep(gen, resolve4, reject, _next, _throw, "next", value);
1162
1162
  }
1163
1163
  function _throw(err) {
1164
- asyncGeneratorStep(gen, resolve3, reject, _next, _throw, "throw", err);
1164
+ asyncGeneratorStep(gen, resolve4, reject, _next, _throw, "throw", err);
1165
1165
  }
1166
1166
  _next(void 0);
1167
1167
  });
@@ -1202,7 +1202,7 @@ var require_RedisConnection = __commonJS({
1202
1202
  }
1203
1203
  _setup(client, sub) {
1204
1204
  client.setMaxListeners(0);
1205
- return new this.Promise((resolve3, reject) => {
1205
+ return new this.Promise((resolve4, reject) => {
1206
1206
  client.on("error", (e) => {
1207
1207
  return this.Events.trigger("error", e);
1208
1208
  });
@@ -1213,14 +1213,14 @@ var require_RedisConnection = __commonJS({
1213
1213
  });
1214
1214
  }
1215
1215
  if (client.ready) {
1216
- return resolve3();
1216
+ return resolve4();
1217
1217
  } else {
1218
- return client.once("ready", resolve3);
1218
+ return client.once("ready", resolve4);
1219
1219
  }
1220
1220
  });
1221
1221
  }
1222
1222
  _loadScript(name) {
1223
- return new this.Promise((resolve3, reject) => {
1223
+ return new this.Promise((resolve4, reject) => {
1224
1224
  var payload;
1225
1225
  payload = Scripts.payload(name);
1226
1226
  return this.client.multi([["script", "load", payload]]).exec((err, replies) => {
@@ -1228,7 +1228,7 @@ var require_RedisConnection = __commonJS({
1228
1228
  return reject(err);
1229
1229
  }
1230
1230
  this.shas[name] = replies[0];
1231
- return resolve3(replies[0]);
1231
+ return resolve4(replies[0]);
1232
1232
  });
1233
1233
  });
1234
1234
  }
@@ -1241,12 +1241,12 @@ var require_RedisConnection = __commonJS({
1241
1241
  var _this = this;
1242
1242
  return _asyncToGenerator(function* () {
1243
1243
  yield _this.ready;
1244
- return new _this.Promise((resolve3, reject) => {
1244
+ return new _this.Promise((resolve4, reject) => {
1245
1245
  return _this.client.multi([cmd]).exec_atomic(function(err, replies) {
1246
1246
  if (err != null) {
1247
1247
  return reject(err);
1248
1248
  } else {
1249
- return resolve3(replies[0]);
1249
+ return resolve4(replies[0]);
1250
1250
  }
1251
1251
  });
1252
1252
  });
@@ -1254,13 +1254,13 @@ var require_RedisConnection = __commonJS({
1254
1254
  }
1255
1255
  __addLimiter__(instance) {
1256
1256
  return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => {
1257
- return new this.Promise((resolve3, reject) => {
1257
+ return new this.Promise((resolve4, reject) => {
1258
1258
  var handler;
1259
1259
  handler = (chan) => {
1260
1260
  if (chan === channel) {
1261
1261
  this.subscriber.removeListener("subscribe", handler);
1262
1262
  this.limiters[channel] = instance;
1263
- return resolve3();
1263
+ return resolve4();
1264
1264
  }
1265
1265
  };
1266
1266
  this.subscriber.on("subscribe", handler);
@@ -1274,13 +1274,13 @@ var require_RedisConnection = __commonJS({
1274
1274
  /* @__PURE__ */ (function() {
1275
1275
  var _ref = _asyncToGenerator(function* (channel) {
1276
1276
  if (!_this2.terminated) {
1277
- yield new _this2.Promise((resolve3, reject) => {
1277
+ yield new _this2.Promise((resolve4, reject) => {
1278
1278
  return _this2.subscriber.unsubscribe(channel, function(err, chan) {
1279
1279
  if (err != null) {
1280
1280
  return reject(err);
1281
1281
  }
1282
1282
  if (chan === channel) {
1283
- return resolve3();
1283
+ return resolve4();
1284
1284
  }
1285
1285
  });
1286
1286
  });
@@ -1365,7 +1365,7 @@ var require_IORedisConnection = __commonJS({
1365
1365
  function _arrayWithHoles(arr) {
1366
1366
  if (Array.isArray(arr)) return arr;
1367
1367
  }
1368
- function asyncGeneratorStep(gen, resolve3, reject, _next, _throw, key, arg) {
1368
+ function asyncGeneratorStep(gen, resolve4, reject, _next, _throw, key, arg) {
1369
1369
  try {
1370
1370
  var info = gen[key](arg);
1371
1371
  var value = info.value;
@@ -1374,7 +1374,7 @@ var require_IORedisConnection = __commonJS({
1374
1374
  return;
1375
1375
  }
1376
1376
  if (info.done) {
1377
- resolve3(value);
1377
+ resolve4(value);
1378
1378
  } else {
1379
1379
  Promise.resolve(value).then(_next, _throw);
1380
1380
  }
@@ -1382,13 +1382,13 @@ var require_IORedisConnection = __commonJS({
1382
1382
  function _asyncToGenerator(fn) {
1383
1383
  return function() {
1384
1384
  var self = this, args = arguments;
1385
- return new Promise(function(resolve3, reject) {
1385
+ return new Promise(function(resolve4, reject) {
1386
1386
  var gen = fn.apply(self, args);
1387
1387
  function _next(value) {
1388
- asyncGeneratorStep(gen, resolve3, reject, _next, _throw, "next", value);
1388
+ asyncGeneratorStep(gen, resolve4, reject, _next, _throw, "next", value);
1389
1389
  }
1390
1390
  function _throw(err) {
1391
- asyncGeneratorStep(gen, resolve3, reject, _next, _throw, "throw", err);
1391
+ asyncGeneratorStep(gen, resolve4, reject, _next, _throw, "throw", err);
1392
1392
  }
1393
1393
  _next(void 0);
1394
1394
  });
@@ -1434,7 +1434,7 @@ var require_IORedisConnection = __commonJS({
1434
1434
  }
1435
1435
  _setup(client, sub) {
1436
1436
  client.setMaxListeners(0);
1437
- return new this.Promise((resolve3, reject) => {
1437
+ return new this.Promise((resolve4, reject) => {
1438
1438
  client.on("error", (e) => {
1439
1439
  return this.Events.trigger("error", e);
1440
1440
  });
@@ -1445,9 +1445,9 @@ var require_IORedisConnection = __commonJS({
1445
1445
  });
1446
1446
  }
1447
1447
  if (client.status === "ready") {
1448
- return resolve3();
1448
+ return resolve4();
1449
1449
  } else {
1450
- return client.once("ready", resolve3);
1450
+ return client.once("ready", resolve4);
1451
1451
  }
1452
1452
  });
1453
1453
  }
@@ -1473,10 +1473,10 @@ var require_IORedisConnection = __commonJS({
1473
1473
  }
1474
1474
  __addLimiter__(instance) {
1475
1475
  return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => {
1476
- return new this.Promise((resolve3, reject) => {
1476
+ return new this.Promise((resolve4, reject) => {
1477
1477
  return this.subscriber.subscribe(channel, () => {
1478
1478
  this.limiters[channel] = instance;
1479
- return resolve3();
1479
+ return resolve4();
1480
1480
  });
1481
1481
  });
1482
1482
  }));
@@ -1574,7 +1574,7 @@ var require_RedisDatastore = __commonJS({
1574
1574
  function _arrayWithHoles2(arr) {
1575
1575
  if (Array.isArray(arr)) return arr;
1576
1576
  }
1577
- function asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, key, arg) {
1577
+ function asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, key, arg) {
1578
1578
  try {
1579
1579
  var info = gen[key](arg);
1580
1580
  var value = info.value;
@@ -1583,7 +1583,7 @@ var require_RedisDatastore = __commonJS({
1583
1583
  return;
1584
1584
  }
1585
1585
  if (info.done) {
1586
- resolve3(value);
1586
+ resolve4(value);
1587
1587
  } else {
1588
1588
  Promise.resolve(value).then(_next, _throw);
1589
1589
  }
@@ -1591,13 +1591,13 @@ var require_RedisDatastore = __commonJS({
1591
1591
  function _asyncToGenerator2(fn) {
1592
1592
  return function() {
1593
1593
  var self = this, args = arguments;
1594
- return new Promise(function(resolve3, reject) {
1594
+ return new Promise(function(resolve4, reject) {
1595
1595
  var gen = fn.apply(self, args);
1596
1596
  function _next(value) {
1597
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "next", value);
1597
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "next", value);
1598
1598
  }
1599
1599
  function _throw(err) {
1600
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "throw", err);
1600
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "throw", err);
1601
1601
  }
1602
1602
  _next(void 0);
1603
1603
  });
@@ -1733,7 +1733,7 @@ var require_RedisDatastore = __commonJS({
1733
1733
  if (!(name === "init" || name === "register_client")) {
1734
1734
  yield _this3.ready;
1735
1735
  }
1736
- return new _this3.Promise((resolve3, reject) => {
1736
+ return new _this3.Promise((resolve4, reject) => {
1737
1737
  var all_args, arr;
1738
1738
  all_args = [Date.now(), _this3.clientId].concat(args);
1739
1739
  _this3.instance.Events.trigger("debug", `Calling Redis script: ${name}.lua`, all_args);
@@ -1741,7 +1741,7 @@ var require_RedisDatastore = __commonJS({
1741
1741
  if (err != null) {
1742
1742
  return reject(err);
1743
1743
  }
1744
- return resolve3(replies);
1744
+ return resolve4(replies);
1745
1745
  });
1746
1746
  return _this3.connection.__scriptFn__(name)(...arr);
1747
1747
  }).catch((e) => {
@@ -1972,7 +1972,7 @@ var require_States = __commonJS({
1972
1972
  var require_Sync = __commonJS({
1973
1973
  "../../node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/lib/Sync.js"(exports2, module2) {
1974
1974
  "use strict";
1975
- function asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, key, arg) {
1975
+ function asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, key, arg) {
1976
1976
  try {
1977
1977
  var info = gen[key](arg);
1978
1978
  var value = info.value;
@@ -1981,7 +1981,7 @@ var require_Sync = __commonJS({
1981
1981
  return;
1982
1982
  }
1983
1983
  if (info.done) {
1984
- resolve3(value);
1984
+ resolve4(value);
1985
1985
  } else {
1986
1986
  Promise.resolve(value).then(_next, _throw);
1987
1987
  }
@@ -1989,13 +1989,13 @@ var require_Sync = __commonJS({
1989
1989
  function _asyncToGenerator2(fn) {
1990
1990
  return function() {
1991
1991
  var self = this, args = arguments;
1992
- return new Promise(function(resolve3, reject) {
1992
+ return new Promise(function(resolve4, reject) {
1993
1993
  var gen = fn.apply(self, args);
1994
1994
  function _next(value) {
1995
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "next", value);
1995
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "next", value);
1996
1996
  }
1997
1997
  function _throw(err) {
1998
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "throw", err);
1998
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "throw", err);
1999
1999
  }
2000
2000
  _next(void 0);
2001
2001
  });
@@ -2018,19 +2018,19 @@ var require_Sync = __commonJS({
2018
2018
  _tryToRun() {
2019
2019
  var _this = this;
2020
2020
  return _asyncToGenerator2(function* () {
2021
- var args, cb, error, reject, resolve3, returned, task;
2021
+ var args, cb, error, reject, resolve4, returned, task;
2022
2022
  if (_this._running < 1 && _this._queue.length > 0) {
2023
2023
  _this._running++;
2024
2024
  var _this$_queue$shift = _this._queue.shift();
2025
2025
  task = _this$_queue$shift.task;
2026
2026
  args = _this$_queue$shift.args;
2027
- resolve3 = _this$_queue$shift.resolve;
2027
+ resolve4 = _this$_queue$shift.resolve;
2028
2028
  reject = _this$_queue$shift.reject;
2029
2029
  cb = yield _asyncToGenerator2(function* () {
2030
2030
  try {
2031
2031
  returned = yield task(...args);
2032
2032
  return function() {
2033
- return resolve3(returned);
2033
+ return resolve4(returned);
2034
2034
  };
2035
2035
  } catch (error1) {
2036
2036
  error = error1;
@@ -2046,16 +2046,16 @@ var require_Sync = __commonJS({
2046
2046
  })();
2047
2047
  }
2048
2048
  schedule(task, ...args) {
2049
- var promise, reject, resolve3;
2050
- resolve3 = reject = null;
2049
+ var promise, reject, resolve4;
2050
+ resolve4 = reject = null;
2051
2051
  promise = new this.Promise(function(_resolve, _reject) {
2052
- resolve3 = _resolve;
2052
+ resolve4 = _resolve;
2053
2053
  return reject = _reject;
2054
2054
  });
2055
2055
  this._queue.push({
2056
2056
  task,
2057
2057
  args,
2058
- resolve: resolve3,
2058
+ resolve: resolve4,
2059
2059
  reject
2060
2060
  });
2061
2061
  this._tryToRun();
@@ -2108,7 +2108,7 @@ var require_Group = __commonJS({
2108
2108
  function _arrayWithHoles2(arr) {
2109
2109
  if (Array.isArray(arr)) return arr;
2110
2110
  }
2111
- function asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, key, arg) {
2111
+ function asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, key, arg) {
2112
2112
  try {
2113
2113
  var info = gen[key](arg);
2114
2114
  var value = info.value;
@@ -2117,7 +2117,7 @@ var require_Group = __commonJS({
2117
2117
  return;
2118
2118
  }
2119
2119
  if (info.done) {
2120
- resolve3(value);
2120
+ resolve4(value);
2121
2121
  } else {
2122
2122
  Promise.resolve(value).then(_next, _throw);
2123
2123
  }
@@ -2125,13 +2125,13 @@ var require_Group = __commonJS({
2125
2125
  function _asyncToGenerator2(fn) {
2126
2126
  return function() {
2127
2127
  var self = this, args = arguments;
2128
- return new Promise(function(resolve3, reject) {
2128
+ return new Promise(function(resolve4, reject) {
2129
2129
  var gen = fn.apply(self, args);
2130
2130
  function _next(value) {
2131
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "next", value);
2131
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "next", value);
2132
2132
  }
2133
2133
  function _throw(err) {
2134
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "throw", err);
2134
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "throw", err);
2135
2135
  }
2136
2136
  _next(void 0);
2137
2137
  });
@@ -2394,7 +2394,7 @@ var require_Bottleneck = __commonJS({
2394
2394
  function _arrayWithHoles2(arr) {
2395
2395
  if (Array.isArray(arr)) return arr;
2396
2396
  }
2397
- function asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, key, arg) {
2397
+ function asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, key, arg) {
2398
2398
  try {
2399
2399
  var info = gen[key](arg);
2400
2400
  var value = info.value;
@@ -2403,7 +2403,7 @@ var require_Bottleneck = __commonJS({
2403
2403
  return;
2404
2404
  }
2405
2405
  if (info.done) {
2406
- resolve3(value);
2406
+ resolve4(value);
2407
2407
  } else {
2408
2408
  Promise.resolve(value).then(_next, _throw);
2409
2409
  }
@@ -2411,13 +2411,13 @@ var require_Bottleneck = __commonJS({
2411
2411
  function _asyncToGenerator2(fn) {
2412
2412
  return function() {
2413
2413
  var self = this, args = arguments;
2414
- return new Promise(function(resolve3, reject) {
2414
+ return new Promise(function(resolve4, reject) {
2415
2415
  var gen = fn.apply(self, args);
2416
2416
  function _next(value) {
2417
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "next", value);
2417
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "next", value);
2418
2418
  }
2419
2419
  function _throw(err) {
2420
- asyncGeneratorStep2(gen, resolve3, reject, _next, _throw, "throw", err);
2420
+ asyncGeneratorStep2(gen, resolve4, reject, _next, _throw, "throw", err);
2421
2421
  }
2422
2422
  _next(void 0);
2423
2423
  });
@@ -2655,14 +2655,14 @@ var require_Bottleneck = __commonJS({
2655
2655
  counts = this._states.counts;
2656
2656
  return counts[0] + counts[1] + counts[2] + counts[3] === at2;
2657
2657
  };
2658
- return new this.Promise((resolve3, reject) => {
2658
+ return new this.Promise((resolve4, reject) => {
2659
2659
  if (finished()) {
2660
- return resolve3();
2660
+ return resolve4();
2661
2661
  } else {
2662
2662
  return this.on("done", () => {
2663
2663
  if (finished()) {
2664
2664
  this.removeAllListeners("done");
2665
- return resolve3();
2665
+ return resolve4();
2666
2666
  }
2667
2667
  });
2668
2668
  }
@@ -2770,9 +2770,9 @@ var require_Bottleneck = __commonJS({
2770
2770
  options2 = parser2.load(options2, this.jobDefaults);
2771
2771
  }
2772
2772
  task = (...args2) => {
2773
- return new this.Promise(function(resolve3, reject) {
2773
+ return new this.Promise(function(resolve4, reject) {
2774
2774
  return fn(...args2, function(...args3) {
2775
- return (args3[0] != null ? reject : resolve3)(args3);
2775
+ return (args3[0] != null ? reject : resolve4)(args3);
2776
2776
  });
2777
2777
  });
2778
2778
  };
@@ -6444,7 +6444,7 @@ function useColor() {
6444
6444
  var program = new Command();
6445
6445
 
6446
6446
  // package.json
6447
- var version = "4.0.0";
6447
+ var version = "4.1.0";
6448
6448
 
6449
6449
  // src/lib/projectRoot.ts
6450
6450
  import { existsSync as existsSync2 } from "fs";
@@ -6774,7 +6774,7 @@ var syncFileDescription = "DO NOT DELETE THIS FILE. This file is used to keep tr
6774
6774
  import fs2 from "fs";
6775
6775
  import crypto from "crypto";
6776
6776
  async function fileHash(filename, algorithm) {
6777
- return new Promise((resolve3, reject) => {
6777
+ return new Promise((resolve4, reject) => {
6778
6778
  let shasum = crypto.createHash(algorithm);
6779
6779
  try {
6780
6780
  let s = fs2.createReadStream(filename);
@@ -6786,7 +6786,7 @@ async function fileHash(filename, algorithm) {
6786
6786
  });
6787
6787
  s.on("end", function() {
6788
6788
  const hash = shasum.digest("hex");
6789
- return resolve3(hash);
6789
+ return resolve4(hash);
6790
6790
  });
6791
6791
  } catch (error) {
6792
6792
  return reject("calc fail");
@@ -8960,9 +8960,9 @@ function getDefaultSettings(withoutDefaults) {
8960
8960
  timeout: withoutDefaults.timeout ?? 3e4
8961
8961
  };
8962
8962
  }
8963
- function applyExcludeFilter(stat4, excludeFilters) {
8963
+ function applyExcludeFilter(stat5, excludeFilters) {
8964
8964
  if (excludeFilters.length > 0) {
8965
- const pathWithFolderSlash = stat4.path + (stat4.isDirectory() ? "/" : "");
8965
+ const pathWithFolderSlash = stat5.path + (stat5.isDirectory() ? "/" : "");
8966
8966
  const excludeMatch = multimatch(pathWithFolderSlash, excludeFilters, {
8967
8967
  matchBase: true,
8968
8968
  dot: true
@@ -12314,8 +12314,8 @@ async function getLocalFiles(args, logger) {
12314
12314
  logger.verbose(`Local files:`, JSON.stringify({ files }, null, 2));
12315
12315
  const records = [];
12316
12316
  for (const path5 of files) {
12317
- const stat4 = lstatSync(path5);
12318
- if (stat4.isDirectory()) {
12317
+ const stat5 = lstatSync(path5);
12318
+ if (stat5.isDirectory()) {
12319
12319
  records.push({
12320
12320
  type: "folder",
12321
12321
  name: path5,
@@ -12323,16 +12323,16 @@ async function getLocalFiles(args, logger) {
12323
12323
  });
12324
12324
  continue;
12325
12325
  }
12326
- if (stat4.isFile()) {
12326
+ if (stat5.isFile()) {
12327
12327
  records.push({
12328
12328
  type: "file",
12329
12329
  name: path5,
12330
- size: stat4.size,
12330
+ size: stat5.size,
12331
12331
  hash: await fileHash(args["local-dir"] + path5, "sha256")
12332
12332
  });
12333
12333
  continue;
12334
12334
  }
12335
- if (stat4.isSymbolicLink()) {
12335
+ if (stat5.isSymbolicLink()) {
12336
12336
  console.warn(
12337
12337
  "This script is currently unable to handle symbolic links - please add a feature request if you need this"
12338
12338
  );
@@ -13398,9 +13398,9 @@ var NodeFsHandler = class {
13398
13398
  if (this.fsw.closed) {
13399
13399
  return;
13400
13400
  }
13401
- const dirname4 = sp.dirname(file);
13401
+ const dirname5 = sp.dirname(file);
13402
13402
  const basename3 = sp.basename(file);
13403
- const parent = this.fsw._getWatchedDir(dirname4);
13403
+ const parent = this.fsw._getWatchedDir(dirname5);
13404
13404
  let prevStats = stats;
13405
13405
  if (parent.has(basename3))
13406
13406
  return;
@@ -13427,7 +13427,7 @@ var NodeFsHandler = class {
13427
13427
  prevStats = newStats2;
13428
13428
  }
13429
13429
  } catch (error) {
13430
- this.fsw._remove(dirname4, basename3);
13430
+ this.fsw._remove(dirname5, basename3);
13431
13431
  }
13432
13432
  } else if (parent.has(basename3)) {
13433
13433
  const at2 = newStats.atimeMs;
@@ -13524,7 +13524,7 @@ var NodeFsHandler = class {
13524
13524
  this._addToNodeFs(path5, initialAdd, wh, depth + 1);
13525
13525
  }
13526
13526
  }).on(EV.ERROR, this._boundHandleError);
13527
- return new Promise((resolve3, reject) => {
13527
+ return new Promise((resolve4, reject) => {
13528
13528
  if (!stream)
13529
13529
  return reject();
13530
13530
  stream.once(STR_END, () => {
@@ -13533,7 +13533,7 @@ var NodeFsHandler = class {
13533
13533
  return;
13534
13534
  }
13535
13535
  const wasThrottled = throttler ? throttler.clear() : false;
13536
- resolve3(void 0);
13536
+ resolve4(void 0);
13537
13537
  previous.getChildren().filter((item) => {
13538
13538
  return item !== directory && !current.has(item);
13539
13539
  }).forEach((item) => {
@@ -13677,11 +13677,11 @@ function createPattern(matcher) {
13677
13677
  if (matcher.path === string)
13678
13678
  return true;
13679
13679
  if (matcher.recursive) {
13680
- const relative4 = sp2.relative(matcher.path, string);
13681
- if (!relative4) {
13680
+ const relative5 = sp2.relative(matcher.path, string);
13681
+ if (!relative5) {
13682
13682
  return false;
13683
13683
  }
13684
- return !relative4.startsWith("..") && !sp2.isAbsolute(relative4);
13684
+ return !relative5.startsWith("..") && !sp2.isAbsolute(relative5);
13685
13685
  }
13686
13686
  return false;
13687
13687
  };
@@ -14260,8 +14260,8 @@ var FSWatcher = class extends EventEmitter2 {
14260
14260
  }
14261
14261
  return this._userIgnored(path5, stats);
14262
14262
  }
14263
- _isntIgnored(path5, stat4) {
14264
- return !this._isIgnored(path5, stat4);
14263
+ _isntIgnored(path5, stat5) {
14264
+ return !this._isIgnored(path5, stat5);
14265
14265
  }
14266
14266
  /**
14267
14267
  * Provides a set of common helpers and properties relating to symlink handling.
@@ -14697,7 +14697,17 @@ var describeToken = (w) => {
14697
14697
  // src/lib/sftpAuth.ts
14698
14698
  var SshKeyNotRegisteredError = class extends Error {
14699
14699
  };
14700
+ var SFTP_SUNSET_DATE = "February 6, 2027";
14701
+ var warnedSunset = false;
14702
+ var warnSftpSunset = () => {
14703
+ if (warnedSunset) return;
14704
+ warnedSunset = true;
14705
+ console.warn(
14706
+ `\u26A0\uFE0F SFTP shuts down on ${SFTP_SUNSET_DATE}. Use 'pockethost deploy' / 'pockethost dev' (HTTPS) for code, and 'pockethost files', 'pull', 'upload' and 'rm' for everything else. https://pockethost.io/blog/sftp-sunset`
14707
+ );
14708
+ };
14700
14709
  var sftpCredentials = async () => {
14710
+ warnSftpSunset();
14701
14711
  const cred = await resolveDeployCredential();
14702
14712
  const key = ensureLocalDeployKey();
14703
14713
  const who = await tokenWhoami(cred.token, key.fingerprint);
@@ -15122,8 +15132,273 @@ var DeployCommand = () => {
15122
15132
  });
15123
15133
  };
15124
15134
 
15135
+ // src/commands/FilesCommand.ts
15136
+ import { existsSync as existsSync5, readdirSync as readdirSync2, statSync } from "fs";
15137
+ import { join as join5, relative as relative4, resolve as resolve3, sep as sep3 } from "path";
15138
+
15139
+ // src/lib/filesApi.ts
15140
+ import { createReadStream, createWriteStream } from "fs";
15141
+ import { mkdir, rename, stat as stat4, utimes } from "fs/promises";
15142
+ import { dirname as dirname4 } from "path";
15143
+ import { Readable as Readable2 } from "stream";
15144
+ import { pipeline } from "stream/promises";
15145
+ var FILE_CHUNK_BYTES = 32 * 1024 * 1024;
15146
+ var normalizeRemotePath = (p = "") => p.replace(/\\/g, "/").replace(/^\.?\/+/, "").replace(/\/+$/, "").replace(/^\.$/, "");
15147
+ var errorFrom = async (res, instanceName) => {
15148
+ const text = await res.text().catch(() => "");
15149
+ let message = text.slice(0, 300) || `HTTP ${res.status}`;
15150
+ try {
15151
+ message = JSON.parse(text).message || message;
15152
+ } catch {
15153
+ }
15154
+ if (res.status === 404 && /not found$/.test(message) && message.includes("."))
15155
+ message = `Instance '${instanceName}' not found, or this token cannot access it.`;
15156
+ return new DeployApiError(res.status, message);
15157
+ };
15158
+ var createFilesClient = async (instanceName) => {
15159
+ const api = createDeployClient(instanceName, await resolveDeployCredential());
15160
+ const url = (path5, q2) => {
15161
+ const u = new URL(`${api.base}/files${path5}`);
15162
+ for (const [k2, v2] of Object.entries(q2)) u.searchParams.set(k2, `${v2}`);
15163
+ return u.toString();
15164
+ };
15165
+ const send = async (method, path5, q2, body) => {
15166
+ let res;
15167
+ try {
15168
+ res = await fetch(url(path5, q2), {
15169
+ method,
15170
+ headers: {
15171
+ ...api.headers,
15172
+ ...body ? { "Content-Type": "application/octet-stream" } : {}
15173
+ },
15174
+ body
15175
+ });
15176
+ } catch (e) {
15177
+ throw new DeployApiError(
15178
+ 0,
15179
+ `Could not reach ${api.base}: ${e.message}`
15180
+ );
15181
+ }
15182
+ if (!res.ok) throw await errorFrom(res, instanceName);
15183
+ return res;
15184
+ };
15185
+ const list = async (path5 = "", recursive = false) => {
15186
+ const res = await send("GET", "", {
15187
+ path: normalizeRemotePath(path5),
15188
+ recursive: recursive ? 1 : 0
15189
+ });
15190
+ return await res.json();
15191
+ };
15192
+ const download = async (remote, dest) => {
15193
+ const res = await send("GET", "/raw", { path: normalizeRemotePath(remote) });
15194
+ await mkdir(dirname4(dest), { recursive: true });
15195
+ const tmp = `${dest}.pockethost-download`;
15196
+ await pipeline(Readable2.fromWeb(res.body), createWriteStream(tmp));
15197
+ await rename(tmp, dest);
15198
+ const mtime = Number(res.headers.get("x-ph-mtime"));
15199
+ if (mtime > 0) await utimes(dest, /* @__PURE__ */ new Date(), new Date(mtime));
15200
+ };
15201
+ const upload = async (local, remote, onProgress) => {
15202
+ const { size } = await stat4(local);
15203
+ const path5 = normalizeRemotePath(remote);
15204
+ if (size === 0) {
15205
+ await send(
15206
+ "PUT",
15207
+ "/raw",
15208
+ { path: path5, offset: 0, final: 1 },
15209
+ new Uint8Array(0)
15210
+ );
15211
+ return size;
15212
+ }
15213
+ let offset = 0;
15214
+ for await (const chunk of createReadStream(local, {
15215
+ highWaterMark: FILE_CHUNK_BYTES
15216
+ })) {
15217
+ const buf = chunk;
15218
+ const final = offset + buf.length >= size;
15219
+ await send(
15220
+ "PUT",
15221
+ "/raw",
15222
+ { path: path5, offset, final: final ? 1 : 0 },
15223
+ new Uint8Array(buf)
15224
+ );
15225
+ offset += buf.length;
15226
+ onProgress?.(offset, size);
15227
+ }
15228
+ if (offset !== size)
15229
+ throw new Error(`${local} changed size during upload; run it again`);
15230
+ return size;
15231
+ };
15232
+ const remove = async (remote, recursive = false) => {
15233
+ await send("DELETE", "", {
15234
+ path: normalizeRemotePath(remote),
15235
+ recursive: recursive ? 1 : 0
15236
+ });
15237
+ };
15238
+ return { base: api.base, list, download, upload, remove };
15239
+ };
15240
+
15241
+ // src/commands/FilesCommand.ts
15242
+ var DATA_DIR = "pb_data";
15243
+ var NODE_MODULES = "node_modules";
15244
+ var UPLOAD_CONCURRENCY = 8;
15245
+ var hasNodeModules = (p) => p.split("/").includes(NODE_MODULES);
15246
+ var requireInstance = (instance) => {
15247
+ const name = instance || savedInstanceName();
15248
+ if (!name)
15249
+ throw new Error(
15250
+ `No instance given and none linked. Pass --instance <name> or run 'pockethost link <instance>'.`
15251
+ );
15252
+ return name;
15253
+ };
15254
+ var instanceOption = (cmd) => cmd.option(
15255
+ "-I, --instance <name>",
15256
+ "Instance name (defaults to the linked instance)"
15257
+ );
15258
+ var dataHint = (e) => {
15259
+ const msg = e?.message ?? `${e}`;
15260
+ return /power off/i.test(msg) ? `${msg} Power it off in the dashboard, run this again, then power it back on.` : msg;
15261
+ };
15262
+ var fmtDate = (ms2) => new Date(ms2).toISOString().replace("T", " ").slice(0, 16);
15263
+ var FilesCommand = () => instanceOption(
15264
+ new Command("files").alias("ls-files").description(
15265
+ "List files on your instance (pb_hooks, pb_migrations, pb_public, pb_data, ...)"
15266
+ ).argument("[path]", "Folder or file on the instance", "").option("-r, --recursive", "List everything below the folder").option("--json", "Print JSON")
15267
+ ).action(async (path5, options2) => {
15268
+ const files = await createFilesClient(requireInstance(options2.instance));
15269
+ const out = await files.list(path5, !!options2.recursive).catch((e) => {
15270
+ throw new Error(dataHint(e));
15271
+ });
15272
+ if (options2.json) {
15273
+ console.log(JSON.stringify(out.entries, null, 2));
15274
+ return;
15275
+ }
15276
+ if (out.entries.length === 0) console.log(`(empty)`);
15277
+ for (const e of out.entries) {
15278
+ const size = e.isDirectory ? "-" : prettyBytes(e.size);
15279
+ console.log(
15280
+ `${fmtDate(e.mtime)} ${size.padStart(10)} ${e.path}${e.isDirectory ? "/" : ""}`
15281
+ );
15282
+ }
15283
+ if (out.truncated) console.log(`(list truncated)`);
15284
+ });
15285
+ var isCurrent = (local, e) => {
15286
+ if (!existsSync5(local)) return false;
15287
+ const st2 = statSync(local);
15288
+ return st2.size === e.size && Math.abs(st2.mtimeMs - e.mtime) < 1e3;
15289
+ };
15290
+ var PullCommand = () => instanceOption(
15291
+ new Command("pull").description(
15292
+ "Download files from your instance into this folder. Default: everything except pb_data"
15293
+ ).argument(
15294
+ "[paths...]",
15295
+ "Files or folders on the instance (e.g. pb_hooks pb_data/backups)"
15296
+ ).option("--data", "Include pb_data (the instance must be powered off)").option("-d, --dir <dir>", "Local folder to download into", ".").option("-n, --dry-run", "Show what would be downloaded").option("-v, --verbose", "Print every file")
15297
+ ).action(async (paths, options2) => {
15298
+ const instanceName = requireInstance(options2.instance);
15299
+ const files = await createFilesClient(instanceName);
15300
+ const dir = resolve3(options2.dir);
15301
+ let roots = paths.map((p) => normalizeRemotePath(p)).filter(Boolean);
15302
+ if (roots.length === 0) {
15303
+ const top = await files.list("");
15304
+ roots = top.entries.map((e) => e.path).filter((p) => (options2.data || p !== DATA_DIR) && p !== NODE_MODULES);
15305
+ if (!options2.data && top.entries.some((e) => e.path === DATA_DIR))
15306
+ console.log(`Skipping pb_data (add --data to include it).`);
15307
+ if (top.entries.some((e) => e.path === NODE_MODULES))
15308
+ console.log(
15309
+ `Skipping node_modules (run 'pockethost pull node_modules' if you need it).`
15310
+ );
15311
+ }
15312
+ const wanted = [];
15313
+ for (const root of roots) {
15314
+ const { entries } = await files.list(root, true).catch((e) => {
15315
+ throw new Error(`${root}: ${dataHint(e)}`);
15316
+ });
15317
+ wanted.push(
15318
+ ...entries.filter(
15319
+ (e) => !e.isDirectory && (hasNodeModules(root) || !hasNodeModules(e.path))
15320
+ )
15321
+ );
15322
+ }
15323
+ const todo = wanted.filter((e) => !isCurrent(join5(dir, e.path), e));
15324
+ const bytes = todo.reduce((n7, e) => n7 + e.size, 0);
15325
+ console.log(
15326
+ `${options2.dryRun ? "Would download" : "Downloading"} ${todo.length} of ${wanted.length} file(s) (${prettyBytes(bytes)}) from ${instanceName} into ${dir}`
15327
+ );
15328
+ for (const e of todo) {
15329
+ if (options2.verbose || options2.dryRun) console.log(` ${e.path}`);
15330
+ if (!options2.dryRun) await files.download(e.path, join5(dir, e.path));
15331
+ }
15332
+ if (!options2.dryRun) console.log(`\u2705 Done.`);
15333
+ });
15334
+ var walkLocal = (abs) => {
15335
+ const st2 = statSync(abs);
15336
+ if (!st2.isDirectory()) return [abs];
15337
+ return readdirSync2(abs).filter((n7) => !n7.startsWith(".git")).flatMap((n7) => walkLocal(join5(abs, n7)));
15338
+ };
15339
+ var UploadCommand = () => instanceOption(
15340
+ new Command("upload").description(
15341
+ "Upload a file or folder to your instance, e.g. an existing pb_data or node_modules. Writing to pb_data needs the instance powered off"
15342
+ ).argument("<local>", "Local file or folder").argument(
15343
+ "[remote]",
15344
+ "Where to put it on the instance (defaults to the same relative path, e.g. pb_data/data.db)"
15345
+ ).option("-v, --verbose", "Print every file")
15346
+ ).action(async (local, remote, options2) => {
15347
+ const instanceName = requireInstance(options2.instance);
15348
+ const abs = resolve3(local);
15349
+ if (!existsSync5(abs)) throw new Error(`${local} not found`);
15350
+ const target = normalizeRemotePath(
15351
+ remote ?? relative4(process.cwd(), abs).split(sep3).join("/")
15352
+ );
15353
+ if (!target || target.startsWith(".."))
15354
+ throw new Error(
15355
+ `Give a remote path, e.g. 'pockethost upload ${local} pb_data/data.db'`
15356
+ );
15357
+ const files = await createFilesClient(instanceName);
15358
+ const all = walkLocal(abs);
15359
+ const total = all.reduce((n7, f) => n7 + statSync(f).size, 0);
15360
+ console.log(
15361
+ `\u2B06\uFE0F Uploading ${all.length} file(s) (${prettyBytes(total)}) to ${instanceName}:${target}`
15362
+ );
15363
+ let next = 0;
15364
+ let done = 0;
15365
+ const worker = async () => {
15366
+ while (next < all.length) {
15367
+ const f = all[next++];
15368
+ const rel = relative4(abs, f).split(sep3).join("/");
15369
+ const dest = rel ? `${target}/${rel}` : target;
15370
+ await files.upload(f, dest).catch((e) => {
15371
+ next = all.length;
15372
+ throw new Error(`${dest}: ${dataHint(e)}`);
15373
+ });
15374
+ done++;
15375
+ if (options2.verbose) console.log(` ${dest}`);
15376
+ else if (all.length > 50 && done % 250 === 0)
15377
+ console.log(` ${done}/${all.length}`);
15378
+ }
15379
+ };
15380
+ await Promise.all(
15381
+ Array.from({ length: Math.min(UPLOAD_CONCURRENCY, all.length) }, worker)
15382
+ );
15383
+ console.log(`\u2705 Done.`);
15384
+ });
15385
+ var RmCommand = () => instanceOption(
15386
+ new Command("rm").description(
15387
+ "Delete files on your instance, e.g. a migration that keeps it from starting"
15388
+ ).argument("<paths...>", "Files or folders on the instance").option("-r, --recursive", "Delete folders and everything in them")
15389
+ ).action(async (paths, options2) => {
15390
+ const instanceName = requireInstance(options2.instance);
15391
+ const files = await createFilesClient(instanceName);
15392
+ for (const p of paths) {
15393
+ await files.remove(p, !!options2.recursive).catch((e) => {
15394
+ throw new Error(`${p}: ${dataHint(e)}`);
15395
+ });
15396
+ console.log(`\u{1F5D1}\uFE0F Deleted ${instanceName}:${normalizeRemotePath(p)}`);
15397
+ }
15398
+ });
15399
+
15125
15400
  // src/commands/InfoCommand.ts
15126
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
15401
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
15127
15402
 
15128
15403
  // ../../node_modules/.pnpm/@inquirer+core@11.2.1_@types+node@20.19.43/node_modules/@inquirer/core/dist/lib/key.js
15129
15404
  var keybindings = ["emacs", "vim"];
@@ -16515,13 +16790,13 @@ var PromisePolyfill = class extends Promise {
16515
16790
  // Available starting from Node 22
16516
16791
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
16517
16792
  static withResolver() {
16518
- let resolve3;
16793
+ let resolve4;
16519
16794
  let reject;
16520
16795
  const promise = new Promise((res, rej) => {
16521
- resolve3 = res;
16796
+ resolve4 = res;
16522
16797
  reject = rej;
16523
16798
  });
16524
- return { promise, resolve: resolve3, reject };
16799
+ return { promise, resolve: resolve4, reject };
16525
16800
  }
16526
16801
  };
16527
16802
 
@@ -16558,7 +16833,7 @@ function createPrompt(view) {
16558
16833
  });
16559
16834
  output.mute();
16560
16835
  const screen = new ScreenManager(rl);
16561
- const { promise, resolve: resolve3, reject } = PromisePolyfill.withResolver();
16836
+ const { promise, resolve: resolve4, reject } = PromisePolyfill.withResolver();
16562
16837
  const cancel = () => reject(new CancelPromptError());
16563
16838
  if (signal) {
16564
16839
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -16589,7 +16864,7 @@ function createPrompt(view) {
16589
16864
  try {
16590
16865
  const nextView = view(config2, (value) => {
16591
16866
  if (effectsSettled) {
16592
- resolve3(value);
16867
+ resolve4(value);
16593
16868
  } else {
16594
16869
  pendingDone = { value };
16595
16870
  }
@@ -16612,7 +16887,7 @@ function createPrompt(view) {
16612
16887
  if (pendingDone !== null) {
16613
16888
  const { value } = pendingDone;
16614
16889
  pendingDone = null;
16615
- resolve3(value);
16890
+ resolve4(value);
16616
16891
  }
16617
16892
  });
16618
16893
  };
@@ -16932,7 +17207,7 @@ var TokenCommand = () => new Command("token").description(`Show, save or remove
16932
17207
  // src/commands/InfoCommand.ts
16933
17208
  var sshKeyStatus = async () => {
16934
17209
  const { publicKeyPath } = getDeployKeyPaths();
16935
- if (!existsSync5(publicKeyPath))
17210
+ if (!existsSync6(publicKeyPath))
16936
17211
  return `none yet (created the first time you use SFTP)`;
16937
17212
  const fingerprint = fingerprintForPublicKey(
16938
17213
  readFileSync5(publicKeyPath, "utf8").trim()
@@ -17169,7 +17444,7 @@ function fetchEventSource(input, {
17169
17444
  fetch: inputFetch,
17170
17445
  ...rest
17171
17446
  }) {
17172
- return new Promise((resolve3, reject) => {
17447
+ return new Promise((resolve4, reject) => {
17173
17448
  const headers = { ...inputHeaders };
17174
17449
  if (!headers.accept) {
17175
17450
  headers.accept = EventStreamContentType;
@@ -17193,7 +17468,7 @@ function fetchEventSource(input, {
17193
17468
  }
17194
17469
  inputSignal?.addEventListener("abort", () => {
17195
17470
  dispose();
17196
- resolve3();
17471
+ resolve4();
17197
17472
  });
17198
17473
  const fetch2 = inputFetch ?? globalThis.fetch;
17199
17474
  const onopen = inputOnOpen ?? defaultOnOpen;
@@ -17220,7 +17495,7 @@ function fetchEventSource(input, {
17220
17495
  }, onmessage)));
17221
17496
  onclose?.();
17222
17497
  dispose();
17223
- resolve3();
17498
+ resolve4();
17224
17499
  } catch (err) {
17225
17500
  if (!curRequestController.signal.aborted) {
17226
17501
  try {
@@ -17263,14 +17538,14 @@ var watchInstanceLog = async (instanceName, update, nInitial = 100) => {
17263
17538
  retryTimeout = null;
17264
17539
  }
17265
17540
  };
17266
- const streamingPromise = new Promise((resolve3, reject) => {
17541
+ const streamingPromise = new Promise((resolve4, reject) => {
17267
17542
  signal.addEventListener("abort", () => {
17268
17543
  clearPendingTimeouts();
17269
- resolve3();
17544
+ resolve4();
17270
17545
  });
17271
17546
  const continuallyFetchFromEventSource = () => {
17272
17547
  if (isAborting) {
17273
- resolve3();
17548
+ resolve4();
17274
17549
  return;
17275
17550
  }
17276
17551
  fetchEventSource(`${api.base}/logs?n=${nInitial}`, {
@@ -17432,7 +17707,7 @@ var SftpCommand = () => {
17432
17707
 
17433
17708
  // src/cli.ts
17434
17709
  ensureProjectRoot();
17435
- program.name(`pockethost`).version(version).description(`Deploy, sync, and tail logs for your PocketHost instances`).addCommand(LoginCommand()).addCommand(TokenCommand()).addCommand(LogsCommand()).addCommand(DevCommand()).addCommand(ListCommand()).addCommand(LinkCommand()).addCommand(DeployCommand()).addCommand(SftpCommand()).addCommand(LogoutCommand()).addCommand(InfoCommand());
17710
+ program.name(`pockethost`).version(version).description(`Deploy, sync, and tail logs for your PocketHost instances`).addCommand(LoginCommand()).addCommand(TokenCommand()).addCommand(LogsCommand()).addCommand(DevCommand()).addCommand(ListCommand()).addCommand(LinkCommand()).addCommand(DeployCommand()).addCommand(FilesCommand()).addCommand(PullCommand()).addCommand(UploadCommand()).addCommand(RmCommand()).addCommand(SftpCommand()).addCommand(LogoutCommand()).addCommand(InfoCommand());
17436
17711
  program.exitOverride();
17437
17712
  program.parseAsync(process.argv).catch((err) => {
17438
17713
  if (err.code === "commander.helpDisplayed" || err.code === "commander.help" || err.code === "commander.version") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pockethost",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "The PocketHost CLI: deploy, sync, and tail logs for your PocketHost instances",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,15 +25,6 @@
25
25
  "engines": {
26
26
  "node": ">=20"
27
27
  },
28
- "scripts": {
29
- "build": "node scripts/build.mjs",
30
- "check:types": "tsc --noEmit",
31
- "dev": "node --import tsx ./src/cli.ts",
32
- "start": "node --import tsx ./src/cli.ts",
33
- "test": "vitest run",
34
- "prepublishOnly": "pnpm check:types && pnpm test",
35
- "prepack": "pnpm build"
36
- },
37
28
  "files": [
38
29
  "dist",
39
30
  "CHANGELOG.md",
@@ -66,5 +57,12 @@
66
57
  "semi": false,
67
58
  "singleQuote": true,
68
59
  "trailingComma": "es5"
60
+ },
61
+ "scripts": {
62
+ "build": "node scripts/build.mjs",
63
+ "check:types": "tsc --noEmit",
64
+ "dev": "node --import tsx ./src/cli.ts",
65
+ "start": "node --import tsx ./src/cli.ts",
66
+ "test": "vitest run"
69
67
  }
70
- }
68
+ }