@hot-updater/cloudflare 0.35.8 → 0.35.9

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.
@@ -50,306 +50,10 @@ let node_fs = require("node:fs");
50
50
  let node_stream_promises = require("node:stream/promises");
51
51
  let node_stream = require("node:stream");
52
52
  let node_buffer = require("node:buffer");
53
+ let cloudflare_error = require("cloudflare/error");
53
54
  let os = require("os");
54
55
  os = __toESM(os);
55
- //#endregion
56
56
  //#region ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
57
- var import_dayjs_min = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
58
- (function(t, e) {
59
- "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
60
- })(exports, (function() {
61
- "use strict";
62
- var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = {
63
- name: "en",
64
- weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
65
- months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
66
- ordinal: function(t) {
67
- var e = [
68
- "th",
69
- "st",
70
- "nd",
71
- "rd"
72
- ], n = t % 100;
73
- return "[" + t + (e[(n - 20) % 10] || e[n] || e[0]) + "]";
74
- }
75
- }, m = function(t, e, n) {
76
- var r = String(t);
77
- return !r || r.length >= e ? t : "" + Array(e + 1 - r.length).join(n) + t;
78
- }, v = {
79
- s: m,
80
- z: function(t) {
81
- var e = -t.utcOffset(), n = Math.abs(e), r = Math.floor(n / 60), i = n % 60;
82
- return (e <= 0 ? "+" : "-") + m(r, 2, "0") + ":" + m(i, 2, "0");
83
- },
84
- m: function t(e, n) {
85
- if (e.date() < n.date()) return -t(n, e);
86
- var r = 12 * (n.year() - e.year()) + (n.month() - e.month()), i = e.clone().add(r, c), s = n - i < 0, u = e.clone().add(r + (s ? -1 : 1), c);
87
- return +(-(r + (n - i) / (s ? i - u : u - i)) || 0);
88
- },
89
- a: function(t) {
90
- return t < 0 ? Math.ceil(t) || 0 : Math.floor(t);
91
- },
92
- p: function(t) {
93
- return {
94
- M: c,
95
- y: h,
96
- w: o,
97
- d: a,
98
- D: d,
99
- h: u,
100
- m: s,
101
- s: i,
102
- ms: r,
103
- Q: f
104
- }[t] || String(t || "").toLowerCase().replace(/s$/, "");
105
- },
106
- u: function(t) {
107
- return void 0 === t;
108
- }
109
- }, g = "en", D = {};
110
- D[g] = M;
111
- var p = "$isDayjsObject", S = function(t) {
112
- return t instanceof _ || !(!t || !t[p]);
113
- }, w = function t(e, n, r) {
114
- var i;
115
- if (!e) return g;
116
- if ("string" == typeof e) {
117
- var s = e.toLowerCase();
118
- D[s] && (i = s), n && (D[s] = n, i = s);
119
- var u = e.split("-");
120
- if (!i && u.length > 1) return t(u[0]);
121
- } else {
122
- var a = e.name;
123
- D[a] = e, i = a;
124
- }
125
- return !r && i && (g = i), i || !r && g;
126
- }, O = function(t, e) {
127
- if (S(t)) return t.clone();
128
- var n = "object" == typeof e ? e : {};
129
- return n.date = t, n.args = arguments, new _(n);
130
- }, b = v;
131
- b.l = w, b.i = S, b.w = function(t, e) {
132
- return O(t, {
133
- locale: e.$L,
134
- utc: e.$u,
135
- x: e.$x,
136
- $offset: e.$offset
137
- });
138
- };
139
- var _ = function() {
140
- function M(t) {
141
- this.$L = w(t.locale, null, !0), this.parse(t), this.$x = this.$x || t.x || {}, this[p] = !0;
142
- }
143
- var m = M.prototype;
144
- return m.parse = function(t) {
145
- this.$d = function(t) {
146
- var e = t.date, n = t.utc;
147
- if (null === e) return /* @__PURE__ */ new Date(NaN);
148
- if (b.u(e)) return /* @__PURE__ */ new Date();
149
- if (e instanceof Date) return new Date(e);
150
- if ("string" == typeof e && !/Z$/i.test(e)) {
151
- var r = e.match($);
152
- if (r) {
153
- var i = r[2] - 1 || 0, s = (r[7] || "0").substring(0, 3);
154
- return n ? new Date(Date.UTC(r[1], i, r[3] || 1, r[4] || 0, r[5] || 0, r[6] || 0, s)) : new Date(r[1], i, r[3] || 1, r[4] || 0, r[5] || 0, r[6] || 0, s);
155
- }
156
- }
157
- return new Date(e);
158
- }(t), this.init();
159
- }, m.init = function() {
160
- var t = this.$d;
161
- this.$y = t.getFullYear(), this.$M = t.getMonth(), this.$D = t.getDate(), this.$W = t.getDay(), this.$H = t.getHours(), this.$m = t.getMinutes(), this.$s = t.getSeconds(), this.$ms = t.getMilliseconds();
162
- }, m.$utils = function() {
163
- return b;
164
- }, m.isValid = function() {
165
- return !(this.$d.toString() === l);
166
- }, m.isSame = function(t, e) {
167
- var n = O(t);
168
- return this.startOf(e) <= n && n <= this.endOf(e);
169
- }, m.isAfter = function(t, e) {
170
- return O(t) < this.startOf(e);
171
- }, m.isBefore = function(t, e) {
172
- return this.endOf(e) < O(t);
173
- }, m.$g = function(t, e, n) {
174
- return b.u(t) ? this[e] : this.set(n, t);
175
- }, m.unix = function() {
176
- return Math.floor(this.valueOf() / 1e3);
177
- }, m.valueOf = function() {
178
- return this.$d.getTime();
179
- }, m.startOf = function(t, e) {
180
- var n = this, r = !!b.u(e) || e, f = b.p(t), l = function(t, e) {
181
- var i = b.w(n.$u ? Date.UTC(n.$y, e, t) : new Date(n.$y, e, t), n);
182
- return r ? i : i.endOf(a);
183
- }, $ = function(t, e) {
184
- return b.w(n.toDate()[t].apply(n.toDate("s"), (r ? [
185
- 0,
186
- 0,
187
- 0,
188
- 0
189
- ] : [
190
- 23,
191
- 59,
192
- 59,
193
- 999
194
- ]).slice(e)), n);
195
- }, y = this.$W, M = this.$M, m = this.$D, v = "set" + (this.$u ? "UTC" : "");
196
- switch (f) {
197
- case h: return r ? l(1, 0) : l(31, 11);
198
- case c: return r ? l(1, M) : l(0, M + 1);
199
- case o:
200
- var g = this.$locale().weekStart || 0, D = (y < g ? y + 7 : y) - g;
201
- return l(r ? m - D : m + (6 - D), M);
202
- case a:
203
- case d: return $(v + "Hours", 0);
204
- case u: return $(v + "Minutes", 1);
205
- case s: return $(v + "Seconds", 2);
206
- case i: return $(v + "Milliseconds", 3);
207
- default: return this.clone();
208
- }
209
- }, m.endOf = function(t) {
210
- return this.startOf(t, !1);
211
- }, m.$set = function(t, e) {
212
- var n, o = b.p(t), f = "set" + (this.$u ? "UTC" : ""), l = (n = {}, n[a] = f + "Date", n[d] = f + "Date", n[c] = f + "Month", n[h] = f + "FullYear", n[u] = f + "Hours", n[s] = f + "Minutes", n[i] = f + "Seconds", n[r] = f + "Milliseconds", n)[o], $ = o === a ? this.$D + (e - this.$W) : e;
213
- if (o === c || o === h) {
214
- var y = this.clone().set(d, 1);
215
- y.$d[l]($), y.init(), this.$d = y.set(d, Math.min(this.$D, y.daysInMonth())).$d;
216
- } else l && this.$d[l]($);
217
- return this.init(), this;
218
- }, m.set = function(t, e) {
219
- return this.clone().$set(t, e);
220
- }, m.get = function(t) {
221
- return this[b.p(t)]();
222
- }, m.add = function(r, f) {
223
- var d, l = this;
224
- r = Number(r);
225
- var $ = b.p(f), y = function(t) {
226
- var e = O(l);
227
- return b.w(e.date(e.date() + Math.round(t * r)), l);
228
- };
229
- if ($ === c) return this.set(c, this.$M + r);
230
- if ($ === h) return this.set(h, this.$y + r);
231
- if ($ === a) return y(1);
232
- if ($ === o) return y(7);
233
- var M = (d = {}, d[s] = e, d[u] = n, d[i] = t, d)[$] || 1, m = this.$d.getTime() + r * M;
234
- return b.w(m, this);
235
- }, m.subtract = function(t, e) {
236
- return this.add(-1 * t, e);
237
- }, m.format = function(t) {
238
- var e = this, n = this.$locale();
239
- if (!this.isValid()) return n.invalidDate || l;
240
- var r = t || "YYYY-MM-DDTHH:mm:ssZ", i = b.z(this), s = this.$H, u = this.$m, a = this.$M, o = n.weekdays, c = n.months, f = n.meridiem, h = function(t, n, i, s) {
241
- return t && (t[n] || t(e, r)) || i[n].slice(0, s);
242
- }, d = function(t) {
243
- return b.s(s % 12 || 12, t, "0");
244
- }, $ = f || function(t, e, n) {
245
- var r = t < 12 ? "AM" : "PM";
246
- return n ? r.toLowerCase() : r;
247
- };
248
- return r.replace(y, (function(t, r) {
249
- return r || function(t) {
250
- switch (t) {
251
- case "YY": return String(e.$y).slice(-2);
252
- case "YYYY": return b.s(e.$y, 4, "0");
253
- case "M": return a + 1;
254
- case "MM": return b.s(a + 1, 2, "0");
255
- case "MMM": return h(n.monthsShort, a, c, 3);
256
- case "MMMM": return h(c, a);
257
- case "D": return e.$D;
258
- case "DD": return b.s(e.$D, 2, "0");
259
- case "d": return String(e.$W);
260
- case "dd": return h(n.weekdaysMin, e.$W, o, 2);
261
- case "ddd": return h(n.weekdaysShort, e.$W, o, 3);
262
- case "dddd": return o[e.$W];
263
- case "H": return String(s);
264
- case "HH": return b.s(s, 2, "0");
265
- case "h": return d(1);
266
- case "hh": return d(2);
267
- case "a": return $(s, u, !0);
268
- case "A": return $(s, u, !1);
269
- case "m": return String(u);
270
- case "mm": return b.s(u, 2, "0");
271
- case "s": return String(e.$s);
272
- case "ss": return b.s(e.$s, 2, "0");
273
- case "SSS": return b.s(e.$ms, 3, "0");
274
- case "Z": return i;
275
- }
276
- return null;
277
- }(t) || i.replace(":", "");
278
- }));
279
- }, m.utcOffset = function() {
280
- return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
281
- }, m.diff = function(r, d, l) {
282
- var $, y = this, M = b.p(d), m = O(r), v = (m.utcOffset() - this.utcOffset()) * e, g = this - m, D = function() {
283
- return b.m(y, m);
284
- };
285
- switch (M) {
286
- case h:
287
- $ = D() / 12;
288
- break;
289
- case c:
290
- $ = D();
291
- break;
292
- case f:
293
- $ = D() / 3;
294
- break;
295
- case o:
296
- $ = (g - v) / 6048e5;
297
- break;
298
- case a:
299
- $ = (g - v) / 864e5;
300
- break;
301
- case u:
302
- $ = g / n;
303
- break;
304
- case s:
305
- $ = g / e;
306
- break;
307
- case i:
308
- $ = g / t;
309
- break;
310
- default: $ = g;
311
- }
312
- return l ? $ : b.a($);
313
- }, m.daysInMonth = function() {
314
- return this.endOf(c).$D;
315
- }, m.$locale = function() {
316
- return D[this.$L];
317
- }, m.locale = function(t, e) {
318
- if (!t) return this.$L;
319
- var n = this.clone(), r = w(t, e, !0);
320
- return r && (n.$L = r), n;
321
- }, m.clone = function() {
322
- return b.w(this.$d, this);
323
- }, m.toDate = function() {
324
- return new Date(this.valueOf());
325
- }, m.toJSON = function() {
326
- return this.isValid() ? this.toISOString() : null;
327
- }, m.toISOString = function() {
328
- return this.$d.toISOString();
329
- }, m.toString = function() {
330
- return this.$d.toUTCString();
331
- }, M;
332
- }(), Y = _.prototype;
333
- return O.prototype = Y, [
334
- ["$ms", r],
335
- ["$s", i],
336
- ["$m", s],
337
- ["$H", u],
338
- ["$W", a],
339
- ["$M", c],
340
- ["$y", h],
341
- ["$D", d]
342
- ].forEach((function(t) {
343
- Y[t[1]] = function(e) {
344
- return this.$g(e, t[0], t[1]);
345
- };
346
- })), O.extend = function(t, e) {
347
- return t.$i || (t(e, _, O), t.$i = !0), O;
348
- }, O.locale = w, O.isDayjs = S, O.unix = function(t) {
349
- return O(1e3 * t);
350
- }, O.en = D[g], O.Ls = D, O.p = {}, O;
351
- }));
352
- })))(), 1);
353
57
  function isPlainObject(value) {
354
58
  if (typeof value !== "object" || value === null) return false;
355
59
  const prototype = Object.getPrototypeOf(value);
@@ -6509,13 +6213,14 @@ createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
6509
6213
  const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
6510
6214
  //#endregion
6511
6215
  //#region src/utils/createWrangler.ts
6512
- const createWrangler = ({ stdio, accountId, cloudflareApiToken, cwd }) => {
6216
+ const createWrangler = ({ stdio, accountId, cloudflareApiToken, cwd, nonInteractive }) => {
6513
6217
  const $ = execa({
6514
6218
  stdio,
6515
6219
  extendsEnv: true,
6516
- shell: stdio === "inherit",
6220
+ shell: false,
6517
6221
  cwd,
6518
6222
  env: {
6223
+ ...nonInteractive ? { CI: "true" } : {},
6519
6224
  CLOUDFLARE_ACCOUNT_ID: accountId,
6520
6225
  CLOUDFLARE_API_TOKEN: cloudflareApiToken
6521
6226
  }
@@ -6523,6 +6228,465 @@ const createWrangler = ({ stdio, accountId, cloudflareApiToken, cwd }) => {
6523
6228
  return (...command) => $("npx", ["wrangler", ...command]);
6524
6229
  };
6525
6230
  //#endregion
6231
+ //#region iac/cloudflareInitErrors.ts
6232
+ const CLOUDFLARE_INIT_PERMISSION = { d1: "D1: Edit" };
6233
+ const CLOUDFLARE_INIT_PERMISSIONS = [CLOUDFLARE_INIT_PERMISSION.d1];
6234
+ const getCredentialRemediation = (source) => {
6235
+ switch (source.kind) {
6236
+ case "environment": return ["Update HOT_UPDATER_CLOUDFLARE_API_TOKEN in the environment, then rerun init."];
6237
+ case "env-file": return [`Update HOT_UPDATER_CLOUDFLARE_API_TOKEN in ${source.envFile}, then rerun init.`, "Alternatively, rerun without --env-file to enter a new token."];
6238
+ case "prompt": return ["Create a new API token, then rerun init and enter it again."];
6239
+ case "wrangler-oauth": return ["Refresh Wrangler authentication with `npx wrangler login`, then rerun init."];
6240
+ }
6241
+ };
6242
+ const getErrorOutput = (error) => {
6243
+ const output = [];
6244
+ if (error instanceof Error) output.push(error.message);
6245
+ if (typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string") output.push(error.stderr);
6246
+ if (typeof error === "object" && error !== null && "stdout" in error && typeof error.stdout === "string") output.push(error.stdout);
6247
+ return output.join("\n");
6248
+ };
6249
+ const isCloudflareAuthenticationError = (error) => {
6250
+ if (error instanceof cloudflare_error.APIError) return error.status === 401 || error.status === 403 || error.errors.some(({ code }) => code === 6003 || code === 6111 || code === 1e4 || code === 9109) || /invalid format for authorization header/i.test(error.message);
6251
+ return [
6252
+ /authentication error/i,
6253
+ /invalid access token/i,
6254
+ /invalid format for authorization header/i,
6255
+ /code:\s*(?:6003|6111|10000|9109)/i,
6256
+ /"code"\s*:\s*(?:6003|6111|10000|9109)/i
6257
+ ].some((pattern) => pattern.test(getErrorOutput(error)));
6258
+ };
6259
+ var CloudflareAuthenticationError = class extends _hot_updater_cli_tools.InitError {
6260
+ name = "CloudflareAuthenticationError";
6261
+ constructor(source, accountId, options) {
6262
+ super([
6263
+ source.kind === "wrangler-oauth" ? "Cloudflare Wrangler authentication failed." : "Cloudflare API token is invalid, expired, or missing required permissions.",
6264
+ ...accountId ? [`Selected account: ${accountId}`, "Confirm the token is active and its resource scope includes this account."] : [],
6265
+ ...getCredentialRemediation(source),
6266
+ ...source.kind === "wrangler-oauth" ? [] : [`Required permissions: ${CLOUDFLARE_INIT_PERMISSIONS.join(", ")}`],
6267
+ "Verify token status: https://developers.cloudflare.com/fundamentals/api/get-started/create-token/#test-the-token"
6268
+ ].join("\n"), options);
6269
+ this.source = source;
6270
+ this.accountId = accountId;
6271
+ }
6272
+ };
6273
+ var CloudflarePermissionError = class extends _hot_updater_cli_tools.InitError {
6274
+ name = "CloudflarePermissionError";
6275
+ constructor(source, { accountId, check, requiredPermission }, options) {
6276
+ super([
6277
+ "Cloudflare API token cannot access a required account resource.",
6278
+ `Selected account: ${accountId}`,
6279
+ `Failed check: ${check}`,
6280
+ `Required permission: ${requiredPermission}`,
6281
+ "Confirm the token permission and account resource scope, then rerun init.",
6282
+ ...getCredentialRemediation(source)
6283
+ ].join("\n"), options);
6284
+ this.source = source;
6285
+ this.accountId = accountId;
6286
+ this.check = check;
6287
+ this.requiredPermission = requiredPermission;
6288
+ }
6289
+ accountId;
6290
+ check;
6291
+ requiredPermission;
6292
+ };
6293
+ var CloudflareDeploymentError = class extends _hot_updater_cli_tools.InitError {
6294
+ name = "CloudflareDeploymentError";
6295
+ constructor(cause) {
6296
+ super([
6297
+ "Cloudflare Worker deployment failed.",
6298
+ "Review the Wrangler error above, fix the reported resource or permission, then rerun init.",
6299
+ `Cause: ${cause.message}`
6300
+ ].join("\n"), { cause });
6301
+ }
6302
+ };
6303
+ var CloudflareApiRequestError = class extends _hot_updater_cli_tools.InitError {
6304
+ name = "CloudflareApiRequestError";
6305
+ constructor(cause) {
6306
+ super([
6307
+ "Cloudflare infrastructure request failed.",
6308
+ "Review the Cloudflare error, confirm the token permissions and selected resources, then rerun init.",
6309
+ `Cause: ${cause.message}`
6310
+ ].join("\n"), { cause });
6311
+ }
6312
+ };
6313
+ const toCloudflareApiError = (error, source) => {
6314
+ if (error instanceof _hot_updater_cli_tools.InitError) return error;
6315
+ if (isCloudflareAuthenticationError(error)) return new CloudflareAuthenticationError(source, void 0, { cause: error });
6316
+ if (error instanceof cloudflare_error.APIError) return new CloudflareApiRequestError(error);
6317
+ return error instanceof Error ? error : new Error(String(error));
6318
+ };
6319
+ const runCloudflareApiRequest = async ({ request, source }) => {
6320
+ try {
6321
+ return await request();
6322
+ } catch (error) {
6323
+ if (error instanceof Error) throw toCloudflareApiError(error, source);
6324
+ throw new Error(String(error));
6325
+ }
6326
+ };
6327
+ const toCloudflareDeploymentError = (error, source) => {
6328
+ const apiError = toCloudflareApiError(error, source);
6329
+ return apiError instanceof _hot_updater_cli_tools.InitError ? apiError : new CloudflareDeploymentError(apiError);
6330
+ };
6331
+ //#endregion
6332
+ //#region iac/cloudflareApiToken.ts
6333
+ const verifyCloudflareApiTokenIdentity = async ({ accountId, apiToken, verifyAccountToken, verifyUserToken }) => {
6334
+ if (apiToken.startsWith("cfat_")) return verifyAccountToken(accountId);
6335
+ if (apiToken.startsWith("cfut_")) return verifyUserToken();
6336
+ try {
6337
+ return await verifyAccountToken(accountId);
6338
+ } catch (error) {
6339
+ if (!isCloudflareAuthenticationError(error)) throw error;
6340
+ return verifyUserToken();
6341
+ }
6342
+ };
6343
+ const validateCloudflareApiToken = async ({ accountId, probes, source, verify }) => {
6344
+ let verification;
6345
+ try {
6346
+ verification = await verify();
6347
+ } catch (error) {
6348
+ if (isCloudflareAuthenticationError(error)) throw new CloudflareAuthenticationError(source, accountId, { cause: error });
6349
+ throw toCloudflareApiError(error, source);
6350
+ }
6351
+ if (verification.status !== "active") throw new CloudflareAuthenticationError(source, accountId);
6352
+ for (const probe of probes) try {
6353
+ await probe.request();
6354
+ } catch (error) {
6355
+ if (isCloudflareAuthenticationError(error)) throw new CloudflarePermissionError(source, {
6356
+ accountId,
6357
+ check: probe.check,
6358
+ requiredPermission: probe.requiredPermission
6359
+ }, { cause: error });
6360
+ throw toCloudflareApiError(error, source);
6361
+ }
6362
+ };
6363
+ //#endregion
6364
+ //#region iac/cloudflareD1Selection.ts
6365
+ var CloudflareD1IdentifierConflictError = class extends _hot_updater_cli_tools.InitError {
6366
+ name = "CloudflareD1IdentifierConflictError";
6367
+ constructor({ databaseId, databaseName }) {
6368
+ super([
6369
+ "Cloudflare D1 identifiers conflict.",
6370
+ `Database ID: ${databaseId}`,
6371
+ `Database name: ${databaseName}`,
6372
+ "Update the env file so both values identify the same database, then rerun init."
6373
+ ].join("\n"));
6374
+ }
6375
+ };
6376
+ const resolveCloudflareReplayD1Database = ({ availableDatabases, databaseId, databaseName }) => {
6377
+ const exactMatch = availableDatabases.find((database) => database.uuid === databaseId && database.name === databaseName);
6378
+ if (exactMatch) return {
6379
+ database: exactMatch,
6380
+ kind: "existing"
6381
+ };
6382
+ if (availableDatabases.some((database) => database.uuid === databaseId || database.name === databaseName)) throw new CloudflareD1IdentifierConflictError({
6383
+ databaseId,
6384
+ databaseName
6385
+ });
6386
+ return {
6387
+ kind: "create",
6388
+ name: databaseName
6389
+ };
6390
+ };
6391
+ //#endregion
6392
+ //#region ../../node_modules/.pnpm/dayjs@1.11.21/node_modules/dayjs/dayjs.min.js
6393
+ var require_dayjs_min = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6394
+ (function(t, e) {
6395
+ "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
6396
+ })(exports, (function() {
6397
+ "use strict";
6398
+ var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = {
6399
+ name: "en",
6400
+ weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
6401
+ months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
6402
+ ordinal: function(t) {
6403
+ var e = [
6404
+ "th",
6405
+ "st",
6406
+ "nd",
6407
+ "rd"
6408
+ ], n = t % 100;
6409
+ return "[" + t + (e[(n - 20) % 10] || e[n] || e[0]) + "]";
6410
+ }
6411
+ }, m = function(t, e, n) {
6412
+ var r = String(t);
6413
+ return !r || r.length >= e ? t : "" + Array(e + 1 - r.length).join(n) + t;
6414
+ }, v = {
6415
+ s: m,
6416
+ z: function(t) {
6417
+ var e = -t.utcOffset(), n = Math.abs(e), r = Math.floor(n / 60), i = n % 60;
6418
+ return (e <= 0 ? "+" : "-") + m(r, 2, "0") + ":" + m(i, 2, "0");
6419
+ },
6420
+ m: function t(e, n) {
6421
+ if (e.date() < n.date()) return -t(n, e);
6422
+ var r = 12 * (n.year() - e.year()) + (n.month() - e.month()), i = e.clone().add(r, c), s = n - i < 0, u = e.clone().add(r + (s ? -1 : 1), c);
6423
+ return +(-(r + (n - i) / (s ? i - u : u - i)) || 0);
6424
+ },
6425
+ a: function(t) {
6426
+ return t < 0 ? Math.ceil(t) || 0 : Math.floor(t);
6427
+ },
6428
+ p: function(t) {
6429
+ return {
6430
+ M: c,
6431
+ y: h,
6432
+ w: o,
6433
+ d: a,
6434
+ D: d,
6435
+ h: u,
6436
+ m: s,
6437
+ s: i,
6438
+ ms: r,
6439
+ Q: f
6440
+ }[t] || String(t || "").toLowerCase().replace(/s$/, "");
6441
+ },
6442
+ u: function(t) {
6443
+ return void 0 === t;
6444
+ }
6445
+ }, g = "en", D = {};
6446
+ D[g] = M;
6447
+ var p = "$isDayjsObject", S = function(t) {
6448
+ return t instanceof _ || !(!t || !t[p]);
6449
+ }, w = function t(e, n, r) {
6450
+ var i;
6451
+ if (!e) return g;
6452
+ if ("string" == typeof e) {
6453
+ var s = e.toLowerCase();
6454
+ D[s] && (i = s), n && (D[s] = n, i = s);
6455
+ var u = e.split("-");
6456
+ if (!i && u.length > 1) return t(u[0]);
6457
+ } else {
6458
+ var a = e.name;
6459
+ D[a] = e, i = a;
6460
+ }
6461
+ return !r && i && (g = i), i || !r && g;
6462
+ }, O = function(t, e) {
6463
+ if (S(t)) return t.clone();
6464
+ var n = "object" == typeof e ? e : {};
6465
+ return n.date = t, n.args = arguments, new _(n);
6466
+ }, b = v;
6467
+ b.l = w, b.i = S, b.w = function(t, e) {
6468
+ return O(t, {
6469
+ locale: e.$L,
6470
+ utc: e.$u,
6471
+ x: e.$x,
6472
+ $offset: e.$offset
6473
+ });
6474
+ };
6475
+ var _ = function() {
6476
+ function M(t) {
6477
+ this.$L = w(t.locale, null, !0), this.parse(t), this.$x = this.$x || t.x || {}, this[p] = !0;
6478
+ }
6479
+ var m = M.prototype;
6480
+ return m.parse = function(t) {
6481
+ this.$d = function(t) {
6482
+ var e = t.date, n = t.utc;
6483
+ if (null === e) return /* @__PURE__ */ new Date(NaN);
6484
+ if (b.u(e)) return /* @__PURE__ */ new Date();
6485
+ if (e instanceof Date) return new Date(e);
6486
+ if ("string" == typeof e && !/Z$/i.test(e)) {
6487
+ var r = e.match($);
6488
+ if (r) {
6489
+ var i = r[2] - 1 || 0, s = (r[7] || "0").substring(0, 3);
6490
+ return n ? new Date(Date.UTC(r[1], i, r[3] || 1, r[4] || 0, r[5] || 0, r[6] || 0, s)) : new Date(r[1], i, r[3] || 1, r[4] || 0, r[5] || 0, r[6] || 0, s);
6491
+ }
6492
+ }
6493
+ return new Date(e);
6494
+ }(t), this.init();
6495
+ }, m.init = function() {
6496
+ var t = this.$d;
6497
+ this.$y = t.getFullYear(), this.$M = t.getMonth(), this.$D = t.getDate(), this.$W = t.getDay(), this.$H = t.getHours(), this.$m = t.getMinutes(), this.$s = t.getSeconds(), this.$ms = t.getMilliseconds();
6498
+ }, m.$utils = function() {
6499
+ return b;
6500
+ }, m.isValid = function() {
6501
+ return !(this.$d.toString() === l);
6502
+ }, m.isSame = function(t, e) {
6503
+ var n = O(t);
6504
+ return this.startOf(e) <= n && n <= this.endOf(e);
6505
+ }, m.isAfter = function(t, e) {
6506
+ return O(t) < this.startOf(e);
6507
+ }, m.isBefore = function(t, e) {
6508
+ return this.endOf(e) < O(t);
6509
+ }, m.$g = function(t, e, n) {
6510
+ return b.u(t) ? this[e] : this.set(n, t);
6511
+ }, m.unix = function() {
6512
+ return Math.floor(this.valueOf() / 1e3);
6513
+ }, m.valueOf = function() {
6514
+ return this.$d.getTime();
6515
+ }, m.startOf = function(t, e) {
6516
+ var n = this, r = !!b.u(e) || e, f = b.p(t), l = function(t, e) {
6517
+ var i = b.w(n.$u ? Date.UTC(n.$y, e, t) : new Date(n.$y, e, t), n);
6518
+ return r ? i : i.endOf(a);
6519
+ }, $ = function(t, e) {
6520
+ return b.w(n.toDate()[t].apply(n.toDate("s"), (r ? [
6521
+ 0,
6522
+ 0,
6523
+ 0,
6524
+ 0
6525
+ ] : [
6526
+ 23,
6527
+ 59,
6528
+ 59,
6529
+ 999
6530
+ ]).slice(e)), n);
6531
+ }, y = this.$W, M = this.$M, m = this.$D, v = "set" + (this.$u ? "UTC" : "");
6532
+ switch (f) {
6533
+ case h: return r ? l(1, 0) : l(31, 11);
6534
+ case c: return r ? l(1, M) : l(0, M + 1);
6535
+ case o:
6536
+ var g = this.$locale().weekStart || 0, D = (y < g ? y + 7 : y) - g;
6537
+ return l(r ? m - D : m + (6 - D), M);
6538
+ case a:
6539
+ case d: return $(v + "Hours", 0);
6540
+ case u: return $(v + "Minutes", 1);
6541
+ case s: return $(v + "Seconds", 2);
6542
+ case i: return $(v + "Milliseconds", 3);
6543
+ default: return this.clone();
6544
+ }
6545
+ }, m.endOf = function(t) {
6546
+ return this.startOf(t, !1);
6547
+ }, m.$set = function(t, e) {
6548
+ var n, o = b.p(t), f = "set" + (this.$u ? "UTC" : ""), l = (n = {}, n[a] = f + "Date", n[d] = f + "Date", n[c] = f + "Month", n[h] = f + "FullYear", n[u] = f + "Hours", n[s] = f + "Minutes", n[i] = f + "Seconds", n[r] = f + "Milliseconds", n)[o], $ = o === a ? this.$D + (e - this.$W) : e;
6549
+ if (o === c || o === h) {
6550
+ var y = this.clone().set(d, 1);
6551
+ y.$d[l]($), y.init(), this.$d = y.set(d, Math.min(this.$D, y.daysInMonth())).$d;
6552
+ } else l && this.$d[l]($);
6553
+ return this.init(), this;
6554
+ }, m.set = function(t, e) {
6555
+ return this.clone().$set(t, e);
6556
+ }, m.get = function(t) {
6557
+ return this[b.p(t)]();
6558
+ }, m.add = function(r, f) {
6559
+ var d, l = this;
6560
+ r = Number(r);
6561
+ var $ = b.p(f), y = function(t) {
6562
+ var e = O(l);
6563
+ return b.w(e.date(e.date() + Math.round(t * r)), l);
6564
+ };
6565
+ if ($ === c) return this.set(c, this.$M + r);
6566
+ if ($ === h) return this.set(h, this.$y + r);
6567
+ if ($ === a) return y(1);
6568
+ if ($ === o) return y(7);
6569
+ var M = (d = {}, d[s] = e, d[u] = n, d[i] = t, d)[$] || 1, m = this.$d.getTime() + r * M;
6570
+ return b.w(m, this);
6571
+ }, m.subtract = function(t, e) {
6572
+ return this.add(-1 * t, e);
6573
+ }, m.format = function(t) {
6574
+ var e = this, n = this.$locale();
6575
+ if (!this.isValid()) return n.invalidDate || l;
6576
+ var r = t || "YYYY-MM-DDTHH:mm:ssZ", i = b.z(this), s = this.$H, u = this.$m, a = this.$M, o = n.weekdays, c = n.months, f = n.meridiem, h = function(t, n, i, s) {
6577
+ return t && (t[n] || t(e, r)) || i[n].slice(0, s);
6578
+ }, d = function(t) {
6579
+ return b.s(s % 12 || 12, t, "0");
6580
+ }, $ = f || function(t, e, n) {
6581
+ var r = t < 12 ? "AM" : "PM";
6582
+ return n ? r.toLowerCase() : r;
6583
+ };
6584
+ return r.replace(y, (function(t, r) {
6585
+ return r || function(t) {
6586
+ switch (t) {
6587
+ case "YY": return String(e.$y).slice(-2);
6588
+ case "YYYY": return b.s(e.$y, 4, "0");
6589
+ case "M": return a + 1;
6590
+ case "MM": return b.s(a + 1, 2, "0");
6591
+ case "MMM": return h(n.monthsShort, a, c, 3);
6592
+ case "MMMM": return h(c, a);
6593
+ case "D": return e.$D;
6594
+ case "DD": return b.s(e.$D, 2, "0");
6595
+ case "d": return String(e.$W);
6596
+ case "dd": return h(n.weekdaysMin, e.$W, o, 2);
6597
+ case "ddd": return h(n.weekdaysShort, e.$W, o, 3);
6598
+ case "dddd": return o[e.$W];
6599
+ case "H": return String(s);
6600
+ case "HH": return b.s(s, 2, "0");
6601
+ case "h": return d(1);
6602
+ case "hh": return d(2);
6603
+ case "a": return $(s, u, !0);
6604
+ case "A": return $(s, u, !1);
6605
+ case "m": return String(u);
6606
+ case "mm": return b.s(u, 2, "0");
6607
+ case "s": return String(e.$s);
6608
+ case "ss": return b.s(e.$s, 2, "0");
6609
+ case "SSS": return b.s(e.$ms, 3, "0");
6610
+ case "Z": return i;
6611
+ }
6612
+ return null;
6613
+ }(t) || i.replace(":", "");
6614
+ }));
6615
+ }, m.utcOffset = function() {
6616
+ return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
6617
+ }, m.diff = function(r, d, l) {
6618
+ var $, y = this, M = b.p(d), m = O(r), v = (m.utcOffset() - this.utcOffset()) * e, g = this - m, D = function() {
6619
+ return b.m(y, m);
6620
+ };
6621
+ switch (M) {
6622
+ case h:
6623
+ $ = D() / 12;
6624
+ break;
6625
+ case c:
6626
+ $ = D();
6627
+ break;
6628
+ case f:
6629
+ $ = D() / 3;
6630
+ break;
6631
+ case o:
6632
+ $ = (g - v) / 6048e5;
6633
+ break;
6634
+ case a:
6635
+ $ = (g - v) / 864e5;
6636
+ break;
6637
+ case u:
6638
+ $ = g / n;
6639
+ break;
6640
+ case s:
6641
+ $ = g / e;
6642
+ break;
6643
+ case i:
6644
+ $ = g / t;
6645
+ break;
6646
+ default: $ = g;
6647
+ }
6648
+ return l ? $ : b.a($);
6649
+ }, m.daysInMonth = function() {
6650
+ return this.endOf(c).$D;
6651
+ }, m.$locale = function() {
6652
+ return D[this.$L];
6653
+ }, m.locale = function(t, e) {
6654
+ if (!t) return this.$L;
6655
+ var n = this.clone(), r = w(t, e, !0);
6656
+ return r && (n.$L = r), n;
6657
+ }, m.clone = function() {
6658
+ return b.w(this.$d, this);
6659
+ }, m.toDate = function() {
6660
+ return new Date(this.valueOf());
6661
+ }, m.toJSON = function() {
6662
+ return this.isValid() ? this.toISOString() : null;
6663
+ }, m.toISOString = function() {
6664
+ return this.$d.toISOString();
6665
+ }, m.toString = function() {
6666
+ return this.$d.toUTCString();
6667
+ }, M;
6668
+ }(), Y = _.prototype;
6669
+ return O.prototype = Y, [
6670
+ ["$ms", r],
6671
+ ["$s", i],
6672
+ ["$m", s],
6673
+ ["$H", u],
6674
+ ["$W", a],
6675
+ ["$M", c],
6676
+ ["$y", h],
6677
+ ["$D", d]
6678
+ ].forEach((function(t) {
6679
+ Y[t[1]] = function(e) {
6680
+ return this.$g(e, t[0], t[1]);
6681
+ };
6682
+ })), O.extend = function(t, e) {
6683
+ return t.$i || (t(e, _, O), t.$i = !0), O;
6684
+ }, O.locale = w, O.isDayjs = S, O.unix = function(t) {
6685
+ return O(1e3 * t);
6686
+ }, O.en = D[g], O.Ls = D, O.p = {}, O;
6687
+ }));
6688
+ }));
6689
+ //#endregion
6526
6690
  //#region ../../node_modules/.pnpm/toml@3.0.0/node_modules/toml/lib/parser.js
6527
6691
  var require_parser = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6528
6692
  module.exports = (function() {
@@ -10810,6 +10974,7 @@ var require_mod_cjs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
10810
10974
  }));
10811
10975
  //#endregion
10812
10976
  //#region ../../node_modules/.pnpm/xdg-app-paths@8.3.0/node_modules/xdg-app-paths/dist/cjs/esm-wrapper/mod.esm.js
10977
+ var import_dayjs_min = /* @__PURE__ */ __toESM(require_dayjs_min(), 1);
10813
10978
  var import_toml = /* @__PURE__ */ __toESM(require_toml(), 1);
10814
10979
  var mod_esm_default = (/* @__PURE__ */ __toESM(require_mod_cjs())).default;
10815
10980
  //#endregion
@@ -10837,6 +11002,206 @@ const getWranglerLoginAuthToken = () => {
10837
11002
  }
10838
11003
  };
10839
11004
  //#endregion
11005
+ //#region iac/cloudflareInfrastructureAuth.ts
11006
+ var CloudflareWranglerLoginRequiredError = class extends _hot_updater_cli_tools.InitError {
11007
+ name = "CloudflareWranglerLoginRequiredError";
11008
+ constructor() {
11009
+ super(["Cloudflare Wrangler login is required.", "Run `npx wrangler login` interactively, then rerun init."].join("\n"));
11010
+ }
11011
+ };
11012
+ const getValidWranglerAuthToken = () => {
11013
+ const auth = getWranglerLoginAuthToken();
11014
+ if (!auth || (0, import_dayjs_min.default)(auth.expiration_time).isBefore((0, import_dayjs_min.default)())) return;
11015
+ return auth.oauth_token;
11016
+ };
11017
+ const resolveCloudflareInfrastructureApiToken = async ({ cwd, nonInteractive }) => {
11018
+ const existingToken = getValidWranglerAuthToken();
11019
+ if (existingToken) return existingToken;
11020
+ if (nonInteractive) throw new CloudflareWranglerLoginRequiredError();
11021
+ await execa("npx", [
11022
+ "wrangler",
11023
+ "login",
11024
+ "--scopes",
11025
+ "account:read",
11026
+ "user:read",
11027
+ "d1:write",
11028
+ "workers:write",
11029
+ "workers_scripts:write"
11030
+ ], { cwd });
11031
+ const authenticatedToken = getValidWranglerAuthToken();
11032
+ if (!authenticatedToken) throw new CloudflareWranglerLoginRequiredError();
11033
+ return authenticatedToken;
11034
+ };
11035
+ //#endregion
11036
+ //#region iac/init/index.ts
11037
+ const initProvider = {
11038
+ label: "Cloudflare D1 + R2 + Worker",
11039
+ inputs: {
11040
+ accountId: {
11041
+ envKey: "HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID",
11042
+ help: "Cloudflare account ID",
11043
+ prompt: {
11044
+ message: "Account List",
11045
+ type: "select"
11046
+ }
11047
+ },
11048
+ apiToken: {
11049
+ envKey: "HOT_UPDATER_CLOUDFLARE_API_TOKEN",
11050
+ help: "API token with D1 edit permission",
11051
+ persistence: "with-consent",
11052
+ prompt: {
11053
+ message: "Enter the Cloudflare D1 API Token",
11054
+ type: "password"
11055
+ }
11056
+ },
11057
+ bucketName: {
11058
+ envKey: "HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME",
11059
+ help: "R2 bucket name",
11060
+ prompt: {
11061
+ defaultValue: "hot-updater-storage",
11062
+ message: "Enter the name of the new R2 Bucket",
11063
+ placeholder: "hot-updater-storage",
11064
+ type: "text"
11065
+ }
11066
+ },
11067
+ accessKeyId: {
11068
+ envKey: "HOT_UPDATER_CLOUDFLARE_R2_ACCESS_KEY_ID",
11069
+ help: "R2 access key ID",
11070
+ persistence: "with-consent",
11071
+ prompt: {
11072
+ message: "Enter the R2 Access Key ID",
11073
+ type: "password"
11074
+ }
11075
+ },
11076
+ secretAccessKey: {
11077
+ envKey: "HOT_UPDATER_CLOUDFLARE_R2_SECRET_ACCESS_KEY",
11078
+ help: "R2 secret access key",
11079
+ persistence: "with-consent",
11080
+ prompt: {
11081
+ message: "Enter the R2 Secret Access Key",
11082
+ type: "password"
11083
+ }
11084
+ },
11085
+ workerName: {
11086
+ envKey: "HOT_UPDATER_CLOUDFLARE_WORKER_NAME",
11087
+ help: "Worker name",
11088
+ prompt: {
11089
+ defaultValue: "hot-updater",
11090
+ message: "Enter the name of the worker",
11091
+ placeholder: "hot-updater",
11092
+ type: "text"
11093
+ }
11094
+ },
11095
+ d1DatabaseId: {
11096
+ envKey: "HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID",
11097
+ help: "D1 database ID"
11098
+ },
11099
+ d1DatabaseName: {
11100
+ envKey: "HOT_UPDATER_CLOUDFLARE_D1_DATABASE_NAME",
11101
+ help: "D1 database name",
11102
+ prompt: {
11103
+ defaultValue: "hot-updater",
11104
+ message: "Enter the name of the new D1 Database",
11105
+ placeholder: "hot-updater",
11106
+ type: "text"
11107
+ }
11108
+ },
11109
+ r2Private: {
11110
+ envKey: "HOT_UPDATER_CLOUDFLARE_R2_PRIVATE",
11111
+ help: "Whether the R2 bucket is private (true or false)",
11112
+ prompt: {
11113
+ message: "Make R2 bucket private?",
11114
+ type: "confirm"
11115
+ },
11116
+ validate: (value) => value === "true" || value === "false"
11117
+ }
11118
+ }
11119
+ };
11120
+ //#endregion
11121
+ //#region iac/cloudflareInitInputs.ts
11122
+ const shouldUpdateR2ManagedDomain = ({ isPrivate, managedDomainEnabled }) => managedDomainEnabled !== !isPrivate;
11123
+ const resolveR2Privacy = ({ createBucket, managedDomainEnabled, savedPrivateSetting }) => {
11124
+ if (savedPrivateSetting === "true" || savedPrivateSetting === "false") return {
11125
+ isPrivate: savedPrivateSetting === "true",
11126
+ kind: "resolved"
11127
+ };
11128
+ if (!createBucket && managedDomainEnabled !== void 0) return {
11129
+ isPrivate: !managedDomainEnabled,
11130
+ kind: "resolved"
11131
+ };
11132
+ return { kind: "prompt" };
11133
+ };
11134
+ const resolveCloudflareInitInputs = (existingEnv) => {
11135
+ const { inputs } = initProvider;
11136
+ return {
11137
+ accessKeyId: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.accessKeyId),
11138
+ accountId: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.accountId),
11139
+ apiToken: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.apiToken),
11140
+ bucketName: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.bucketName),
11141
+ d1DatabaseId: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.d1DatabaseId),
11142
+ d1DatabaseName: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.d1DatabaseName),
11143
+ r2Private: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.r2Private),
11144
+ secretAccessKey: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.secretAccessKey),
11145
+ workerName: (0, _hot_updater_cli_tools.resolveInitProviderInput)(existingEnv, inputs.workerName)
11146
+ };
11147
+ };
11148
+ const assertCloudflareNonInteractiveInputs = (inputs, nonInteractive) => {
11149
+ (0, _hot_updater_cli_tools.assertInitProviderInputs)({
11150
+ inputs,
11151
+ provider: initProvider,
11152
+ strict: nonInteractive
11153
+ });
11154
+ };
11155
+ //#endregion
11156
+ //#region iac/cloudflareInitSecrets.ts
11157
+ const inputCloudflareInitSecrets = async ({ accountId, bucketName, apiToken, accessKeyId, secretAccessKey, workerName, nonInteractive }) => {
11158
+ const inputDefinitions = initProvider.inputs;
11159
+ (0, _hot_updater_cli_tools.assertInitInputs)({
11160
+ inputs: {
11161
+ [inputDefinitions.apiToken.envKey]: apiToken,
11162
+ [inputDefinitions.accessKeyId.envKey]: accessKeyId,
11163
+ [inputDefinitions.secretAccessKey.envKey]: secretAccessKey,
11164
+ [inputDefinitions.workerName.envKey]: workerName
11165
+ },
11166
+ strict: nonInteractive
11167
+ });
11168
+ if (nonInteractive && apiToken && accessKeyId && secretAccessKey && workerName) return {
11169
+ accessKeyId,
11170
+ apiToken,
11171
+ secretAccessKey,
11172
+ workerName
11173
+ };
11174
+ if (!nonInteractive) {
11175
+ _hot_updater_cli_tools.p.log.step(`D1 API Token dashboard: ${(0, _hot_updater_cli_tools.link)(`https://dash.cloudflare.com/${accountId}/api-tokens`)}`);
11176
+ _hot_updater_cli_tools.p.log.step(`Required permissions: ${CLOUDFLARE_INIT_PERMISSIONS.join(", ")}`);
11177
+ _hot_updater_cli_tools.p.log.step("Used by d1Database for bundle metadata writes.");
11178
+ }
11179
+ if (!nonInteractive) {
11180
+ _hot_updater_cli_tools.p.log.step(`R2 API Tokens dashboard: ${(0, _hot_updater_cli_tools.link)(`https://dash.cloudflare.com/${accountId}/r2/api-tokens`)}`);
11181
+ _hot_updater_cli_tools.p.log.step("Required permission: Object Read & Write");
11182
+ _hot_updater_cli_tools.p.log.step(`Target bucket: ${bucketName}`);
11183
+ }
11184
+ return await _hot_updater_cli_tools.p.group({
11185
+ apiToken: () => nonInteractive && apiToken ? Promise.resolve(apiToken) : _hot_updater_cli_tools.p.password({
11186
+ message: inputDefinitions.apiToken.prompt.message,
11187
+ validate: (value) => value ? void 0 : "Cloudflare API Token is required"
11188
+ }),
11189
+ accessKeyId: () => nonInteractive && accessKeyId ? Promise.resolve(accessKeyId) : _hot_updater_cli_tools.p.password({
11190
+ message: inputDefinitions.accessKeyId.prompt.message,
11191
+ validate: (value) => value ? void 0 : "R2 Access Key ID is required"
11192
+ }),
11193
+ secretAccessKey: () => nonInteractive && secretAccessKey ? Promise.resolve(secretAccessKey) : _hot_updater_cli_tools.p.password({
11194
+ message: inputDefinitions.secretAccessKey.prompt.message,
11195
+ validate: (value) => value ? void 0 : "R2 Secret Access Key is required"
11196
+ }),
11197
+ workerName: () => nonInteractive && workerName ? Promise.resolve(workerName) : _hot_updater_cli_tools.p.text({
11198
+ ...(0, _hot_updater_cli_tools.getInitProviderTextPromptValues)(inputDefinitions.workerName.prompt, workerName),
11199
+ message: inputDefinitions.workerName.prompt.message,
11200
+ validate: (value) => value ? void 0 : "Worker name is required"
11201
+ })
11202
+ }, { onCancel: () => process.exit(1) });
11203
+ };
11204
+ //#endregion
10840
11205
  //#region iac/index.ts
10841
11206
  const getConfigScaffold = (build) => {
10842
11207
  return (0, _hot_updater_cli_tools.createHotUpdaterConfigScaffoldFromBuilder)(new _hot_updater_cli_tools.ConfigBuilder().setBuildType(build).setStorage({
@@ -10875,50 +11240,7 @@ export default HotUpdater.wrap({
10875
11240
  baseURL: "%%source%%",
10876
11241
  updateStrategy: "appVersion", // or "fingerprint"
10877
11242
  })(App);`;
10878
- const HOT_UPDATER_ENV_PATH = ".env.hotupdater";
10879
- const unquoteEnvValue = (value) => {
10880
- const trimmed = value.trim();
10881
- if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
10882
- return trimmed;
10883
- };
10884
- const readHotUpdaterEnv = async (cwd) => {
10885
- const envPath = path.default.join(cwd, HOT_UPDATER_ENV_PATH);
10886
- const content = await fs_promises.default.readFile(envPath, "utf-8").catch(() => "");
10887
- const env = {};
10888
- for (const line of content.split("\n")) {
10889
- const trimmed = line.trim();
10890
- if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) continue;
10891
- const [key, ...valueParts] = trimmed.split("=");
10892
- if (!key) continue;
10893
- env[key.trim()] = unquoteEnvValue(valueParts.join("="));
10894
- }
10895
- return env;
10896
- };
10897
- const getEnvValue = (env, key) => {
10898
- return process.env[key]?.trim() || env[key]?.trim() || void 0;
10899
- };
10900
- const inputR2ApiCredentials = async ({ accountId, bucketName, accessKeyId, secretAccessKey }) => {
10901
- _hot_updater_cli_tools.p.log.step(`R2 API Tokens dashboard: ${(0, _hot_updater_cli_tools.link)(`https://dash.cloudflare.com/${accountId}/r2/api-tokens`)}`);
10902
- _hot_updater_cli_tools.p.log.step("Required permission: Object Read & Write");
10903
- _hot_updater_cli_tools.p.log.step(`Target bucket: ${bucketName}`);
10904
- let resolvedAccessKeyId = accessKeyId;
10905
- if (!resolvedAccessKeyId) {
10906
- const inputR2AccessKeyId = await _hot_updater_cli_tools.p.password({ message: "Enter the R2 Access Key ID" });
10907
- if (_hot_updater_cli_tools.p.isCancel(inputR2AccessKeyId)) process.exit(1);
10908
- resolvedAccessKeyId = inputR2AccessKeyId;
10909
- }
10910
- let resolvedSecretAccessKey = secretAccessKey;
10911
- if (!resolvedSecretAccessKey) {
10912
- const inputR2SecretAccessKey = await _hot_updater_cli_tools.p.password({ message: "Enter the R2 Secret Access Key" });
10913
- if (_hot_updater_cli_tools.p.isCancel(inputR2SecretAccessKey)) process.exit(1);
10914
- resolvedSecretAccessKey = inputR2SecretAccessKey;
10915
- }
10916
- return {
10917
- accessKeyId: resolvedAccessKeyId,
10918
- secretAccessKey: resolvedSecretAccessKey
10919
- };
10920
- };
10921
- const deployWorker = async (oauth_token, accountId, { d1DatabaseId, d1DatabaseName, r2BucketName, workerName }) => {
11243
+ const deployWorker = async (apiToken, accountId, { credentialSource, d1DatabaseId, d1DatabaseName, nonInteractive, r2BucketName, workerName }) => {
10922
11244
  const cwd = (0, _hot_updater_cli_tools.getCwd)();
10923
11245
  const cloudflarePackagePath = require.resolve("@hot-updater/cloudflare/package.json", { paths: [cwd] });
10924
11246
  const { tmpDir, removeTmpDir } = await (0, _hot_updater_cli_tools.copyDirToTmp)(path.default.dirname(cloudflarePackagePath));
@@ -10938,9 +11260,10 @@ const deployWorker = async (oauth_token, accountId, { d1DatabaseId, d1DatabaseNa
10938
11260
  await fs_promises.default.writeFile(path.default.join(workerRoot, "wrangler.json"), JSON.stringify(wranglerConfig, null, 2));
10939
11261
  const wrangler = await createWrangler({
10940
11262
  stdio: "inherit",
10941
- cloudflareApiToken: oauth_token,
11263
+ cloudflareApiToken: apiToken,
10942
11264
  cwd: workerRoot,
10943
- accountId
11265
+ accountId,
11266
+ nonInteractive
10944
11267
  });
10945
11268
  const migrationPath = await path.default.join(workerRoot, "migrations");
10946
11269
  const migrationFiles = await fs_promises.default.readdir(migrationPath);
@@ -10950,48 +11273,35 @@ const deployWorker = async (oauth_token, accountId, { d1DatabaseId, d1DatabaseNa
10950
11273
  await fs_promises.default.writeFile(filePath, (0, _hot_updater_cli_tools.transformTemplate)(content, { BUCKET_NAME: r2BucketName }));
10951
11274
  }
10952
11275
  await wrangler("d1", "migrations", "apply", d1DatabaseName, "--remote");
10953
- let resolvedWorkerName = workerName;
10954
- if (resolvedWorkerName) _hot_updater_cli_tools.p.log.info("Using existing Cloudflare Worker name.");
10955
- else {
10956
- const inputWorkerName = await _hot_updater_cli_tools.p.text({
10957
- message: "Enter the name of the worker",
10958
- defaultValue: "hot-updater",
10959
- placeholder: "hot-updater"
10960
- });
10961
- if (_hot_updater_cli_tools.p.isCancel(inputWorkerName)) process.exit(1);
10962
- resolvedWorkerName = inputWorkerName;
10963
- }
10964
- await wrangler("deploy", "--name", resolvedWorkerName);
10965
- return resolvedWorkerName;
11276
+ await wrangler("deploy", "--name", workerName);
11277
+ return workerName;
10966
11278
  } catch (error) {
10967
- throw new Error("Failed to deploy worker", { cause: error });
11279
+ if (error instanceof Error) throw toCloudflareDeploymentError(error, credentialSource);
11280
+ throw new Error(String(error));
10968
11281
  } finally {
10969
11282
  await removeTmpDir();
10970
11283
  }
10971
11284
  };
10972
- const runInit = async ({ build }) => {
11285
+ const runInit = async ({ build, envFile }) => {
10973
11286
  const cwd = (0, _hot_updater_cli_tools.getCwd)();
10974
- const existingEnv = await readHotUpdaterEnv(cwd);
10975
- let auth = getWranglerLoginAuthToken();
10976
- if (!auth || (0, import_dayjs_min.default)(auth?.expiration_time).isBefore((0, import_dayjs_min.default)())) {
10977
- await execa("npx", [
10978
- "wrangler",
10979
- "login",
10980
- "--scopes",
10981
- "account:read",
10982
- "user:read",
10983
- "d1:write",
10984
- "workers:write",
10985
- "workers_scripts:write"
10986
- ], { cwd });
10987
- auth = getWranglerLoginAuthToken();
10988
- }
10989
- if (!auth) throw new Error("'npx wrangler login' is required to use this command");
10990
- const cf = new cloudflare.Cloudflare({ apiToken: auth.oauth_token });
11287
+ const nonInteractive = envFile !== void 0;
11288
+ const initEnvSources = await (0, _hot_updater_cli_tools.readHotUpdaterInitEnv)(cwd, envFile);
11289
+ const { managedEnv } = initEnvSources;
11290
+ const existingInputs = resolveCloudflareInitInputs((0, _hot_updater_cli_tools.getHotUpdaterInitInputEnv)(initEnvSources, nonInteractive));
11291
+ assertCloudflareNonInteractiveInputs(existingInputs, nonInteractive);
11292
+ const { accessKeyId: existingR2AccessKeyId, accountId: existingAccountId, apiToken: existingApiToken, bucketName: existingBucketName, d1DatabaseId: existingD1DatabaseId, d1DatabaseName: existingD1DatabaseName, r2Private: savedPrivateSetting, secretAccessKey: existingR2SecretAccessKey, workerName: existingWorkerName } = existingInputs;
11293
+ const infrastructureCredentialSource = { kind: "wrangler-oauth" };
11294
+ const infrastructureApiToken = await resolveCloudflareInfrastructureApiToken({
11295
+ cwd,
11296
+ nonInteractive
11297
+ });
11298
+ const cf = new cloudflare.Cloudflare({ apiToken: infrastructureApiToken });
10991
11299
  const createKey = `create/${Math.random().toString(36).substring(2, 15)}`;
10992
- let accountId = getEnvValue(existingEnv, "HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID");
10993
- if (accountId) _hot_updater_cli_tools.p.log.info("Using existing Cloudflare account ID.");
10994
- else {
11300
+ let accountId;
11301
+ if (nonInteractive && existingAccountId) {
11302
+ accountId = existingAccountId;
11303
+ _hot_updater_cli_tools.p.log.info("Using existing Cloudflare account ID.");
11304
+ } else {
10995
11305
  const accounts = [];
10996
11306
  try {
10997
11307
  await _hot_updater_cli_tools.p.tasks([{
@@ -11003,12 +11313,15 @@ const runInit = async ({ build }) => {
11003
11313
  })));
11004
11314
  }
11005
11315
  }]);
11006
- } catch (e) {
11007
- if (e instanceof Error) _hot_updater_cli_tools.p.log.error(e.message);
11008
- throw e;
11316
+ } catch (error) {
11317
+ if (error instanceof Error) throw toCloudflareApiError(error, infrastructureCredentialSource);
11318
+ throw new Error(String(error));
11009
11319
  }
11320
+ const savedAccount = accounts.find((account) => account.id === existingAccountId);
11321
+ if (existingAccountId && !savedAccount) _hot_updater_cli_tools.p.log.warn("Saved Cloudflare account was not found. Select an account again.");
11010
11322
  const selectedAccountId = await _hot_updater_cli_tools.p.select({
11011
- message: "Account List",
11323
+ initialValue: savedAccount?.id ?? accounts[0]?.id,
11324
+ message: initProvider.inputs.accountId.prompt.message,
11012
11325
  options: accounts.map((account) => ({
11013
11326
  value: account.id,
11014
11327
  label: `${account.name} (${account.id})`
@@ -11017,103 +11330,60 @@ const runInit = async ({ build }) => {
11017
11330
  if (_hot_updater_cli_tools.p.isCancel(selectedAccountId)) process.exit(1);
11018
11331
  accountId = selectedAccountId;
11019
11332
  }
11020
- let apiToken = getEnvValue(existingEnv, "HOT_UPDATER_CLOUDFLARE_API_TOKEN");
11021
- if (apiToken) _hot_updater_cli_tools.p.log.info("Using existing Cloudflare API token.");
11022
- else {
11023
- _hot_updater_cli_tools.p.log.step(`D1 API Token dashboard: ${(0, _hot_updater_cli_tools.link)(`https://dash.cloudflare.com/${accountId}/api-tokens`)}`);
11024
- _hot_updater_cli_tools.p.log.step("Required permission: D1 Edit");
11025
- _hot_updater_cli_tools.p.log.step("Used for bundle metadata writes after init.");
11026
- const inputApiToken = await _hot_updater_cli_tools.p.password({ message: "Enter the D1 API Token" });
11027
- if (_hot_updater_cli_tools.p.isCancel(inputApiToken)) process.exit(1);
11028
- apiToken = inputApiToken;
11029
- if (!apiToken) _hot_updater_cli_tools.p.log.warn("Skipping API Token. You can set it later in .env HOT_UPDATER_CLOUDFLARE_API_TOKEN file.");
11030
- }
11031
- const existingBucketName = getEnvValue(existingEnv, "HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME");
11333
+ const availableBuckets = [];
11334
+ try {
11335
+ await _hot_updater_cli_tools.p.tasks([{
11336
+ title: "Checking R2 Buckets...",
11337
+ task: async () => {
11338
+ const buckets = (await cf.r2.buckets.list({ account_id: accountId })).buckets ?? [];
11339
+ availableBuckets.push(...buckets.flatMap((bucket) => bucket.name ? [{ name: bucket.name }] : []));
11340
+ }
11341
+ }]);
11342
+ } catch (error) {
11343
+ if (error instanceof Error) throw toCloudflareApiError(error, infrastructureCredentialSource);
11344
+ throw new Error(String(error));
11345
+ }
11346
+ const hasExistingBucket = availableBuckets.some((bucket) => bucket.name === existingBucketName);
11347
+ let createBucket = false;
11032
11348
  let selectedBucketName;
11033
- if (existingBucketName) {
11349
+ if (nonInteractive && existingBucketName && hasExistingBucket) {
11350
+ selectedBucketName = existingBucketName;
11351
+ _hot_updater_cli_tools.p.log.info("Using existing Cloudflare R2 bucket.");
11352
+ } else if (nonInteractive && existingBucketName) {
11034
11353
  selectedBucketName = existingBucketName;
11035
- _hot_updater_cli_tools.p.log.info("Using existing Cloudflare R2 bucket name.");
11354
+ createBucket = true;
11036
11355
  } else {
11037
- const availableBuckets = [];
11038
- try {
11039
- await _hot_updater_cli_tools.p.tasks([{
11040
- title: "Checking R2 Buckets...",
11041
- task: async () => {
11042
- const buckets = (await cf.r2.buckets.list({ account_id: accountId })).buckets ?? [];
11043
- availableBuckets.push(...buckets.filter((bucket) => bucket.name).map((bucket) => ({ name: bucket.name })));
11044
- }
11045
- }]);
11046
- } catch (e) {
11047
- if (e instanceof Error) _hot_updater_cli_tools.p.log.error(e.message);
11048
- throw e;
11049
- }
11050
- if (availableBuckets.length === 1) {
11051
- selectedBucketName = availableBuckets[0].name;
11052
- _hot_updater_cli_tools.p.log.info("Using the only Cloudflare R2 bucket.");
11053
- } else {
11054
- const selectedR2BucketName = await _hot_updater_cli_tools.p.select({
11055
- message: "R2 List",
11056
- options: [...availableBuckets.map((bucket) => ({
11057
- value: bucket.name,
11058
- label: bucket.name
11059
- })), {
11060
- value: createKey,
11061
- label: "Create New R2 Bucket"
11062
- }]
11356
+ if (existingBucketName && !hasExistingBucket) _hot_updater_cli_tools.p.log.warn("Saved Cloudflare R2 bucket was not found. Select a bucket again.");
11357
+ const selectedR2BucketName = await _hot_updater_cli_tools.p.select({
11358
+ initialValue: hasExistingBucket ? existingBucketName : availableBuckets[0]?.name,
11359
+ message: "R2 List",
11360
+ options: [...availableBuckets.map((bucket) => ({
11361
+ value: bucket.name,
11362
+ label: bucket.name
11363
+ })), {
11364
+ value: createKey,
11365
+ label: "Create New R2 Bucket"
11366
+ }]
11367
+ });
11368
+ if (_hot_updater_cli_tools.p.isCancel(selectedR2BucketName)) process.exit(1);
11369
+ if (selectedR2BucketName === createKey) {
11370
+ const prompt = initProvider.inputs.bucketName.prompt;
11371
+ const name = await _hot_updater_cli_tools.p.text({
11372
+ ...(0, _hot_updater_cli_tools.getInitProviderTextPromptValues)(prompt, existingBucketName),
11373
+ message: prompt.message,
11374
+ validate: (value) => value ? void 0 : "R2 bucket name is required"
11063
11375
  });
11064
- if (_hot_updater_cli_tools.p.isCancel(selectedR2BucketName)) process.exit(1);
11065
- selectedBucketName = selectedR2BucketName;
11066
- }
11067
- if (selectedBucketName === createKey) {
11068
- const name = await _hot_updater_cli_tools.p.text({ message: "Enter the name of the new R2 Bucket" });
11069
11376
  if (_hot_updater_cli_tools.p.isCancel(name)) process.exit(1);
11070
- const newR2 = await cf.r2.buckets.create({
11071
- account_id: accountId,
11072
- name
11073
- });
11074
- if (!newR2.name) throw new Error("Failed to create new R2 Bucket");
11075
- selectedBucketName = newR2.name;
11076
- }
11077
- }
11078
- _hot_updater_cli_tools.p.log.info(`Selected R2: ${selectedBucketName}`);
11079
- const existingR2AccessKeyId = getEnvValue(existingEnv, "HOT_UPDATER_CLOUDFLARE_R2_ACCESS_KEY_ID");
11080
- const existingR2SecretAccessKey = getEnvValue(existingEnv, "HOT_UPDATER_CLOUDFLARE_R2_SECRET_ACCESS_KEY");
11081
- let r2AccessKeyId = existingR2AccessKeyId;
11082
- let r2SecretAccessKey = existingR2SecretAccessKey;
11083
- if (r2AccessKeyId && r2SecretAccessKey) _hot_updater_cli_tools.p.log.info("Using existing Cloudflare R2 API credentials.");
11084
- else if (r2AccessKeyId || r2SecretAccessKey) {
11085
- _hot_updater_cli_tools.p.log.warn("Existing Cloudflare R2 API credentials are incomplete.");
11086
- const credentials = await inputR2ApiCredentials({
11087
- accountId,
11088
- bucketName: selectedBucketName,
11089
- accessKeyId: r2AccessKeyId,
11090
- secretAccessKey: r2SecretAccessKey
11091
- });
11092
- r2AccessKeyId = credentials.accessKeyId;
11093
- r2SecretAccessKey = credentials.secretAccessKey;
11094
- } else {
11095
- const credentials = await inputR2ApiCredentials({
11096
- accountId,
11097
- bucketName: selectedBucketName
11098
- });
11099
- r2AccessKeyId = credentials.accessKeyId;
11100
- r2SecretAccessKey = credentials.secretAccessKey;
11377
+ selectedBucketName = name;
11378
+ createBucket = true;
11379
+ } else selectedBucketName = selectedR2BucketName;
11101
11380
  }
11102
- if ((existingBucketName ? { enabled: false } : await cf.r2.buckets.domains.managed.list(selectedBucketName, { account_id: accountId })).enabled) {
11103
- if (await _hot_updater_cli_tools.p.confirm({ message: "Make R2 bucket private?" })) try {
11104
- await _hot_updater_cli_tools.p.tasks([{
11105
- title: "Making R2 bucket private...",
11106
- task: async () => {
11107
- await cf.r2.buckets.domains.managed.update(selectedBucketName, {
11108
- account_id: accountId,
11109
- enabled: false
11110
- });
11111
- }
11112
- }]);
11113
- } catch (e) {
11114
- if (e instanceof Error) _hot_updater_cli_tools.p.log.error(e.message);
11115
- throw e;
11116
- }
11381
+ let managedDomainEnabled;
11382
+ if (!createBucket) try {
11383
+ managedDomainEnabled = (await cf.r2.buckets.domains.managed.list(selectedBucketName, { account_id: accountId })).enabled;
11384
+ } catch (error) {
11385
+ if (error instanceof Error) throw toCloudflareApiError(error, infrastructureCredentialSource);
11386
+ throw new Error(String(error));
11117
11387
  }
11118
11388
  const availableD1List = [];
11119
11389
  try {
@@ -11121,25 +11391,38 @@ const runInit = async ({ build }) => {
11121
11391
  title: "Checking D1 List...",
11122
11392
  task: async () => {
11123
11393
  const d1List = (await cf.d1.database.list({ account_id: accountId })).result ?? [];
11124
- availableD1List.push(...d1List.filter((d1) => d1.name || d1.uuid).map((d1) => ({
11394
+ availableD1List.push(...d1List.flatMap((d1) => d1.name && d1.uuid ? [{
11125
11395
  name: d1.name,
11126
11396
  uuid: d1.uuid
11127
- })));
11397
+ }] : []));
11128
11398
  }
11129
11399
  }]);
11130
- } catch (e) {
11131
- if (e instanceof Error) _hot_updater_cli_tools.p.log.error(e.message);
11132
- throw e;
11400
+ } catch (error) {
11401
+ if (error instanceof Error) throw toCloudflareApiError(error, infrastructureCredentialSource);
11402
+ throw new Error(String(error));
11133
11403
  }
11134
- const existingD1DatabaseId = getEnvValue(existingEnv, "HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID");
11135
- const hasExistingD1Database = availableD1List.some((d1) => d1.uuid === existingD1DatabaseId);
11404
+ const existingD1Database = availableD1List.find((d1) => d1.uuid === existingD1DatabaseId || d1.name === existingD1DatabaseName);
11405
+ let createD1Database = false;
11136
11406
  let selectedD1DatabaseId;
11137
- if (existingD1DatabaseId && hasExistingD1Database) {
11138
- selectedD1DatabaseId = existingD1DatabaseId;
11139
- _hot_updater_cli_tools.p.log.info("Using existing Cloudflare D1 database ID.");
11407
+ let d1DatabaseName;
11408
+ if (nonInteractive && existingD1DatabaseId && existingD1DatabaseName) {
11409
+ const replayResolution = resolveCloudflareReplayD1Database({
11410
+ availableDatabases: availableD1List,
11411
+ databaseId: existingD1DatabaseId,
11412
+ databaseName: existingD1DatabaseName
11413
+ });
11414
+ if (replayResolution.kind === "existing") {
11415
+ selectedD1DatabaseId = replayResolution.database.uuid;
11416
+ d1DatabaseName = replayResolution.database.name;
11417
+ _hot_updater_cli_tools.p.log.info("Using existing Cloudflare D1 database.");
11418
+ } else {
11419
+ createD1Database = true;
11420
+ d1DatabaseName = replayResolution.name;
11421
+ }
11140
11422
  } else {
11141
- if (existingD1DatabaseId) _hot_updater_cli_tools.p.log.warn("Existing Cloudflare D1 database ID was not found. Select a database again.");
11423
+ if ((existingD1DatabaseId || existingD1DatabaseName) && !existingD1Database) _hot_updater_cli_tools.p.log.warn("Existing Cloudflare D1 database ID was not found. Select a database again.");
11142
11424
  const selectedD1 = await _hot_updater_cli_tools.p.select({
11425
+ initialValue: existingD1Database?.uuid ?? availableD1List[0]?.uuid,
11143
11426
  message: "D1 List",
11144
11427
  options: [...availableD1List.map((d1) => ({
11145
11428
  value: d1.uuid,
@@ -11150,43 +11433,149 @@ const runInit = async ({ build }) => {
11150
11433
  }]
11151
11434
  });
11152
11435
  if (_hot_updater_cli_tools.p.isCancel(selectedD1)) process.exit(1);
11153
- selectedD1DatabaseId = selectedD1;
11154
- }
11155
- if (selectedD1DatabaseId === createKey) {
11156
- const name = await _hot_updater_cli_tools.p.text({ message: "Enter the name of the new D1 Database" });
11157
- if (_hot_updater_cli_tools.p.isCancel(name)) process.exit(1);
11158
- const newD1 = await cf.d1.database.create({
11159
- account_id: accountId,
11160
- name
11436
+ if (selectedD1 === createKey) {
11437
+ const prompt = initProvider.inputs.d1DatabaseName.prompt;
11438
+ const name = await _hot_updater_cli_tools.p.text({
11439
+ ...(0, _hot_updater_cli_tools.getInitProviderTextPromptValues)(prompt, existingD1DatabaseName),
11440
+ message: prompt.message,
11441
+ validate: (value) => value ? void 0 : "D1 database name is required"
11442
+ });
11443
+ if (_hot_updater_cli_tools.p.isCancel(name)) process.exit(1);
11444
+ createD1Database = true;
11445
+ d1DatabaseName = name;
11446
+ } else {
11447
+ const selectedDatabase = availableD1List.find((d1) => d1.uuid === selectedD1);
11448
+ if (!selectedDatabase) throw new Error("Failed to get D1 Database");
11449
+ selectedD1DatabaseId = selectedDatabase.uuid;
11450
+ d1DatabaseName = selectedDatabase.name;
11451
+ _hot_updater_cli_tools.p.log.info(`Selected D1: ${selectedD1DatabaseId}`);
11452
+ }
11453
+ }
11454
+ if (nonInteractive && existingR2AccessKeyId && existingR2SecretAccessKey) _hot_updater_cli_tools.p.log.info("Using existing Cloudflare R2 API credentials.");
11455
+ else if (nonInteractive && (existingR2AccessKeyId || existingR2SecretAccessKey)) _hot_updater_cli_tools.p.log.warn("Existing Cloudflare R2 API credentials are incomplete.");
11456
+ const { apiToken, accessKeyId, secretAccessKey, workerName } = await inputCloudflareInitSecrets({
11457
+ accountId,
11458
+ bucketName: selectedBucketName,
11459
+ apiToken: existingApiToken,
11460
+ accessKeyId: existingR2AccessKeyId,
11461
+ secretAccessKey: existingR2SecretAccessKey,
11462
+ workerName: existingWorkerName,
11463
+ nonInteractive
11464
+ });
11465
+ const privacyResolution = resolveR2Privacy({
11466
+ createBucket,
11467
+ managedDomainEnabled,
11468
+ savedPrivateSetting
11469
+ });
11470
+ const isPrivate = nonInteractive && privacyResolution.kind === "resolved" ? privacyResolution.isPrivate : await _hot_updater_cli_tools.p.confirm({
11471
+ message: initProvider.inputs.r2Private.prompt.message,
11472
+ initialValue: privacyResolution.kind === "resolved" ? privacyResolution.isPrivate : true
11473
+ });
11474
+ if (_hot_updater_cli_tools.p.isCancel(isPrivate)) process.exit(1);
11475
+ const databaseCredentialSource = existingApiToken ? envFile ? {
11476
+ envFile,
11477
+ kind: "env-file"
11478
+ } : { kind: "environment" } : { kind: "prompt" };
11479
+ const credentialClient = new cloudflare.Cloudflare({ apiToken });
11480
+ await validateCloudflareApiToken({
11481
+ accountId,
11482
+ probes: [{
11483
+ check: "D1 database access",
11484
+ request: () => credentialClient.d1.database.list({ account_id: accountId }),
11485
+ requiredPermission: CLOUDFLARE_INIT_PERMISSION.d1
11486
+ }],
11487
+ source: databaseCredentialSource,
11488
+ verify: () => verifyCloudflareApiTokenIdentity({
11489
+ accountId,
11490
+ apiToken,
11491
+ verifyAccountToken: (selectedAccountId) => credentialClient.accounts.tokens.verify({ account_id: selectedAccountId }),
11492
+ verifyUserToken: () => credentialClient.user.tokens.verify()
11493
+ })
11494
+ });
11495
+ const resolvedInputs = {
11496
+ ...existingInputs,
11497
+ accessKeyId,
11498
+ accountId,
11499
+ apiToken,
11500
+ bucketName: selectedBucketName,
11501
+ d1DatabaseId: selectedD1DatabaseId,
11502
+ d1DatabaseName,
11503
+ r2Private: String(isPrivate),
11504
+ secretAccessKey,
11505
+ workerName
11506
+ };
11507
+ await (0, _hot_updater_cli_tools.makeEnv)({ ...(0, _hot_updater_cli_tools.getInitProviderEnvVars)({
11508
+ includeConsentInputs: await (0, _hot_updater_cli_tools.confirmInitInputPersistence)({
11509
+ existingEnv: managedEnv,
11510
+ inputs: resolvedInputs,
11511
+ nonInteractive,
11512
+ provider: initProvider
11513
+ }),
11514
+ inputs: resolvedInputs,
11515
+ provider: initProvider
11516
+ }) });
11517
+ if (createBucket) {
11518
+ const newR2 = await runCloudflareApiRequest({
11519
+ request: () => cf.r2.buckets.create({
11520
+ account_id: accountId,
11521
+ name: selectedBucketName
11522
+ }),
11523
+ source: infrastructureCredentialSource
11161
11524
  });
11162
- if (!newD1.uuid || !newD1.name) throw new Error("Failed to create new D1 Database");
11163
- selectedD1DatabaseId = newD1.uuid;
11164
- availableD1List.push({
11165
- name: newD1.name,
11166
- uuid: newD1.uuid
11525
+ if (!newR2.name) throw new Error("Failed to create new R2 Bucket");
11526
+ _hot_updater_cli_tools.p.log.info(`Created R2: ${newR2.name}`);
11527
+ managedDomainEnabled = (await runCloudflareApiRequest({
11528
+ request: () => cf.r2.buckets.domains.managed.list(selectedBucketName, { account_id: accountId }),
11529
+ source: infrastructureCredentialSource
11530
+ })).enabled;
11531
+ } else _hot_updater_cli_tools.p.log.info(`Selected R2: ${selectedBucketName}`);
11532
+ if (managedDomainEnabled === void 0) throw new Error("Failed to resolve the R2 managed domain state.");
11533
+ if (shouldUpdateR2ManagedDomain({
11534
+ isPrivate,
11535
+ managedDomainEnabled
11536
+ })) await _hot_updater_cli_tools.p.tasks([{
11537
+ title: `Making R2 bucket ${isPrivate ? "private" : "public"}...`,
11538
+ task: async () => {
11539
+ await runCloudflareApiRequest({
11540
+ request: () => cf.r2.buckets.domains.managed.update(selectedBucketName, {
11541
+ account_id: accountId,
11542
+ enabled: !isPrivate
11543
+ }),
11544
+ source: infrastructureCredentialSource
11545
+ });
11546
+ }
11547
+ }]);
11548
+ if (createD1Database) {
11549
+ const newD1 = await runCloudflareApiRequest({
11550
+ request: () => cf.d1.database.create({
11551
+ account_id: accountId,
11552
+ name: d1DatabaseName
11553
+ }),
11554
+ source: infrastructureCredentialSource
11167
11555
  });
11168
- _hot_updater_cli_tools.p.log.info(`Created new D1 Database: ${newD1.name} (${newD1.uuid})`);
11169
- } else _hot_updater_cli_tools.p.log.info(`Selected D1: ${selectedD1DatabaseId}`);
11170
- const d1DatabaseName = availableD1List.find((d1) => d1.uuid === selectedD1DatabaseId)?.name;
11171
- if (!d1DatabaseName) throw new Error("Failed to get D1 Database name");
11172
- const subdomains = await cf.workers.subdomains.get({ account_id: accountId });
11173
- const existingWorkerName = getEnvValue(existingEnv, "HOT_UPDATER_CLOUDFLARE_WORKER_NAME");
11174
- const workerName = await deployWorker(auth.oauth_token, accountId, {
11556
+ if (!newD1.uuid || !newD1.name) throw new Error("Failed to create the requested D1 Database");
11557
+ selectedD1DatabaseId = newD1.uuid;
11558
+ d1DatabaseName = newD1.name;
11559
+ _hot_updater_cli_tools.p.log.info(`Created D1 Database: ${newD1.name} (${newD1.uuid})`);
11560
+ }
11561
+ if (!selectedD1DatabaseId) throw new Error("Failed to resolve the D1 Database");
11562
+ await (0, _hot_updater_cli_tools.makeEnv)({
11563
+ [initProvider.inputs.d1DatabaseId.envKey]: selectedD1DatabaseId,
11564
+ [initProvider.inputs.d1DatabaseName.envKey]: d1DatabaseName
11565
+ });
11566
+ const subdomains = await runCloudflareApiRequest({
11567
+ request: () => cf.workers.subdomains.get({ account_id: accountId }),
11568
+ source: infrastructureCredentialSource
11569
+ });
11570
+ await deployWorker(infrastructureApiToken, accountId, {
11571
+ credentialSource: infrastructureCredentialSource,
11175
11572
  d1DatabaseId: selectedD1DatabaseId,
11176
11573
  d1DatabaseName,
11574
+ nonInteractive,
11177
11575
  r2BucketName: selectedBucketName,
11178
- workerName: existingWorkerName
11576
+ workerName
11179
11577
  });
11180
11578
  const configWriteResult = await (0, _hot_updater_cli_tools.writeHotUpdaterConfig)(getConfigScaffold(build));
11181
- await (0, _hot_updater_cli_tools.makeEnv)({
11182
- HOT_UPDATER_CLOUDFLARE_API_TOKEN: apiToken,
11183
- HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID: accountId,
11184
- HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME: selectedBucketName,
11185
- HOT_UPDATER_CLOUDFLARE_R2_ACCESS_KEY_ID: r2AccessKeyId,
11186
- HOT_UPDATER_CLOUDFLARE_R2_SECRET_ACCESS_KEY: r2SecretAccessKey,
11187
- HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID: selectedD1DatabaseId,
11188
- HOT_UPDATER_CLOUDFLARE_WORKER_NAME: workerName
11189
- });
11190
11579
  _hot_updater_cli_tools.p.log.success("Generated '.env.hotupdater' file with Cloudflare settings.");
11191
11580
  if (configWriteResult.status === "created") _hot_updater_cli_tools.p.log.success("Generated 'hot-updater.config.ts' file with Cloudflare settings.");
11192
11581
  else if (configWriteResult.status === "merged") _hot_updater_cli_tools.p.log.success("Updated 'hot-updater.config.ts' file with Cloudflare settings.");