@coffre/cli 0.1.13 → 0.1.14

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.
@@ -1,1785 +1,17 @@
1
1
  import { d as esm_default } from "./esm-Bts-esAl.js";
2
- import { C as yes, E as isEmpty, S as wrap, T as init, _ as select, b as truncate, c as Cancelled, d as listed, f as openTerminal, g as row, h as release, i as keyValues, l as edit, m as readKeys, n as jsonWarning, o as needsTerminal, p as paragraph, r as keyGuide, s as showSecrets, t as generateKeys, u as hiddenLine, v as style, w as KINDS, x as width, y as textLine } from "./keys-BCKUEb-Y.js";
3
- import { r as postgresConnection, t as engineOfUrl } from "./connect-tekAM4hC.js";
2
+ import { n as init, t as KINDS } from "./init-mO8V087p.js";
3
+ import { i as keyValues, n as jsonWarning, o as needsTerminal, r as keyGuide, s as showSecrets, t as generateKeys } from "./keys-DDdMwm0N.js";
4
+ import { a as openTerminal, c as release, d as style, f as textLine, i as listed, l as row, o as paragraph, t as Cancelled, u as select } from "./tty-BDa14JX2.js";
5
+ import { r as postgresConnection } from "./connect-C4wevMJ5.js";
6
+ import { n as migrateDatabase, t as readDatabaseUrl } from "./database-url-CJ9yqoi_.js";
7
+ import { n as StepFailed, r as Steps, t as cliVersion } from "./version-CPk6zTTK.js";
8
+ import { a as install, i as editWorker, o as placeholder, r as deploymentKind, s as readWorker } from "./deployment-S8za5nUu.js";
4
9
  import { parseArgs } from "node:util";
5
10
  import { spawn } from "node:child_process";
6
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
11
+ import { existsSync } from "node:fs";
7
12
  import { join } from "node:path";
8
- import { fileURLToPath } from "node:url";
9
13
  import { createHash, createHmac, pbkdf2Sync, randomBytes } from "node:crypto";
10
- import { readFile } from "node:fs/promises";
11
14
  import { createServer, get } from "node:http";
12
- //#region ../db/dist/migrate.js
13
- /**
14
- * Bring a database up to date with its engine's migration tree:
15
- * migrations/postgres or migrations/sqlite. Both trees
16
- * describe one schema; see schema-parity.test.ts.
17
- *
18
- * Applied history must be a prefix of the local journal, byte for byte,
19
- * before and after. Only one migrator runs at a time: Postgres takes an
20
- * advisory lock, and SQLite's own write lock covers the
21
- * whole run. Restricted runtime roles are Postgres-only (baseline/postgres.sql).
22
- */
23
- const MIGRATION_LOCK_KEY = "7165058122361679213";
24
- /** Reassert database privileges that pg_dump and CREATE DATABASE TEMPLATE do not carry. */
25
- async function restrictDatabase(client) {
26
- await client.query(`DO $$ BEGIN
27
- EXECUTE format(
28
- 'REVOKE CREATE, TEMPORARY ON DATABASE %I FROM PUBLIC, coffre_app, coffre_runtime, coffre_vault, coffre_vault_runtime',
29
- current_database()
30
- );
31
- END $$`);
32
- }
33
- /**
34
- * Beside this module: src/migrations in the workspace, and dist/migrations
35
- * in the built package, where the build copies them.
36
- */
37
- function migrationsFolder(engine) {
38
- return fileURLToPath(new URL(`./migrations/${engine}`, import.meta.url));
39
- }
40
- async function expectedMigrations(engine) {
41
- const folder = migrationsFolder(engine);
42
- const journal = JSON.parse(await readFile(`${folder}/meta/_journal.json`, "utf8"));
43
- if (!Array.isArray(journal.entries)) throw new Error("invalid Drizzle migration journal");
44
- const expected = await Promise.all(journal.entries.map(async (entry, position) => {
45
- if (entry.idx !== position || !Number.isSafeInteger(entry.when) || typeof entry.tag !== "string" || !/^[a-zA-Z0-9_-]+$/.test(entry.tag)) throw new Error(`invalid Drizzle migration journal entry at index ${position}`);
46
- const sqlText = await readFile(`${folder}/${entry.tag}.sql`, "utf8");
47
- return {
48
- createdAt: String(entry.when),
49
- hash: createHash("sha256").update(sqlText).digest("hex"),
50
- tag: entry.tag
51
- };
52
- }));
53
- for (let index = 1; index < expected.length; index += 1) if (BigInt(expected[index - 1].createdAt) >= BigInt(expected[index].createdAt)) throw new Error("Drizzle migration journal timestamps must be strictly increasing");
54
- return expected;
55
- }
56
- function verifyHistory(expected, applied, requireComplete) {
57
- const rows = applied ?? [];
58
- if (rows.length > expected.length) throw new Error("database contains migrations that are absent from this image");
59
- if (requireComplete && rows.length !== expected.length) throw new Error(`migration history is incomplete: expected ${expected.length}, found ${rows.length}`);
60
- rows.forEach((row, index) => {
61
- const local = expected[index];
62
- if (row.created_at !== local.createdAt || row.hash !== local.hash) throw new Error(`migration history diverged at ${local.tag}; applied migrations must never be edited`);
63
- });
64
- }
65
- async function postgresMigrator(url) {
66
- const [{ default: pg }, { drizzle }, { migrate }] = await Promise.all([
67
- import("./esm-B69mMLcR.js"),
68
- import("./node-postgres-BWEOOdc6.js"),
69
- import("./migrator-W1a-ooWi.js")
70
- ]);
71
- const pool = new pg.Pool({
72
- ...postgresConnection(url),
73
- application_name: "coffre-migrations",
74
- max: 1
75
- });
76
- const client = await pool.connect();
77
- return {
78
- async applied() {
79
- if (!(await client.query("SELECT to_regclass('drizzle.__drizzle_migrations')::text AS relation")).rows[0]?.relation) return null;
80
- return (await client.query("SELECT hash, created_at::text FROM drizzle.__drizzle_migrations ORDER BY created_at, id")).rows;
81
- },
82
- async lock() {
83
- await client.query("SET lock_timeout = '5min'");
84
- await client.query("SELECT pg_advisory_lock($1::bigint)", [MIGRATION_LOCK_KEY]);
85
- },
86
- async unlock() {
87
- await client.query("SELECT pg_advisory_unlock($1::bigint)", [MIGRATION_LOCK_KEY]);
88
- },
89
- migrate: (migrationsFolder) => migrate(drizzle(client), { migrationsFolder }),
90
- restrict: () => restrictDatabase(client),
91
- async close() {
92
- client.release();
93
- await pool.end();
94
- }
95
- };
96
- }
97
- async function sqliteMigrator(url) {
98
- const [{ openDatabase }, { migrate }] = await Promise.all([import("./connect-BXDkiWOL.js"), import("drizzle-orm/libsql/migrator")]);
99
- const { db, close } = await openDatabase(url);
100
- const sqlite = db;
101
- return {
102
- async applied() {
103
- if ((await sqlite.all("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = '__drizzle_migrations'")).length === 0) return null;
104
- return sqlite.all("SELECT hash, CAST(created_at AS TEXT) AS created_at FROM __drizzle_migrations ORDER BY created_at, id");
105
- },
106
- async lock() {},
107
- async unlock() {},
108
- migrate: (migrationsFolder) => migrate(sqlite, { migrationsFolder }),
109
- async restrict() {},
110
- close
111
- };
112
- }
113
- /**
114
- * Apply missing migrations, check their history and reassert database
115
- * privileges. `onPlan` hears how many there are to apply before they are:
116
- * all of them go in one call, with no word of each.
117
- */
118
- async function migrateDatabase(url, onPlan) {
119
- const engine = engineOfUrl(url);
120
- const expected = await expectedMigrations(engine);
121
- const migrator = await {
122
- postgres: postgresMigrator,
123
- sqlite: sqliteMigrator
124
- }[engine](url);
125
- let locked = false;
126
- try {
127
- await migrator.lock();
128
- locked = true;
129
- const applied = await migrator.applied();
130
- verifyHistory(expected, applied, false);
131
- onPlan?.({
132
- applied: applied?.length ?? 0,
133
- total: expected.length
134
- });
135
- await migrator.migrate(migrationsFolder(engine));
136
- verifyHistory(expected, await migrator.applied(), true);
137
- await migrator.restrict();
138
- } finally {
139
- try {
140
- if (locked) await migrator.unlock();
141
- } finally {
142
- await migrator.close();
143
- }
144
- }
145
- }
146
- //#endregion
147
- //#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
148
- /**
149
- * Creates a JSON scanner on the given text.
150
- * If ignoreTrivia is set, whitespaces or comments are ignored.
151
- */
152
- function createScanner(text, ignoreTrivia = false) {
153
- const len = text.length;
154
- let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
155
- function scanHexDigits(count, exact) {
156
- let digits = 0;
157
- let value = 0;
158
- while (digits < count || !exact) {
159
- let ch = text.charCodeAt(pos);
160
- if (ch >= 48 && ch <= 57) value = value * 16 + ch - 48;
161
- else if (ch >= 65 && ch <= 70) value = value * 16 + ch - 65 + 10;
162
- else if (ch >= 97 && ch <= 102) value = value * 16 + ch - 97 + 10;
163
- else break;
164
- pos++;
165
- digits++;
166
- }
167
- if (digits < count) value = -1;
168
- return value;
169
- }
170
- function setPosition(newPosition) {
171
- pos = newPosition;
172
- value = "";
173
- tokenOffset = 0;
174
- token = 16;
175
- scanError = 0;
176
- }
177
- function scanNumber() {
178
- let start = pos;
179
- if (text.charCodeAt(pos) === 48) pos++;
180
- else {
181
- pos++;
182
- while (pos < text.length && isDigit(text.charCodeAt(pos))) pos++;
183
- }
184
- if (pos < text.length && text.charCodeAt(pos) === 46) {
185
- pos++;
186
- if (pos < text.length && isDigit(text.charCodeAt(pos))) {
187
- pos++;
188
- while (pos < text.length && isDigit(text.charCodeAt(pos))) pos++;
189
- } else {
190
- scanError = 3;
191
- return text.substring(start, pos);
192
- }
193
- }
194
- let end = pos;
195
- if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
196
- pos++;
197
- if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) pos++;
198
- if (pos < text.length && isDigit(text.charCodeAt(pos))) {
199
- pos++;
200
- while (pos < text.length && isDigit(text.charCodeAt(pos))) pos++;
201
- end = pos;
202
- } else scanError = 3;
203
- }
204
- return text.substring(start, end);
205
- }
206
- function scanString() {
207
- let result = "", start = pos;
208
- while (true) {
209
- if (pos >= len) {
210
- result += text.substring(start, pos);
211
- scanError = 2;
212
- break;
213
- }
214
- const ch = text.charCodeAt(pos);
215
- if (ch === 34) {
216
- result += text.substring(start, pos);
217
- pos++;
218
- break;
219
- }
220
- if (ch === 92) {
221
- result += text.substring(start, pos);
222
- pos++;
223
- if (pos >= len) {
224
- scanError = 2;
225
- break;
226
- }
227
- switch (text.charCodeAt(pos++)) {
228
- case 34:
229
- result += "\"";
230
- break;
231
- case 92:
232
- result += "\\";
233
- break;
234
- case 47:
235
- result += "/";
236
- break;
237
- case 98:
238
- result += "\b";
239
- break;
240
- case 102:
241
- result += "\f";
242
- break;
243
- case 110:
244
- result += "\n";
245
- break;
246
- case 114:
247
- result += "\r";
248
- break;
249
- case 116:
250
- result += " ";
251
- break;
252
- case 117:
253
- const ch3 = scanHexDigits(4, true);
254
- if (ch3 >= 0) result += String.fromCharCode(ch3);
255
- else scanError = 4;
256
- break;
257
- default: scanError = 5;
258
- }
259
- start = pos;
260
- continue;
261
- }
262
- if (ch >= 0 && ch <= 31) {
263
- if (isLineBreak(ch)) {
264
- result += text.substring(start, pos);
265
- scanError = 2;
266
- break;
267
- } else scanError = 6;
268
- }
269
- pos++;
270
- }
271
- return result;
272
- }
273
- function scanNext() {
274
- value = "";
275
- scanError = 0;
276
- tokenOffset = pos;
277
- lineStartOffset = lineNumber;
278
- prevTokenLineStartOffset = tokenLineStartOffset;
279
- if (pos >= len) {
280
- tokenOffset = len;
281
- return token = 17;
282
- }
283
- let code = text.charCodeAt(pos);
284
- if (isWhiteSpace(code)) {
285
- do {
286
- pos++;
287
- value += String.fromCharCode(code);
288
- code = text.charCodeAt(pos);
289
- } while (isWhiteSpace(code));
290
- return token = 15;
291
- }
292
- if (isLineBreak(code)) {
293
- pos++;
294
- value += String.fromCharCode(code);
295
- if (code === 13 && text.charCodeAt(pos) === 10) {
296
- pos++;
297
- value += "\n";
298
- }
299
- lineNumber++;
300
- tokenLineStartOffset = pos;
301
- return token = 14;
302
- }
303
- switch (code) {
304
- case 123:
305
- pos++;
306
- return token = 1;
307
- case 125:
308
- pos++;
309
- return token = 2;
310
- case 91:
311
- pos++;
312
- return token = 3;
313
- case 93:
314
- pos++;
315
- return token = 4;
316
- case 58:
317
- pos++;
318
- return token = 6;
319
- case 44:
320
- pos++;
321
- return token = 5;
322
- case 34:
323
- pos++;
324
- value = scanString();
325
- return token = 10;
326
- case 47:
327
- const start = pos - 1;
328
- if (text.charCodeAt(pos + 1) === 47) {
329
- pos += 2;
330
- while (pos < len) {
331
- if (isLineBreak(text.charCodeAt(pos))) break;
332
- pos++;
333
- }
334
- value = text.substring(start, pos);
335
- return token = 12;
336
- }
337
- if (text.charCodeAt(pos + 1) === 42) {
338
- pos += 2;
339
- const safeLength = len - 1;
340
- let commentClosed = false;
341
- while (pos < safeLength) {
342
- const ch = text.charCodeAt(pos);
343
- if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
344
- pos += 2;
345
- commentClosed = true;
346
- break;
347
- }
348
- pos++;
349
- if (isLineBreak(ch)) {
350
- if (ch === 13 && text.charCodeAt(pos) === 10) pos++;
351
- lineNumber++;
352
- tokenLineStartOffset = pos;
353
- }
354
- }
355
- if (!commentClosed) {
356
- pos++;
357
- scanError = 1;
358
- }
359
- value = text.substring(start, pos);
360
- return token = 13;
361
- }
362
- value += String.fromCharCode(code);
363
- pos++;
364
- return token = 16;
365
- case 45:
366
- value += String.fromCharCode(code);
367
- pos++;
368
- if (pos === len || !isDigit(text.charCodeAt(pos))) return token = 16;
369
- case 48:
370
- case 49:
371
- case 50:
372
- case 51:
373
- case 52:
374
- case 53:
375
- case 54:
376
- case 55:
377
- case 56:
378
- case 57:
379
- value += scanNumber();
380
- return token = 11;
381
- default:
382
- while (pos < len && isUnknownContentCharacter(code)) {
383
- pos++;
384
- code = text.charCodeAt(pos);
385
- }
386
- if (tokenOffset !== pos) {
387
- value = text.substring(tokenOffset, pos);
388
- switch (value) {
389
- case "true": return token = 8;
390
- case "false": return token = 9;
391
- case "null": return token = 7;
392
- }
393
- return token = 16;
394
- }
395
- value += String.fromCharCode(code);
396
- pos++;
397
- return token = 16;
398
- }
399
- }
400
- function isUnknownContentCharacter(code) {
401
- if (isWhiteSpace(code) || isLineBreak(code)) return false;
402
- switch (code) {
403
- case 125:
404
- case 93:
405
- case 123:
406
- case 91:
407
- case 34:
408
- case 58:
409
- case 44:
410
- case 47: return false;
411
- }
412
- return true;
413
- }
414
- function scanNextNonTrivia() {
415
- let result;
416
- do
417
- result = scanNext();
418
- while (result >= 12 && result <= 15);
419
- return result;
420
- }
421
- return {
422
- setPosition,
423
- getPosition: () => pos,
424
- scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
425
- getToken: () => token,
426
- getTokenValue: () => value,
427
- getTokenOffset: () => tokenOffset,
428
- getTokenLength: () => pos - tokenOffset,
429
- getTokenStartLine: () => lineStartOffset,
430
- getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
431
- getTokenError: () => scanError
432
- };
433
- }
434
- function isWhiteSpace(ch) {
435
- return ch === 32 || ch === 9;
436
- }
437
- function isLineBreak(ch) {
438
- return ch === 10 || ch === 13;
439
- }
440
- function isDigit(ch) {
441
- return ch >= 48 && ch <= 57;
442
- }
443
- var CharacterCodes;
444
- (function(CharacterCodes) {
445
- CharacterCodes[CharacterCodes["lineFeed"] = 10] = "lineFeed";
446
- CharacterCodes[CharacterCodes["carriageReturn"] = 13] = "carriageReturn";
447
- CharacterCodes[CharacterCodes["space"] = 32] = "space";
448
- CharacterCodes[CharacterCodes["_0"] = 48] = "_0";
449
- CharacterCodes[CharacterCodes["_1"] = 49] = "_1";
450
- CharacterCodes[CharacterCodes["_2"] = 50] = "_2";
451
- CharacterCodes[CharacterCodes["_3"] = 51] = "_3";
452
- CharacterCodes[CharacterCodes["_4"] = 52] = "_4";
453
- CharacterCodes[CharacterCodes["_5"] = 53] = "_5";
454
- CharacterCodes[CharacterCodes["_6"] = 54] = "_6";
455
- CharacterCodes[CharacterCodes["_7"] = 55] = "_7";
456
- CharacterCodes[CharacterCodes["_8"] = 56] = "_8";
457
- CharacterCodes[CharacterCodes["_9"] = 57] = "_9";
458
- CharacterCodes[CharacterCodes["a"] = 97] = "a";
459
- CharacterCodes[CharacterCodes["b"] = 98] = "b";
460
- CharacterCodes[CharacterCodes["c"] = 99] = "c";
461
- CharacterCodes[CharacterCodes["d"] = 100] = "d";
462
- CharacterCodes[CharacterCodes["e"] = 101] = "e";
463
- CharacterCodes[CharacterCodes["f"] = 102] = "f";
464
- CharacterCodes[CharacterCodes["g"] = 103] = "g";
465
- CharacterCodes[CharacterCodes["h"] = 104] = "h";
466
- CharacterCodes[CharacterCodes["i"] = 105] = "i";
467
- CharacterCodes[CharacterCodes["j"] = 106] = "j";
468
- CharacterCodes[CharacterCodes["k"] = 107] = "k";
469
- CharacterCodes[CharacterCodes["l"] = 108] = "l";
470
- CharacterCodes[CharacterCodes["m"] = 109] = "m";
471
- CharacterCodes[CharacterCodes["n"] = 110] = "n";
472
- CharacterCodes[CharacterCodes["o"] = 111] = "o";
473
- CharacterCodes[CharacterCodes["p"] = 112] = "p";
474
- CharacterCodes[CharacterCodes["q"] = 113] = "q";
475
- CharacterCodes[CharacterCodes["r"] = 114] = "r";
476
- CharacterCodes[CharacterCodes["s"] = 115] = "s";
477
- CharacterCodes[CharacterCodes["t"] = 116] = "t";
478
- CharacterCodes[CharacterCodes["u"] = 117] = "u";
479
- CharacterCodes[CharacterCodes["v"] = 118] = "v";
480
- CharacterCodes[CharacterCodes["w"] = 119] = "w";
481
- CharacterCodes[CharacterCodes["x"] = 120] = "x";
482
- CharacterCodes[CharacterCodes["y"] = 121] = "y";
483
- CharacterCodes[CharacterCodes["z"] = 122] = "z";
484
- CharacterCodes[CharacterCodes["A"] = 65] = "A";
485
- CharacterCodes[CharacterCodes["B"] = 66] = "B";
486
- CharacterCodes[CharacterCodes["C"] = 67] = "C";
487
- CharacterCodes[CharacterCodes["D"] = 68] = "D";
488
- CharacterCodes[CharacterCodes["E"] = 69] = "E";
489
- CharacterCodes[CharacterCodes["F"] = 70] = "F";
490
- CharacterCodes[CharacterCodes["G"] = 71] = "G";
491
- CharacterCodes[CharacterCodes["H"] = 72] = "H";
492
- CharacterCodes[CharacterCodes["I"] = 73] = "I";
493
- CharacterCodes[CharacterCodes["J"] = 74] = "J";
494
- CharacterCodes[CharacterCodes["K"] = 75] = "K";
495
- CharacterCodes[CharacterCodes["L"] = 76] = "L";
496
- CharacterCodes[CharacterCodes["M"] = 77] = "M";
497
- CharacterCodes[CharacterCodes["N"] = 78] = "N";
498
- CharacterCodes[CharacterCodes["O"] = 79] = "O";
499
- CharacterCodes[CharacterCodes["P"] = 80] = "P";
500
- CharacterCodes[CharacterCodes["Q"] = 81] = "Q";
501
- CharacterCodes[CharacterCodes["R"] = 82] = "R";
502
- CharacterCodes[CharacterCodes["S"] = 83] = "S";
503
- CharacterCodes[CharacterCodes["T"] = 84] = "T";
504
- CharacterCodes[CharacterCodes["U"] = 85] = "U";
505
- CharacterCodes[CharacterCodes["V"] = 86] = "V";
506
- CharacterCodes[CharacterCodes["W"] = 87] = "W";
507
- CharacterCodes[CharacterCodes["X"] = 88] = "X";
508
- CharacterCodes[CharacterCodes["Y"] = 89] = "Y";
509
- CharacterCodes[CharacterCodes["Z"] = 90] = "Z";
510
- CharacterCodes[CharacterCodes["asterisk"] = 42] = "asterisk";
511
- CharacterCodes[CharacterCodes["backslash"] = 92] = "backslash";
512
- CharacterCodes[CharacterCodes["closeBrace"] = 125] = "closeBrace";
513
- CharacterCodes[CharacterCodes["closeBracket"] = 93] = "closeBracket";
514
- CharacterCodes[CharacterCodes["colon"] = 58] = "colon";
515
- CharacterCodes[CharacterCodes["comma"] = 44] = "comma";
516
- CharacterCodes[CharacterCodes["dot"] = 46] = "dot";
517
- CharacterCodes[CharacterCodes["doubleQuote"] = 34] = "doubleQuote";
518
- CharacterCodes[CharacterCodes["minus"] = 45] = "minus";
519
- CharacterCodes[CharacterCodes["openBrace"] = 123] = "openBrace";
520
- CharacterCodes[CharacterCodes["openBracket"] = 91] = "openBracket";
521
- CharacterCodes[CharacterCodes["plus"] = 43] = "plus";
522
- CharacterCodes[CharacterCodes["slash"] = 47] = "slash";
523
- CharacterCodes[CharacterCodes["formFeed"] = 12] = "formFeed";
524
- CharacterCodes[CharacterCodes["tab"] = 9] = "tab";
525
- })(CharacterCodes || (CharacterCodes = {}));
526
- //#endregion
527
- //#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/string-intern.js
528
- const cachedSpaces = new Array(20).fill(0).map((_, index) => {
529
- return " ".repeat(index);
530
- });
531
- const maxCachedValues = 200;
532
- const cachedBreakLinesWithSpaces = {
533
- " ": {
534
- "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
535
- return "\n" + " ".repeat(index);
536
- }),
537
- "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
538
- return "\r" + " ".repeat(index);
539
- }),
540
- "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
541
- return "\r\n" + " ".repeat(index);
542
- })
543
- },
544
- " ": {
545
- "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
546
- return "\n" + " ".repeat(index);
547
- }),
548
- "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
549
- return "\r" + " ".repeat(index);
550
- }),
551
- "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
552
- return "\r\n" + " ".repeat(index);
553
- })
554
- }
555
- };
556
- const supportedEols = [
557
- "\n",
558
- "\r",
559
- "\r\n"
560
- ];
561
- //#endregion
562
- //#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/format.js
563
- function format(documentText, range, options) {
564
- let initialIndentLevel;
565
- let formatText;
566
- let formatTextStart;
567
- let rangeStart;
568
- let rangeEnd;
569
- if (range) {
570
- rangeStart = range.offset;
571
- rangeEnd = rangeStart + range.length;
572
- formatTextStart = rangeStart;
573
- while (formatTextStart > 0 && !isEOL(documentText, formatTextStart - 1)) formatTextStart--;
574
- let endOffset = rangeEnd;
575
- while (endOffset < documentText.length && !isEOL(documentText, endOffset)) endOffset++;
576
- formatText = documentText.substring(formatTextStart, endOffset);
577
- initialIndentLevel = computeIndentLevel(formatText, options);
578
- } else {
579
- formatText = documentText;
580
- initialIndentLevel = 0;
581
- formatTextStart = 0;
582
- rangeStart = 0;
583
- rangeEnd = documentText.length;
584
- }
585
- const eol = getEOL(options, documentText);
586
- const eolFastPathSupported = supportedEols.includes(eol);
587
- let numberLineBreaks = 0;
588
- let indentLevel = 0;
589
- let indentValue;
590
- if (options.insertSpaces) indentValue = cachedSpaces[options.tabSize || 4] ?? repeat(cachedSpaces[1], options.tabSize || 4);
591
- else indentValue = " ";
592
- const indentType = indentValue === " " ? " " : " ";
593
- let scanner = createScanner(formatText, false);
594
- let hasError = false;
595
- function newLinesAndIndent() {
596
- if (numberLineBreaks > 1) return repeat(eol, numberLineBreaks) + repeat(indentValue, initialIndentLevel + indentLevel);
597
- const amountOfSpaces = indentValue.length * (initialIndentLevel + indentLevel);
598
- if (!eolFastPathSupported || amountOfSpaces > cachedBreakLinesWithSpaces[indentType][eol].length) return eol + repeat(indentValue, initialIndentLevel + indentLevel);
599
- if (amountOfSpaces <= 0) return eol;
600
- return cachedBreakLinesWithSpaces[indentType][eol][amountOfSpaces];
601
- }
602
- function scanNext() {
603
- let token = scanner.scan();
604
- numberLineBreaks = 0;
605
- while (token === 15 || token === 14) {
606
- if (token === 14 && options.keepLines) numberLineBreaks += 1;
607
- else if (token === 14) numberLineBreaks = 1;
608
- token = scanner.scan();
609
- }
610
- hasError = token === 16 || scanner.getTokenError() !== 0;
611
- return token;
612
- }
613
- const editOperations = [];
614
- function addEdit(text, startOffset, endOffset) {
615
- if (!hasError && (!range || startOffset < rangeEnd && endOffset > rangeStart) && documentText.substring(startOffset, endOffset) !== text) editOperations.push({
616
- offset: startOffset,
617
- length: endOffset - startOffset,
618
- content: text
619
- });
620
- }
621
- let firstToken = scanNext();
622
- if (options.keepLines && numberLineBreaks > 0) addEdit(repeat(eol, numberLineBreaks), 0, 0);
623
- if (firstToken !== 17) {
624
- let firstTokenStart = scanner.getTokenOffset() + formatTextStart;
625
- addEdit(indentValue.length * initialIndentLevel < 20 && options.insertSpaces ? cachedSpaces[indentValue.length * initialIndentLevel] : repeat(indentValue, initialIndentLevel), formatTextStart, firstTokenStart);
626
- }
627
- while (firstToken !== 17) {
628
- let firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
629
- let secondToken = scanNext();
630
- let replaceContent = "";
631
- let needsLineBreak = false;
632
- while (numberLineBreaks === 0 && (secondToken === 12 || secondToken === 13)) {
633
- let commentTokenStart = scanner.getTokenOffset() + formatTextStart;
634
- addEdit(cachedSpaces[1], firstTokenEnd, commentTokenStart);
635
- firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
636
- needsLineBreak = secondToken === 12;
637
- replaceContent = needsLineBreak ? newLinesAndIndent() : "";
638
- secondToken = scanNext();
639
- }
640
- if (secondToken === 2) {
641
- if (firstToken !== 1) indentLevel--;
642
- if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 1) replaceContent = newLinesAndIndent();
643
- else if (options.keepLines) replaceContent = cachedSpaces[1];
644
- } else if (secondToken === 4) {
645
- if (firstToken !== 3) indentLevel--;
646
- if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 3) replaceContent = newLinesAndIndent();
647
- else if (options.keepLines) replaceContent = cachedSpaces[1];
648
- } else {
649
- switch (firstToken) {
650
- case 3:
651
- case 1:
652
- indentLevel++;
653
- if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) replaceContent = newLinesAndIndent();
654
- else replaceContent = cachedSpaces[1];
655
- break;
656
- case 5:
657
- if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) replaceContent = newLinesAndIndent();
658
- else replaceContent = cachedSpaces[1];
659
- break;
660
- case 12:
661
- replaceContent = newLinesAndIndent();
662
- break;
663
- case 13:
664
- if (numberLineBreaks > 0) replaceContent = newLinesAndIndent();
665
- else if (!needsLineBreak) replaceContent = cachedSpaces[1];
666
- break;
667
- case 6:
668
- if (options.keepLines && numberLineBreaks > 0) replaceContent = newLinesAndIndent();
669
- else if (!needsLineBreak) replaceContent = cachedSpaces[1];
670
- break;
671
- case 10:
672
- if (options.keepLines && numberLineBreaks > 0) replaceContent = newLinesAndIndent();
673
- else if (secondToken === 6 && !needsLineBreak) replaceContent = "";
674
- break;
675
- case 7:
676
- case 8:
677
- case 9:
678
- case 11:
679
- case 2:
680
- case 4:
681
- if (options.keepLines && numberLineBreaks > 0) replaceContent = newLinesAndIndent();
682
- else if ((secondToken === 12 || secondToken === 13) && !needsLineBreak) replaceContent = cachedSpaces[1];
683
- else if (secondToken !== 5 && secondToken !== 17) hasError = true;
684
- break;
685
- case 16: hasError = true;
686
- }
687
- if (numberLineBreaks > 0 && (secondToken === 12 || secondToken === 13)) replaceContent = newLinesAndIndent();
688
- }
689
- if (secondToken === 17) {
690
- if (options.keepLines && numberLineBreaks > 0) replaceContent = newLinesAndIndent();
691
- else replaceContent = options.insertFinalNewline ? eol : "";
692
- }
693
- const secondTokenStart = scanner.getTokenOffset() + formatTextStart;
694
- addEdit(replaceContent, firstTokenEnd, secondTokenStart);
695
- firstToken = secondToken;
696
- }
697
- return editOperations;
698
- }
699
- function repeat(s, count) {
700
- let result = "";
701
- for (let i = 0; i < count; i++) result += s;
702
- return result;
703
- }
704
- function computeIndentLevel(content, options) {
705
- let i = 0;
706
- let nChars = 0;
707
- const tabSize = options.tabSize || 4;
708
- while (i < content.length) {
709
- let ch = content.charAt(i);
710
- if (ch === cachedSpaces[1]) nChars++;
711
- else if (ch === " ") nChars += tabSize;
712
- else break;
713
- i++;
714
- }
715
- return Math.floor(nChars / tabSize);
716
- }
717
- function getEOL(options, text) {
718
- for (let i = 0; i < text.length; i++) {
719
- const ch = text.charAt(i);
720
- if (ch === "\r") {
721
- if (i + 1 < text.length && text.charAt(i + 1) === "\n") return "\r\n";
722
- return "\r";
723
- } else if (ch === "\n") return "\n";
724
- }
725
- return options && options.eol || "\n";
726
- }
727
- function isEOL(text, offset) {
728
- return "\r\n".indexOf(text.charAt(offset)) !== -1;
729
- }
730
- //#endregion
731
- //#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js
732
- var ParseOptions;
733
- (function(ParseOptions) {
734
- ParseOptions.DEFAULT = { allowTrailingComma: false };
735
- })(ParseOptions || (ParseOptions = {}));
736
- /**
737
- * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
738
- * Therefore always check the errors list to find out if the input was valid.
739
- */
740
- function parse$1(text, errors = [], options = ParseOptions.DEFAULT) {
741
- let currentProperty = null;
742
- let currentParent = [];
743
- const previousParents = [];
744
- function onValue(value) {
745
- if (Array.isArray(currentParent)) currentParent.push(value);
746
- else if (currentProperty !== null) currentParent[currentProperty] = value;
747
- }
748
- visit(text, {
749
- onObjectBegin: () => {
750
- const object = {};
751
- onValue(object);
752
- previousParents.push(currentParent);
753
- currentParent = object;
754
- currentProperty = null;
755
- },
756
- onObjectProperty: (name) => {
757
- currentProperty = name;
758
- },
759
- onObjectEnd: () => {
760
- currentParent = previousParents.pop();
761
- },
762
- onArrayBegin: () => {
763
- const array = [];
764
- onValue(array);
765
- previousParents.push(currentParent);
766
- currentParent = array;
767
- currentProperty = null;
768
- },
769
- onArrayEnd: () => {
770
- currentParent = previousParents.pop();
771
- },
772
- onLiteralValue: onValue,
773
- onError: (error, offset, length) => {
774
- errors.push({
775
- error,
776
- offset,
777
- length
778
- });
779
- }
780
- }, options);
781
- return currentParent[0];
782
- }
783
- /**
784
- * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
785
- */
786
- function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
787
- let currentParent = {
788
- type: "array",
789
- offset: -1,
790
- length: -1,
791
- children: [],
792
- parent: void 0
793
- };
794
- function ensurePropertyComplete(endOffset) {
795
- if (currentParent.type === "property") {
796
- currentParent.length = endOffset - currentParent.offset;
797
- currentParent = currentParent.parent;
798
- }
799
- }
800
- function onValue(valueNode) {
801
- currentParent.children.push(valueNode);
802
- return valueNode;
803
- }
804
- visit(text, {
805
- onObjectBegin: (offset) => {
806
- currentParent = onValue({
807
- type: "object",
808
- offset,
809
- length: -1,
810
- parent: currentParent,
811
- children: []
812
- });
813
- },
814
- onObjectProperty: (name, offset, length) => {
815
- currentParent = onValue({
816
- type: "property",
817
- offset,
818
- length: -1,
819
- parent: currentParent,
820
- children: []
821
- });
822
- currentParent.children.push({
823
- type: "string",
824
- value: name,
825
- offset,
826
- length,
827
- parent: currentParent
828
- });
829
- },
830
- onObjectEnd: (offset, length) => {
831
- ensurePropertyComplete(offset + length);
832
- currentParent.length = offset + length - currentParent.offset;
833
- currentParent = currentParent.parent;
834
- ensurePropertyComplete(offset + length);
835
- },
836
- onArrayBegin: (offset, length) => {
837
- currentParent = onValue({
838
- type: "array",
839
- offset,
840
- length: -1,
841
- parent: currentParent,
842
- children: []
843
- });
844
- },
845
- onArrayEnd: (offset, length) => {
846
- currentParent.length = offset + length - currentParent.offset;
847
- currentParent = currentParent.parent;
848
- ensurePropertyComplete(offset + length);
849
- },
850
- onLiteralValue: (value, offset, length) => {
851
- onValue({
852
- type: getNodeType(value),
853
- offset,
854
- length,
855
- parent: currentParent,
856
- value
857
- });
858
- ensurePropertyComplete(offset + length);
859
- },
860
- onSeparator: (sep, offset, length) => {
861
- if (currentParent.type === "property") {
862
- if (sep === ":") currentParent.colonOffset = offset;
863
- else if (sep === ",") ensurePropertyComplete(offset);
864
- }
865
- },
866
- onError: (error, offset, length) => {
867
- errors.push({
868
- error,
869
- offset,
870
- length
871
- });
872
- }
873
- }, options);
874
- const result = currentParent.children[0];
875
- if (result) delete result.parent;
876
- return result;
877
- }
878
- /**
879
- * Finds the node at the given path in a JSON DOM.
880
- */
881
- function findNodeAtLocation(root, path) {
882
- if (!root) return;
883
- let node = root;
884
- for (let segment of path) if (typeof segment === "string") {
885
- if (node.type !== "object" || !Array.isArray(node.children)) return;
886
- let found = false;
887
- for (const propertyNode of node.children) if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {
888
- node = propertyNode.children[1];
889
- found = true;
890
- break;
891
- }
892
- if (!found) return;
893
- } else {
894
- const index = segment;
895
- if (node.type !== "array" || index < 0 || !Array.isArray(node.children) || index >= node.children.length) return;
896
- node = node.children[index];
897
- }
898
- return node;
899
- }
900
- /**
901
- * Parses the given text and invokes the visitor functions for each object, array and literal reached.
902
- */
903
- function visit(text, visitor, options = ParseOptions.DEFAULT) {
904
- const _scanner = createScanner(text, false);
905
- const _jsonPath = [];
906
- let suppressedCallbacks = 0;
907
- function toNoArgVisit(visitFunction) {
908
- return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
909
- }
910
- function toOneArgVisit(visitFunction) {
911
- return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
912
- }
913
- function toOneArgVisitWithPath(visitFunction) {
914
- return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
915
- }
916
- function toBeginVisit(visitFunction) {
917
- return visitFunction ? () => {
918
- if (suppressedCallbacks > 0) suppressedCallbacks++;
919
- else if (visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) === false) suppressedCallbacks = 1;
920
- } : () => true;
921
- }
922
- function toEndVisit(visitFunction) {
923
- return visitFunction ? () => {
924
- if (suppressedCallbacks > 0) suppressedCallbacks--;
925
- if (suppressedCallbacks === 0) visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
926
- } : () => true;
927
- }
928
- const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
929
- const disallowComments = options && options.disallowComments;
930
- const allowTrailingComma = options && options.allowTrailingComma;
931
- function scanNext() {
932
- while (true) {
933
- const token = _scanner.scan();
934
- switch (_scanner.getTokenError()) {
935
- case 4:
936
- handleError(14);
937
- break;
938
- case 5:
939
- handleError(15);
940
- break;
941
- case 3:
942
- handleError(13);
943
- break;
944
- case 1:
945
- if (!disallowComments) handleError(11);
946
- break;
947
- case 2:
948
- handleError(12);
949
- break;
950
- case 6: handleError(16);
951
- }
952
- switch (token) {
953
- case 12:
954
- case 13:
955
- if (disallowComments) handleError(10);
956
- else onComment();
957
- break;
958
- case 16:
959
- handleError(1);
960
- break;
961
- case 15:
962
- case 14: break;
963
- default: return token;
964
- }
965
- }
966
- }
967
- function handleError(error, skipUntilAfter = [], skipUntil = []) {
968
- onError(error);
969
- if (skipUntilAfter.length + skipUntil.length > 0) {
970
- let token = _scanner.getToken();
971
- while (token !== 17) {
972
- if (skipUntilAfter.indexOf(token) !== -1) {
973
- scanNext();
974
- break;
975
- } else if (skipUntil.indexOf(token) !== -1) break;
976
- token = scanNext();
977
- }
978
- }
979
- }
980
- function parseString(isValue) {
981
- const value = _scanner.getTokenValue();
982
- if (isValue) onLiteralValue(value);
983
- else {
984
- onObjectProperty(value);
985
- _jsonPath.push(value);
986
- }
987
- scanNext();
988
- return true;
989
- }
990
- function parseLiteral() {
991
- switch (_scanner.getToken()) {
992
- case 11:
993
- const tokenValue = _scanner.getTokenValue();
994
- let value = Number(tokenValue);
995
- if (isNaN(value)) {
996
- handleError(2);
997
- value = 0;
998
- }
999
- onLiteralValue(value);
1000
- break;
1001
- case 7:
1002
- onLiteralValue(null);
1003
- break;
1004
- case 8:
1005
- onLiteralValue(true);
1006
- break;
1007
- case 9:
1008
- onLiteralValue(false);
1009
- break;
1010
- default: return false;
1011
- }
1012
- scanNext();
1013
- return true;
1014
- }
1015
- function parseProperty() {
1016
- if (_scanner.getToken() !== 10) {
1017
- handleError(3, [], [2, 5]);
1018
- return false;
1019
- }
1020
- parseString(false);
1021
- if (_scanner.getToken() === 6) {
1022
- onSeparator(":");
1023
- scanNext();
1024
- if (!parseValue()) handleError(4, [], [2, 5]);
1025
- } else handleError(5, [], [2, 5]);
1026
- _jsonPath.pop();
1027
- return true;
1028
- }
1029
- function parseObject() {
1030
- onObjectBegin();
1031
- scanNext();
1032
- let needsComma = false;
1033
- while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
1034
- if (_scanner.getToken() === 5) {
1035
- if (!needsComma) handleError(4, [], []);
1036
- onSeparator(",");
1037
- scanNext();
1038
- if (_scanner.getToken() === 2 && allowTrailingComma) break;
1039
- } else if (needsComma) handleError(6, [], []);
1040
- if (!parseProperty()) handleError(4, [], [2, 5]);
1041
- needsComma = true;
1042
- }
1043
- onObjectEnd();
1044
- if (_scanner.getToken() !== 2) handleError(7, [2], []);
1045
- else scanNext();
1046
- return true;
1047
- }
1048
- function parseArray() {
1049
- onArrayBegin();
1050
- scanNext();
1051
- let isFirstElement = true;
1052
- let needsComma = false;
1053
- while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
1054
- if (_scanner.getToken() === 5) {
1055
- if (!needsComma) handleError(4, [], []);
1056
- onSeparator(",");
1057
- scanNext();
1058
- if (_scanner.getToken() === 4 && allowTrailingComma) break;
1059
- } else if (needsComma) handleError(6, [], []);
1060
- if (isFirstElement) {
1061
- _jsonPath.push(0);
1062
- isFirstElement = false;
1063
- } else _jsonPath[_jsonPath.length - 1]++;
1064
- if (!parseValue()) handleError(4, [], [4, 5]);
1065
- needsComma = true;
1066
- }
1067
- onArrayEnd();
1068
- if (!isFirstElement) _jsonPath.pop();
1069
- if (_scanner.getToken() !== 4) handleError(8, [4], []);
1070
- else scanNext();
1071
- return true;
1072
- }
1073
- function parseValue() {
1074
- switch (_scanner.getToken()) {
1075
- case 3: return parseArray();
1076
- case 1: return parseObject();
1077
- case 10: return parseString(true);
1078
- default: return parseLiteral();
1079
- }
1080
- }
1081
- scanNext();
1082
- if (_scanner.getToken() === 17) {
1083
- if (options.allowEmptyContent) return true;
1084
- handleError(4, [], []);
1085
- return false;
1086
- }
1087
- if (!parseValue()) {
1088
- handleError(4, [], []);
1089
- return false;
1090
- }
1091
- if (_scanner.getToken() !== 17) handleError(9, [], []);
1092
- return true;
1093
- }
1094
- function getNodeType(value) {
1095
- switch (typeof value) {
1096
- case "boolean": return "boolean";
1097
- case "number": return "number";
1098
- case "string": return "string";
1099
- case "object":
1100
- if (!value) return "null";
1101
- else if (Array.isArray(value)) return "array";
1102
- return "object";
1103
- default: return "null";
1104
- }
1105
- }
1106
- //#endregion
1107
- //#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/edit.js
1108
- function setProperty(text, originalPath, value, options) {
1109
- const path = originalPath.slice();
1110
- const root = parseTree(text, []);
1111
- let parent = void 0;
1112
- let lastSegment = void 0;
1113
- while (path.length > 0) {
1114
- lastSegment = path.pop();
1115
- parent = findNodeAtLocation(root, path);
1116
- if (parent === void 0 && value !== void 0) {
1117
- if (typeof lastSegment === "string") value = { [lastSegment]: value };
1118
- else value = [value];
1119
- } else break;
1120
- }
1121
- if (!parent) {
1122
- if (value === void 0) throw new Error("Can not delete in empty document");
1123
- return withFormatting(text, {
1124
- offset: root ? root.offset : 0,
1125
- length: root ? root.length : 0,
1126
- content: JSON.stringify(value)
1127
- }, options);
1128
- } else if (parent.type === "object" && typeof lastSegment === "string" && Array.isArray(parent.children)) {
1129
- const existing = findNodeAtLocation(parent, [lastSegment]);
1130
- if (existing !== void 0) {
1131
- if (value === void 0) {
1132
- if (!existing.parent) throw new Error("Malformed AST");
1133
- const propertyIndex = parent.children.indexOf(existing.parent);
1134
- let removeBegin;
1135
- let removeEnd = existing.parent.offset + existing.parent.length;
1136
- if (propertyIndex > 0) {
1137
- let previous = parent.children[propertyIndex - 1];
1138
- removeBegin = previous.offset + previous.length;
1139
- } else {
1140
- removeBegin = parent.offset + 1;
1141
- if (parent.children.length > 1) removeEnd = parent.children[1].offset;
1142
- }
1143
- return withFormatting(text, {
1144
- offset: removeBegin,
1145
- length: removeEnd - removeBegin,
1146
- content: ""
1147
- }, options);
1148
- } else return withFormatting(text, {
1149
- offset: existing.offset,
1150
- length: existing.length,
1151
- content: JSON.stringify(value)
1152
- }, options);
1153
- } else {
1154
- if (value === void 0) return [];
1155
- const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
1156
- const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map((p) => p.children[0].value)) : parent.children.length;
1157
- let edit;
1158
- if (index > 0) {
1159
- let previous = parent.children[index - 1];
1160
- edit = {
1161
- offset: previous.offset + previous.length,
1162
- length: 0,
1163
- content: "," + newProperty
1164
- };
1165
- } else if (parent.children.length === 0) edit = {
1166
- offset: parent.offset + 1,
1167
- length: 0,
1168
- content: newProperty
1169
- };
1170
- else edit = {
1171
- offset: parent.offset + 1,
1172
- length: 0,
1173
- content: newProperty + ","
1174
- };
1175
- return withFormatting(text, edit, options);
1176
- }
1177
- } else if (parent.type === "array" && typeof lastSegment === "number" && Array.isArray(parent.children)) {
1178
- const insertIndex = lastSegment;
1179
- if (insertIndex === -1) {
1180
- const newProperty = `${JSON.stringify(value)}`;
1181
- let edit;
1182
- if (parent.children.length === 0) edit = {
1183
- offset: parent.offset + 1,
1184
- length: 0,
1185
- content: newProperty
1186
- };
1187
- else {
1188
- const previous = parent.children[parent.children.length - 1];
1189
- edit = {
1190
- offset: previous.offset + previous.length,
1191
- length: 0,
1192
- content: "," + newProperty
1193
- };
1194
- }
1195
- return withFormatting(text, edit, options);
1196
- } else if (value === void 0 && parent.children.length >= 0) {
1197
- const removalIndex = lastSegment;
1198
- const toRemove = parent.children[removalIndex];
1199
- let edit;
1200
- if (parent.children.length === 1) edit = {
1201
- offset: parent.offset + 1,
1202
- length: parent.length - 2,
1203
- content: ""
1204
- };
1205
- else if (parent.children.length - 1 === removalIndex) {
1206
- let previous = parent.children[removalIndex - 1];
1207
- let offset = previous.offset + previous.length;
1208
- edit = {
1209
- offset,
1210
- length: parent.offset + parent.length - 2 - offset,
1211
- content: ""
1212
- };
1213
- } else edit = {
1214
- offset: toRemove.offset,
1215
- length: parent.children[removalIndex + 1].offset - toRemove.offset,
1216
- content: ""
1217
- };
1218
- return withFormatting(text, edit, options);
1219
- } else if (value !== void 0) {
1220
- let edit;
1221
- const newProperty = `${JSON.stringify(value)}`;
1222
- if (!options.isArrayInsertion && parent.children.length > lastSegment) {
1223
- const toModify = parent.children[lastSegment];
1224
- edit = {
1225
- offset: toModify.offset,
1226
- length: toModify.length,
1227
- content: newProperty
1228
- };
1229
- } else if (parent.children.length === 0 || lastSegment === 0) edit = {
1230
- offset: parent.offset + 1,
1231
- length: 0,
1232
- content: parent.children.length === 0 ? newProperty : newProperty + ","
1233
- };
1234
- else {
1235
- const index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
1236
- const previous = parent.children[index - 1];
1237
- edit = {
1238
- offset: previous.offset + previous.length,
1239
- length: 0,
1240
- content: "," + newProperty
1241
- };
1242
- }
1243
- return withFormatting(text, edit, options);
1244
- } else throw new Error(`Can not ${value === void 0 ? "remove" : options.isArrayInsertion ? "insert" : "modify"} Array index ${insertIndex} as length is not sufficient`);
1245
- } else throw new Error(`Can not add ${typeof lastSegment !== "number" ? "index" : "property"} to parent of type ${parent.type}`);
1246
- }
1247
- function withFormatting(text, edit, options) {
1248
- if (!options.formattingOptions) return [edit];
1249
- let newText = applyEdit(text, edit);
1250
- let begin = edit.offset;
1251
- let end = edit.offset + edit.content.length;
1252
- if (edit.length === 0 || edit.content.length === 0) {
1253
- while (begin > 0 && !isEOL(newText, begin - 1)) begin--;
1254
- while (end < newText.length && !isEOL(newText, end)) end++;
1255
- }
1256
- const edits = format(newText, {
1257
- offset: begin,
1258
- length: end - begin
1259
- }, {
1260
- ...options.formattingOptions,
1261
- keepLines: false
1262
- });
1263
- for (let i = edits.length - 1; i >= 0; i--) {
1264
- const edit = edits[i];
1265
- newText = applyEdit(newText, edit);
1266
- begin = Math.min(begin, edit.offset);
1267
- end = Math.max(end, edit.offset + edit.length);
1268
- end += edit.content.length - edit.length;
1269
- }
1270
- const editLength = text.length - (newText.length - end) - begin;
1271
- return [{
1272
- offset: begin,
1273
- length: editLength,
1274
- content: newText.substring(begin, end)
1275
- }];
1276
- }
1277
- function applyEdit(text, edit) {
1278
- return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
1279
- }
1280
- //#endregion
1281
- //#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js
1282
- var ScanError;
1283
- (function(ScanError) {
1284
- ScanError[ScanError["None"] = 0] = "None";
1285
- ScanError[ScanError["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
1286
- ScanError[ScanError["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
1287
- ScanError[ScanError["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
1288
- ScanError[ScanError["InvalidUnicode"] = 4] = "InvalidUnicode";
1289
- ScanError[ScanError["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
1290
- ScanError[ScanError["InvalidCharacter"] = 6] = "InvalidCharacter";
1291
- })(ScanError || (ScanError = {}));
1292
- var SyntaxKind;
1293
- (function(SyntaxKind) {
1294
- SyntaxKind[SyntaxKind["OpenBraceToken"] = 1] = "OpenBraceToken";
1295
- SyntaxKind[SyntaxKind["CloseBraceToken"] = 2] = "CloseBraceToken";
1296
- SyntaxKind[SyntaxKind["OpenBracketToken"] = 3] = "OpenBracketToken";
1297
- SyntaxKind[SyntaxKind["CloseBracketToken"] = 4] = "CloseBracketToken";
1298
- SyntaxKind[SyntaxKind["CommaToken"] = 5] = "CommaToken";
1299
- SyntaxKind[SyntaxKind["ColonToken"] = 6] = "ColonToken";
1300
- SyntaxKind[SyntaxKind["NullKeyword"] = 7] = "NullKeyword";
1301
- SyntaxKind[SyntaxKind["TrueKeyword"] = 8] = "TrueKeyword";
1302
- SyntaxKind[SyntaxKind["FalseKeyword"] = 9] = "FalseKeyword";
1303
- SyntaxKind[SyntaxKind["StringLiteral"] = 10] = "StringLiteral";
1304
- SyntaxKind[SyntaxKind["NumericLiteral"] = 11] = "NumericLiteral";
1305
- SyntaxKind[SyntaxKind["LineCommentTrivia"] = 12] = "LineCommentTrivia";
1306
- SyntaxKind[SyntaxKind["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
1307
- SyntaxKind[SyntaxKind["LineBreakTrivia"] = 14] = "LineBreakTrivia";
1308
- SyntaxKind[SyntaxKind["Trivia"] = 15] = "Trivia";
1309
- SyntaxKind[SyntaxKind["Unknown"] = 16] = "Unknown";
1310
- SyntaxKind[SyntaxKind["EOF"] = 17] = "EOF";
1311
- })(SyntaxKind || (SyntaxKind = {}));
1312
- /**
1313
- * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
1314
- * Therefore, always check the errors list to find out if the input was valid.
1315
- */
1316
- const parse = parse$1;
1317
- var ParseErrorCode;
1318
- (function(ParseErrorCode) {
1319
- ParseErrorCode[ParseErrorCode["InvalidSymbol"] = 1] = "InvalidSymbol";
1320
- ParseErrorCode[ParseErrorCode["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
1321
- ParseErrorCode[ParseErrorCode["PropertyNameExpected"] = 3] = "PropertyNameExpected";
1322
- ParseErrorCode[ParseErrorCode["ValueExpected"] = 4] = "ValueExpected";
1323
- ParseErrorCode[ParseErrorCode["ColonExpected"] = 5] = "ColonExpected";
1324
- ParseErrorCode[ParseErrorCode["CommaExpected"] = 6] = "CommaExpected";
1325
- ParseErrorCode[ParseErrorCode["CloseBraceExpected"] = 7] = "CloseBraceExpected";
1326
- ParseErrorCode[ParseErrorCode["CloseBracketExpected"] = 8] = "CloseBracketExpected";
1327
- ParseErrorCode[ParseErrorCode["EndOfFileExpected"] = 9] = "EndOfFileExpected";
1328
- ParseErrorCode[ParseErrorCode["InvalidCommentToken"] = 10] = "InvalidCommentToken";
1329
- ParseErrorCode[ParseErrorCode["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
1330
- ParseErrorCode[ParseErrorCode["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
1331
- ParseErrorCode[ParseErrorCode["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
1332
- ParseErrorCode[ParseErrorCode["InvalidUnicode"] = 14] = "InvalidUnicode";
1333
- ParseErrorCode[ParseErrorCode["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
1334
- ParseErrorCode[ParseErrorCode["InvalidCharacter"] = 16] = "InvalidCharacter";
1335
- })(ParseErrorCode || (ParseErrorCode = {}));
1336
- function printParseErrorCode(code) {
1337
- switch (code) {
1338
- case 1: return "InvalidSymbol";
1339
- case 2: return "InvalidNumberFormat";
1340
- case 3: return "PropertyNameExpected";
1341
- case 4: return "ValueExpected";
1342
- case 5: return "ColonExpected";
1343
- case 6: return "CommaExpected";
1344
- case 7: return "CloseBraceExpected";
1345
- case 8: return "CloseBracketExpected";
1346
- case 9: return "EndOfFileExpected";
1347
- case 10: return "InvalidCommentToken";
1348
- case 11: return "UnexpectedEndOfComment";
1349
- case 12: return "UnexpectedEndOfString";
1350
- case 13: return "UnexpectedEndOfNumber";
1351
- case 14: return "InvalidUnicode";
1352
- case 15: return "InvalidEscapeCharacter";
1353
- case 16: return "InvalidCharacter";
1354
- }
1355
- return "<unknown ParseErrorCode>";
1356
- }
1357
- /**
1358
- * Computes the edit operations needed to modify a value in the JSON document.
1359
- *
1360
- * @param documentText The input text
1361
- * @param path The path of the value to change. The path represents either to the document root, a property or an array item.
1362
- * If the path points to an non-existing property or item, it will be created.
1363
- * @param value The new value for the specified property or item. If the value is undefined,
1364
- * the property or item will be removed.
1365
- * @param options Options
1366
- * @returns The edit operations describing the changes to the original document, following the format described in {@linkcode EditResult}.
1367
- * To apply the edit operations to the input, use {@linkcode applyEdits}.
1368
- */
1369
- function modify(text, path, value, options) {
1370
- return setProperty(text, path, value, options);
1371
- }
1372
- /**
1373
- * Applies edits to an input string.
1374
- * @param text The input text
1375
- * @param edits Edit operations following the format described in {@linkcode EditResult}.
1376
- * @returns The text with the applied edits.
1377
- * @throws An error if the edit operations are not well-formed as described in {@linkcode EditResult}.
1378
- */
1379
- function applyEdits(text, edits) {
1380
- let sortedEdits = edits.slice(0).sort((a, b) => {
1381
- const diff = a.offset - b.offset;
1382
- if (diff === 0) return a.length - b.length;
1383
- return diff;
1384
- });
1385
- let lastModifiedOffset = text.length;
1386
- for (let i = sortedEdits.length - 1; i >= 0; i--) {
1387
- let e = sortedEdits[i];
1388
- if (e.offset + e.length <= lastModifiedOffset) text = applyEdit(text, e);
1389
- else throw new Error("Overlapping edit");
1390
- lastModifiedOffset = e.offset;
1391
- }
1392
- return text;
1393
- }
1394
- //#endregion
1395
- //#region src/deployment.ts
1396
- /** What a directory holds: a deployment of either kind, nothing yet (`isEmpty`), or something else. */
1397
- function deploymentKind(dir) {
1398
- if (isEmpty(dir)) return "empty";
1399
- if (existsSync(join(dir, "app", "wrangler.jsonc")) && existsSync(join(dir, "vault", "wrangler.jsonc"))) return "workers";
1400
- if (existsSync(join(dir, "src", "vault.ts")) && existsSync(join(dir, "vault.env.example"))) return "node";
1401
- return "other";
1402
- }
1403
- /** Install a new deployment's packages, as its README says: pnpm, through corepack when pnpm itself is missing. */
1404
- function install(dir) {
1405
- const attempt = (command, args) => new Promise((resolve) => {
1406
- const child = spawn(command, args, {
1407
- cwd: dir,
1408
- stdio: [
1409
- "ignore",
1410
- "pipe",
1411
- "pipe"
1412
- ],
1413
- env: {
1414
- ...process.env,
1415
- COREPACK_ENABLE_DOWNLOAD_PROMPT: "0"
1416
- }
1417
- });
1418
- let output = "";
1419
- child.stdout.setEncoding("utf8").on("data", (chunk) => output += chunk);
1420
- child.stderr.setEncoding("utf8").on("data", (chunk) => output += chunk);
1421
- child.on("error", () => resolve(null));
1422
- child.on("close", (code) => resolve({
1423
- code,
1424
- output
1425
- }));
1426
- });
1427
- return (async () => {
1428
- const ran = await attempt("pnpm", ["install"]) ?? await attempt("corepack", ["pnpm", "install"]);
1429
- if (ran === null) throw new Error("pnpm is not installed: corepack enable, or npm install -g pnpm, then run setup again");
1430
- if (ran.code !== 0) {
1431
- const tail = ran.output.trim().split("\n").slice(-3).join(" ");
1432
- throw new Error(`pnpm install failed: ${tail}`);
1433
- }
1434
- })();
1435
- }
1436
- /** A value the examples ship, standing for the operator's own. */
1437
- function placeholder(value) {
1438
- return value === void 0 || value === null || value === "" || /^replace-with-|example\.com\b/.test(value);
1439
- }
1440
- function readWorker(dir, path) {
1441
- const errors = [];
1442
- const config = parse(readFileSync(join(dir, path), "utf8"), errors, { allowTrailingComma: true });
1443
- if (errors.length > 0) throw new Error(`${path} is not valid: ${printParseErrorCode(errors[0].error)} at offset ${errors[0].offset}`);
1444
- if (typeof config.name !== "string") throw new Error(`${path} names no Worker`);
1445
- const route = config.routes?.[0];
1446
- return {
1447
- path,
1448
- name: config.name,
1449
- accountId: config.account_id ?? null,
1450
- vars: Object.fromEntries(Object.entries(config.vars ?? {}).filter((entry) => typeof entry[1] === "string")),
1451
- hyperdrive: placeholder(config.hyperdrive?.[0]?.id) ? null : config.hyperdrive[0].id,
1452
- route: typeof route === "string" ? route : route?.pattern ?? null
1453
- };
1454
- }
1455
- /** A value as the examples write one on a single line: `[{ "pattern": "…", "custom_domain": true }]`. */
1456
- function inline(value) {
1457
- return JSON.stringify(value, null, 1).replace(/\n\s*/g, " ").replace(/\[ /g, "[").replace(/ \]/g, "]");
1458
- }
1459
- /** Make `changes` to the file at `path`, leaving the rest as it is, comments and all. Says which changed anything. */
1460
- function editWorker(dir, path, changes) {
1461
- const MARK = "\0coffre\0";
1462
- let text = readFileSync(join(dir, path), "utf8");
1463
- const changed = changes.map((change) => {
1464
- const edits = modify(text, change.path, MARK, {
1465
- formattingOptions: {
1466
- insertSpaces: true,
1467
- tabSize: 2,
1468
- eol: "\n"
1469
- },
1470
- getInsertionIndex: change.after === void 0 ? void 0 : (properties) => properties.indexOf(change.after) + 1
1471
- });
1472
- const before = text;
1473
- text = applyEdits(text, edits.map((edit) => ({
1474
- ...edit,
1475
- content: edit.content.replace(JSON.stringify(MARK), inline(change.value))
1476
- })));
1477
- return text !== before;
1478
- });
1479
- writeFileSync(join(dir, path), text);
1480
- return changed;
1481
- }
1482
- //#endregion
1483
- //#region src/steps.ts
1484
- const SPINNER = [
1485
- "⠋",
1486
- "⠙",
1487
- "⠹",
1488
- "⠸",
1489
- "⠼",
1490
- "⠴",
1491
- "⠦",
1492
- "⠧",
1493
- "⠇",
1494
- "⠏"
1495
- ];
1496
- const FRAME_MS = 80;
1497
- /** A step failed, and its line says why: nothing more to show. */
1498
- var StepFailed = class extends Error {};
1499
- var Steps = class {
1500
- #out;
1501
- #s;
1502
- #steps;
1503
- #keys;
1504
- #describe;
1505
- #frame = 0;
1506
- #drawn = 0;
1507
- /** The first step still redrawn: those above it have settled, and been printed for good. */
1508
- #from = 0;
1509
- #timer = null;
1510
- #restoreCursor = () => this.#out.write("\x1B[?25h");
1511
- /** Ctrl-C while a step runs, the terminal in its usual mode: the cursor back, then out, with nothing more to show. */
1512
- #interrupt = () => {
1513
- this.#stop();
1514
- this.end();
1515
- this.#out.write("\n");
1516
- process.exit(130);
1517
- };
1518
- /**
1519
- * `titles`, what each step does while it runs; `keys`, the keyboard for
1520
- * questions; `describe`, an error as it may be shown, a secret it quotes
1521
- * taken out.
1522
- */
1523
- constructor(out, titles, keys, describe) {
1524
- this.#out = out;
1525
- this.#s = style(out);
1526
- this.#keys = keys;
1527
- this.#describe = describe;
1528
- this.#steps = titles.map((text) => ({
1529
- text,
1530
- status: "pending",
1531
- details: [],
1532
- under: [],
1533
- input: null,
1534
- choice: null
1535
- }));
1536
- if (this.#s.ansi) {
1537
- out.write("\x1B[?25l");
1538
- process.once("exit", this.#restoreCursor);
1539
- process.on("SIGINT", this.#interrupt);
1540
- this.#draw();
1541
- }
1542
- }
1543
- /**
1544
- * Run step `i`: its line is the outcome `work` returns, or the error it
1545
- * throws, which comes out as StepFailed, unless it is Cancelled.
1546
- */
1547
- async run(i, work) {
1548
- const state = this.#steps[i];
1549
- state.status = "running";
1550
- this.#tick();
1551
- const step = {
1552
- note: (text) => {
1553
- state.text = text;
1554
- this.#draw();
1555
- },
1556
- under: (lines) => {
1557
- state.under = lines;
1558
- this.#draw();
1559
- },
1560
- ask: (question) => this.#ask(state, question),
1561
- choose: (question, options) => this.#choose(state, question, options),
1562
- paste: (prompt, accept, signal) => this.#paste(state, prompt, accept, signal)
1563
- };
1564
- try {
1565
- const outcome = await work(step);
1566
- Object.assign(state, typeof outcome === "string" ? {
1567
- text: outcome,
1568
- details: []
1569
- } : outcome, {
1570
- status: "done",
1571
- under: [],
1572
- input: null
1573
- });
1574
- } catch (error) {
1575
- Object.assign(state, {
1576
- under: [],
1577
- input: null,
1578
- choice: null
1579
- });
1580
- state.status = "failed";
1581
- state.details = error instanceof Cancelled ? [] : [this.#describe(error)];
1582
- if (error instanceof Cancelled) state.text = `${state.text}: cancelled`;
1583
- this.#stop();
1584
- throw error instanceof Cancelled ? error : new StepFailed(state.details[0]);
1585
- }
1586
- this.#stop();
1587
- if (!this.#s.ansi) this.#out.write(`✓ ${state.text}\n${state.details.map((line) => ` ${line}\n`).join("")}`);
1588
- else if (this.#steps.every((each) => each.status === "done")) this.end();
1589
- }
1590
- /**
1591
- * Lines that stay, such as an address to open, printed whole, so that a
1592
- * terminal can wrap them, and they can be copied or clicked. They go
1593
- * under the steps done, above the one running: those done are printed
1594
- * for good first, and only the rest is redrawn from then on.
1595
- */
1596
- print(text) {
1597
- if (!this.#s.ansi) {
1598
- this.#out.write(`${text}\n`);
1599
- return;
1600
- }
1601
- const running = this.#steps.findIndex((each, i) => i >= this.#from && each.status !== "done");
1602
- const settled = this.#lines(this.#from, running === -1 ? this.#steps.length : running);
1603
- this.#from = running === -1 ? this.#steps.length : running;
1604
- const up = this.#drawn > 0 ? `\x1b[${this.#drawn}F` : "";
1605
- this.#out.write(`${up}\x1b[J${settled.map((line) => `${line}\n`).join("")}${text}\n`);
1606
- this.#drawn = 0;
1607
- this.#draw();
1608
- }
1609
- /** A remark that stays, dim, wrapped to the terminal's width. */
1610
- aside(text) {
1611
- this.print(this.#s.dim(wrap(text, Math.max(20, (this.#out.columns ?? 80) - 3)).map((line) => ` ${line}`).join("\n")));
1612
- }
1613
- /**
1614
- * An address to open, after what it is for: on one line when both fit;
1615
- * otherwise the address on a line of its own, from the first column, so
1616
- * that the terminal wraps it in one piece, to copy whole.
1617
- */
1618
- link(label, address) {
1619
- const fits = width(` ${label} ${address}`) < (this.#out.columns ?? 80);
1620
- this.print(fits ? ` ${this.#s.dim(label)} ${address}` : ` ${this.#s.dim(label)}\n${address}`);
1621
- }
1622
- /** Leave the list as it stands, the cursor below it. */
1623
- end() {
1624
- this.#stop();
1625
- this.#release();
1626
- }
1627
- /** The cursor back, and Ctrl-C the terminal's again. */
1628
- #release() {
1629
- if (this.#s.ansi) {
1630
- this.#restoreCursor();
1631
- process.off("exit", this.#restoreCursor);
1632
- process.off("SIGINT", this.#interrupt);
1633
- }
1634
- }
1635
- async #ask(state, question) {
1636
- const keys = this.#keys();
1637
- if (keys === null) return false;
1638
- this.#stop();
1639
- const before = state.text;
1640
- state.text = `${question} ${this.#s.dim("y/N")}`;
1641
- state.status = "asking";
1642
- this.#draw();
1643
- try {
1644
- return await yes(keys);
1645
- } finally {
1646
- state.text = before;
1647
- state.status = "running";
1648
- this.#tick();
1649
- }
1650
- }
1651
- async #choose(state, question, options) {
1652
- const keys = this.#keys();
1653
- if (keys === null) return 0;
1654
- this.#stop();
1655
- const before = state.text;
1656
- Object.assign(state, {
1657
- text: `${question} ${this.#s.dim("↑↓ then Enter")}`,
1658
- status: "asking",
1659
- choice: {
1660
- options,
1661
- at: 0
1662
- }
1663
- });
1664
- let cancelled = false;
1665
- try {
1666
- const chosen = readKeys(keys, (key) => {
1667
- const choice = state.choice;
1668
- if (key.ctrl && key.name === "c") cancelled = true;
1669
- else if (key.name === "return" || key.name === "enter") return true;
1670
- else if (key.name === "up" || key.name === "k") choice.at = (choice.at - 1 + options.length) % options.length;
1671
- else if (key.name === "down" || key.name === "j" || key.name === "tab") choice.at = (choice.at + 1) % options.length;
1672
- if (cancelled) return true;
1673
- this.#draw();
1674
- return false;
1675
- });
1676
- this.#draw();
1677
- await chosen;
1678
- if (cancelled) throw new Cancelled();
1679
- return state.choice.at;
1680
- } finally {
1681
- Object.assign(state, {
1682
- text: before,
1683
- status: "running",
1684
- choice: null
1685
- });
1686
- this.#tick();
1687
- }
1688
- }
1689
- async #paste(state, prompt, accept, signal) {
1690
- const keys = this.#keys();
1691
- if (keys === null) {
1692
- await new Promise((resolve) => signal.aborted ? resolve() : signal.addEventListener("abort", () => resolve()));
1693
- return null;
1694
- }
1695
- state.input = {
1696
- prompt,
1697
- typed: "",
1698
- error: null
1699
- };
1700
- let taken = null;
1701
- let cancelled = false;
1702
- try {
1703
- const pasted = readKeys(keys, async (key, sequence) => {
1704
- const input = state.input;
1705
- const next = edit(input.typed, key, sequence);
1706
- if (next === "cancel") cancelled = true;
1707
- else if (next === "submit" && input.typed.trim() !== "") {
1708
- const text = input.typed.trim();
1709
- input.typed = "";
1710
- input.error = await accept(text);
1711
- if (input.error === null) taken = text;
1712
- } else if (next !== "submit") {
1713
- input.typed = next;
1714
- input.error = null;
1715
- }
1716
- this.#draw();
1717
- return cancelled || taken !== null;
1718
- }, signal);
1719
- this.#draw();
1720
- await pasted;
1721
- } finally {
1722
- state.input = null;
1723
- this.#draw();
1724
- }
1725
- if (cancelled) throw new Cancelled();
1726
- return taken;
1727
- }
1728
- #tick() {
1729
- this.#draw();
1730
- if (this.#s.ansi && this.#timer === null) this.#timer = setInterval(() => {
1731
- this.#frame = (this.#frame + 1) % SPINNER.length;
1732
- this.#draw();
1733
- }, FRAME_MS).unref();
1734
- }
1735
- #stop() {
1736
- if (this.#timer !== null) clearInterval(this.#timer);
1737
- this.#timer = null;
1738
- this.#draw();
1739
- if (!this.#s.ansi) {
1740
- const failed = this.#steps.find((each) => each.status === "failed");
1741
- if (failed !== void 0) this.#out.write(`✗ ${failed.text}\n${failed.details.map((line) => ` ${line}\n`).join("")}`);
1742
- } else if (this.#steps.some((each) => each.status === "failed")) this.#release();
1743
- }
1744
- #draw() {
1745
- if (!this.#s.ansi) return;
1746
- const lines = this.#lines(this.#from, this.#steps.length);
1747
- const up = this.#drawn > 0 ? `\x1b[${this.#drawn}F` : "";
1748
- this.#out.write(`${up}${lines.map((line) => `${line}\x1b[K\n`).join("")}\x1b[J`);
1749
- this.#drawn = lines.length;
1750
- }
1751
- /** Steps `from` to `to`, as lines cut to the terminal's width. */
1752
- #lines(from, to) {
1753
- const s = this.#s;
1754
- const columns = Math.max(20, (this.#out.columns ?? 80) - 1);
1755
- return this.#steps.slice(from, to).flatMap(({ text, status, details, under, input, choice }) => {
1756
- const icon = {
1757
- pending: s.dim("·"),
1758
- running: s.accent(SPINNER[this.#frame]),
1759
- asking: s.accent("?"),
1760
- done: s.green("✓"),
1761
- failed: s.red("✗")
1762
- }[status];
1763
- const line = status === "pending" ? s.dim(text) : status === "failed" ? s.red(text) : text;
1764
- const below = status === "failed" ? details.flatMap((detail) => wrap(detail, columns - 4)) : details.map(s.dim);
1765
- const live = [
1766
- ...under.map((text) => ` ${s.dim(text)}`),
1767
- ...choice === null ? [] : choice.options.map((option, i) => i === choice.at ? ` ${s.accent("›")} ${s.accent(option)}` : ` ${option}`),
1768
- ...input === null ? [] : [
1769
- ` ${input.prompt}`,
1770
- ` ${s.accent("›")} ${"•".repeat(input.typed.length)}`,
1771
- ...input.error === null ? [] : [` ${s.red(input.error)}`]
1772
- ]
1773
- ];
1774
- return [
1775
- ` ${icon} ${line}`,
1776
- ...below.map((detail) => ` ${detail}`),
1777
- ...live
1778
- ];
1779
- }).map((line) => truncate(line, columns));
1780
- }
1781
- };
1782
- //#endregion
1783
15
  //#region src/browser.ts
1784
16
  /** Open `url` in this machine's browser, if it has one. Silent either way. */
1785
17
  function openBrowser(url, platform = process.platform) {
@@ -2876,10 +1108,13 @@ async function setup(args) {
2876
1108
  const about = offers && (kind === "workers" || kind === "empty") ? "a deployment's database, keys and Cloudflare" : "a deployment's database logins, migrations and keys";
2877
1109
  if (s.ansi) out.write(`\n ${s.bold("coffre setup")} ${s.dim(about)}\n\n`);
2878
1110
  if (kind === "empty" && terminal !== null) kind = await scaffold(dir, terminal.keys, out, clean);
2879
- const text = await readAdministrator(out, s);
2880
- secrets.push(text);
2881
- const administrator = administratorUrl(text);
2882
- if (administrator.password !== "") secrets.push(administrator.password, decodeURIComponent(administrator.password));
1111
+ const { url: administrator, secrets: typed } = await readDatabaseUrl(out, s, {
1112
+ variable: URL_VARIABLE,
1113
+ question: "The database administrator's connection string",
1114
+ hint: "Hidden as you type. Your host's admin URL, such as PlanetScale's Connect page gives.",
1115
+ command: "coffre setup"
1116
+ });
1117
+ secrets.push(...typed);
2883
1118
  let cloudflare = null;
2884
1119
  if (offers && kind === "workers") {
2885
1120
  if (await select(terminal.keys, out, s, "Set Cloudflare up too?", ["Yes: Hyperdrive, GitHub sign-in, the keys as secrets, and the deploy", "No, I'll do Cloudflare myself"]) === 0) cloudflare = await Cloudflare.connect(dir, out, terminal.keys, clean, secrets, administrator);
@@ -2939,35 +1174,6 @@ function parseOptions(args) {
2939
1174
  throw new SetupError(`coffre setup takes only --reset-passwords and --json. It reads the administrator's connection string from a hidden prompt, ${URL_VARIABLE} or stdin, never from the command line, where the shell's history and other users can read it.` + (leaked ? " One of the arguments looks like one: change that password, which is in your shell history now." : ""));
2940
1175
  }
2941
1176
  }
2942
- /** The connection string: from the environment, from stdin when it is piped, or typed at a hidden prompt. */
2943
- async function readAdministrator(out, s) {
2944
- const given = process.env[URL_VARIABLE];
2945
- delete process.env[URL_VARIABLE];
2946
- if (given !== void 0 && given.trim() !== "") return given.trim();
2947
- if (!process.stdin.isTTY) {
2948
- const line = readFileSync(0, "utf8").split("\n").find((candidate) => candidate.trim() !== "");
2949
- if (line === void 0) throw new SetupError(`no connection string: pipe it to stdin, or set ${URL_VARIABLE}`);
2950
- return line.trim();
2951
- }
2952
- const text = await hiddenLine(process.stdin, out, s, "The database administrator's connection string", "Hidden as you type. Your host's admin URL, such as PlanetScale's Connect page gives.");
2953
- if (text === "") throw new SetupError("no connection string given");
2954
- return text;
2955
- }
2956
- function administratorUrl(text) {
2957
- let url;
2958
- try {
2959
- url = new URL(text);
2960
- } catch {
2961
- throw new SetupError("that is not a connection string, such as postgresql://user:password@host:5432/database");
2962
- }
2963
- if (url.protocol !== "postgres:" && url.protocol !== "postgresql:") throw new SetupError("coffre setup needs a Postgres connection string, postgresql://…");
2964
- if (url.username === "" || url.hostname === "" || url.pathname.length <= 1) throw new SetupError("the connection string must name a user, a host and a database");
2965
- return url;
2966
- }
2967
- /** This CLI's version: the schema it migrates to, and the version of coffre a deployment it makes runs. */
2968
- function cliVersion() {
2969
- return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
2970
- }
2971
1177
  /**
2972
1178
  * In an empty directory, a deployment of the kind chosen, its files written
2973
1179
  * as `coffre init` writes them and its packages installed; or none.
@@ -3043,7 +1249,8 @@ async function run(administrator, out, questions, options, secrets, clean) {
3043
1249
  await step(3, async (progress) => {
3044
1250
  let plan = {
3045
1251
  applied: 0,
3046
- total: 0
1252
+ total: 0,
1253
+ pending: []
3047
1254
  };
3048
1255
  await migrateDatabase(administrator.href, (planned) => {
3049
1256
  plan = planned;