@hot-updater/aws 1.0.0-rc.1 → 1.0.0-rc.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.
@@ -6,7 +6,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
9
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
10
10
  var __copyProps = (to, from, except, desc) => {
11
11
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
12
  key = keys[i];
@@ -17,7 +17,7 @@ var __copyProps = (to, from, except, desc) => {
17
17
  }
18
18
  return to;
19
19
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
21
21
  value: mod,
22
22
  enumerable: true
23
23
  }) : target, mod));
@@ -29,13 +29,13 @@ let node_child_process = require("node:child_process");
29
29
  let node_string_decoder = require("node:string_decoder");
30
30
  let node_util = require("node:util");
31
31
  let node_process = require("node:process");
32
- node_process = __toESM(node_process);
32
+ node_process = __toESM(node_process, 1);
33
33
  let node_tty = require("node:tty");
34
- node_tty = __toESM(node_tty);
34
+ node_tty = __toESM(node_tty, 1);
35
35
  let node_path = require("node:path");
36
- node_path = __toESM(node_path);
36
+ node_path = __toESM(node_path, 1);
37
37
  let path = require("path");
38
- path = __toESM(path);
38
+ path = __toESM(path, 1);
39
39
  let node_timers_promises = require("node:timers/promises");
40
40
  let node_os = require("node:os");
41
41
  let node_events = require("node:events");
@@ -44,6 +44,7 @@ let node_fs = require("node:fs");
44
44
  let node_stream_promises = require("node:stream/promises");
45
45
  let node_stream = require("node:stream");
46
46
  let node_buffer = require("node:buffer");
47
+ let node_crypto = require("node:crypto");
47
48
  let _aws_sdk_client_cloudfront = require("@aws-sdk/client-cloudfront");
48
49
  let _aws_sdk_client_dynamodb = require("@aws-sdk/client-dynamodb");
49
50
  let _aws_sdk_lib_dynamodb = require("@aws-sdk/lib-dynamodb");
@@ -52,12 +53,11 @@ let _hot_updater_plugin_core_internal = require("@hot-updater/plugin-core/intern
52
53
  let _aws_sdk_credential_providers = require("@aws-sdk/credential-providers");
53
54
  let _aws_sdk_client_lambda = require("@aws-sdk/client-lambda");
54
55
  let crypto = require("crypto");
55
- crypto = __toESM(crypto);
56
- let node_crypto = require("node:crypto");
56
+ crypto = __toESM(crypto, 1);
57
57
  let _aws_sdk_client_iam = require("@aws-sdk/client-iam");
58
58
  let _aws_sdk_client_sts = require("@aws-sdk/client-sts");
59
59
  let fs_promises = require("fs/promises");
60
- fs_promises = __toESM(fs_promises);
60
+ fs_promises = __toESM(fs_promises, 1);
61
61
  let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
62
62
  let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
63
63
  //#region ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
@@ -158,7 +158,8 @@ const parseTemplate = ({ templates, expressions, tokens, index, template }) => {
158
158
  const newTokens = concatTokens(tokens, nextTokens, leadingWhitespaces);
159
159
  if (index === expressions.length) return newTokens;
160
160
  const expression = expressions[index];
161
- return concatTokens(newTokens, Array.isArray(expression) ? expression.map((expression) => parseExpression(expression)) : [parseExpression(expression)], trailingWhitespaces);
161
+ const expressionTokens = Array.isArray(expression) ? expression.map((expression) => parseExpression(expression)) : [parseExpression(expression)];
162
+ return concatTokens(newTokens, expressionTokens, trailingWhitespaces);
162
163
  };
163
164
  const splitByWhitespaces = (template, rawTemplate) => {
164
165
  if (rawTemplate.length === 0) return {
@@ -191,7 +192,7 @@ const splitByWhitespaces = (template, rawTemplate) => {
191
192
  trailingWhitespaces
192
193
  };
193
194
  };
194
- const DELIMITERS = new Set([
195
+ const DELIMITERS = /* @__PURE__ */ new Set([
195
196
  " ",
196
197
  " ",
197
198
  "\r",
@@ -243,7 +244,8 @@ const normalizeFdSpecificOptions = (options) => {
243
244
  };
244
245
  const normalizeFdSpecificOption = (options, optionName) => {
245
246
  const optionBaseArray = Array.from({ length: getStdioLength(options) + 1 });
246
- return addDefaultValue$1(normalizeFdSpecificValue(options[optionName], optionBaseArray, optionName), optionName);
247
+ const optionArray = normalizeFdSpecificValue(options[optionName], optionBaseArray, optionName);
248
+ return addDefaultValue$1(optionArray, optionName);
247
249
  };
248
250
  const getStdioLength = ({ stdio }) => Array.isArray(stdio) ? Math.max(stdio.length, STANDARD_STREAMS_ALIASES.length) : STANDARD_STREAMS_ALIASES.length;
249
251
  const normalizeFdSpecificValue = (optionValue, optionArray, optionName) => isPlainObject(optionValue) ? normalizeOptionObject(optionValue, optionArray, optionName) : optionArray.fill(optionValue);
@@ -276,7 +278,7 @@ const addDefaultValue$1 = (optionArray, optionName) => optionArray.map((optionVa
276
278
  const DEFAULT_OPTIONS = {
277
279
  lines: false,
278
280
  buffer: true,
279
- maxBuffer: 1e3 * 1e3 * 100,
281
+ maxBuffer: 1e8,
280
282
  verbose: (0, node_util.debuglog)("execa").enabled ? "full" : "none",
281
283
  stripFinalNewline: true
282
284
  };
@@ -324,7 +326,7 @@ const escapeControlCharacter = (character) => {
324
326
  };
325
327
  const getSpecialCharRegExp = () => {
326
328
  try {
327
- return /* @__PURE__ */ new RegExp("\\p{Separator}|\\p{Other}", "gu");
329
+ return new RegExp("\\p{Separator}|\\p{Other}", "gu");
328
330
  } catch {
329
331
  return /[\s\u0000-\u001F\u007F-\u009F\u00AD]/g;
330
332
  }
@@ -744,11 +746,13 @@ const appendNewline = (printedLine) => printedLine.endsWith("\n") ? printedLine
744
746
  //#endregion
745
747
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/verbose/log.js
746
748
  const verboseLog = ({ type, verboseMessage, fdNumber, verboseInfo, result }) => {
747
- const finalLines = applyVerboseOnLines(getPrintedLines(verboseMessage, getVerboseObject({
749
+ const verboseObject = getVerboseObject({
748
750
  type,
749
751
  result,
750
752
  verboseInfo
751
- })), verboseInfo, fdNumber);
753
+ });
754
+ const printedLines = getPrintedLines(verboseMessage, verboseObject);
755
+ const finalLines = applyVerboseOnLines(printedLines, verboseInfo, fdNumber);
752
756
  if (finalLines !== "") console.warn(finalLines.slice(0, -1));
753
757
  };
754
758
  const getVerboseObject = ({ type, result, verboseInfo: { escapedCommand, commandId, rawOptions: { piped = false, ...options } } }) => ({
@@ -771,7 +775,8 @@ const getPrintedLine = (verboseObject) => {
771
775
  };
772
776
  };
773
777
  const serializeVerboseMessage = (message) => {
774
- return escapeLines(typeof message === "string" ? message : (0, node_util.inspect)(message)).replaceAll(" ", " ".repeat(TAB_SIZE));
778
+ const messageString = typeof message === "string" ? message : (0, node_util.inspect)(message);
779
+ return escapeLines(messageString).replaceAll(" ", " ".repeat(TAB_SIZE));
775
780
  };
776
781
  const TAB_SIZE = 2;
777
782
  //#endregion
@@ -816,7 +821,8 @@ const getDurationMs = (startTime) => Number(node_process.hrtime.bigint() - start
816
821
  const handleCommand = (filePath, rawArguments, rawOptions) => {
817
822
  const startTime = getStartTime();
818
823
  const { command, escapedCommand } = joinCommand(filePath, rawArguments);
819
- const verboseInfo = getVerboseInfo(normalizeFdSpecificOption(rawOptions, "verbose"), escapedCommand, { ...rawOptions });
824
+ const verbose = normalizeFdSpecificOption(rawOptions, "verbose");
825
+ const verboseInfo = getVerboseInfo(verbose, escapedCommand, { ...rawOptions });
820
826
  logCommand(escapedCommand, verboseInfo);
821
827
  return {
822
828
  command,
@@ -937,7 +943,8 @@ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
937
943
  const getNotFoundError = (cmd) => Object.assign(/* @__PURE__ */ new Error(`not found: ${cmd}`), { code: "ENOENT" });
938
944
  const getPathInfo = (cmd, opt) => {
939
945
  const colon = opt.colon || COLON;
940
- const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [...isWindows ? [process.cwd()] : [], ...(opt.path || process.env.PATH || "").split(colon)];
946
+ const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [...isWindows ? [process.cwd()] : [], ...(opt.path || process.env.PATH ||
947
+ /* istanbul ignore next: very unusual */ "").split(colon)];
941
948
  const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
942
949
  const pathExt = isWindows ? pathExtExe.split(colon) : [""];
943
950
  if (isWindows) {
@@ -962,14 +969,17 @@ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
962
969
  const ppRaw = pathEnv[i];
963
970
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
964
971
  const pCmd = path$9.join(pathPart, cmd);
965
- resolve(subStep(!pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd, i, 0));
972
+ const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
973
+ resolve(subStep(p, i, 0));
966
974
  });
967
975
  const subStep = (p, i, ii) => new Promise((resolve, reject) => {
968
976
  if (ii === pathExt.length) return resolve(step(i + 1));
969
977
  const ext = pathExt[ii];
970
978
  isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
971
- if (!er && is) if (opt.all) found.push(p + ext);
972
- else return resolve(p + ext);
979
+ if (!er && is) {
980
+ if (opt.all) found.push(p + ext);
981
+ else return resolve(p + ext);
982
+ }
973
983
  return resolve(subStep(p, i, ii + 1));
974
984
  });
975
985
  });
@@ -987,8 +997,10 @@ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
987
997
  for (let j = 0; j < pathExt.length; j++) {
988
998
  const cur = p + pathExt[j];
989
999
  try {
990
- if (isexe.sync(cur, { pathExt: pathExtExe })) if (opt.all) found.push(cur);
991
- else return cur;
1000
+ if (isexe.sync(cur, { pathExt: pathExtExe })) {
1001
+ if (opt.all) found.push(cur);
1002
+ else return cur;
1003
+ }
992
1004
  } catch (ex) {}
993
1005
  }
994
1006
  }
@@ -1679,7 +1691,7 @@ const normalizeForceKillAfterDelay = (forceKillAfterDelay) => {
1679
1691
  if (!Number.isFinite(forceKillAfterDelay) || forceKillAfterDelay < 0) throw new TypeError(`Expected the \`forceKillAfterDelay\` option to be a non-negative integer, got \`${forceKillAfterDelay}\` (${typeof forceKillAfterDelay})`);
1680
1692
  return forceKillAfterDelay;
1681
1693
  };
1682
- const DEFAULT_FORCE_KILL_TIMEOUT = 1e3 * 5;
1694
+ const DEFAULT_FORCE_KILL_TIMEOUT = 5e3;
1683
1695
  const subprocessKill = ({ kill, options: { forceKillAfterDelay, killSignal }, onInternalError, context, controller }, signalOrError, errorArgument) => {
1684
1696
  const { signal, error } = parseKillArguments(signalOrError, errorArgument, killSignal);
1685
1697
  emitKillError(error, onInternalError);
@@ -1781,7 +1793,7 @@ const handleSerializationError = ({ error, methodName, isSubprocess, message })
1781
1793
  if (isSerializationError(error)) throw new Error(`${getMethodName(methodName, isSubprocess)}'s argument type is invalid: the message cannot be serialized: ${String(message)}.`, { cause: error });
1782
1794
  };
1783
1795
  const isSerializationError = ({ code, message }) => SERIALIZATION_ERROR_CODES.has(code) || SERIALIZATION_ERROR_MESSAGES.some((serializationErrorMessage) => message.includes(serializationErrorMessage));
1784
- const SERIALIZATION_ERROR_CODES = new Set(["ERR_MISSING_ARGS", "ERR_INVALID_ARG_TYPE"]);
1796
+ const SERIALIZATION_ERROR_CODES = /* @__PURE__ */ new Set(["ERR_MISSING_ARGS", "ERR_INVALID_ARG_TYPE"]);
1785
1797
  const SERIALIZATION_ERROR_MESSAGES = [
1786
1798
  "could not be cloned",
1787
1799
  "circular structure",
@@ -1991,7 +2003,8 @@ const isConnected = (anyProcess) => {
1991
2003
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/ipc/strict.js
1992
2004
  const handleSendStrict = ({ anyProcess, channel, isSubprocess, message, strict }) => {
1993
2005
  if (!strict) return message;
1994
- const hasListeners = hasMessageListeners(anyProcess, getIpcEmitter(anyProcess, channel, isSubprocess));
2006
+ const ipcEmitter = getIpcEmitter(anyProcess, channel, isSubprocess);
2007
+ const hasListeners = hasMessageListeners(anyProcess, ipcEmitter);
1995
2008
  return {
1996
2009
  id: count++,
1997
2010
  type: REQUEST_TYPE,
@@ -2223,7 +2236,8 @@ const throwOnGracefulCancel = ({ subprocess, cancelSignal, gracefulCancel, force
2223
2236
  })] : [];
2224
2237
  const sendOnAbort = async ({ subprocess, cancelSignal, forceKillAfterDelay, context, controller: { signal } }) => {
2225
2238
  await onAbortedSignal(cancelSignal, signal);
2226
- await sendAbort(subprocess, getReason(cancelSignal));
2239
+ const reason = getReason(cancelSignal);
2240
+ await sendAbort(subprocess, reason);
2227
2241
  killOnTimeout({
2228
2242
  kill: subprocess.kill,
2229
2243
  forceKillAfterDelay,
@@ -2335,8 +2349,8 @@ Please rename it to ${serializeEncoding(correctEncoding)}.`);
2335
2349
  throw new TypeError(`Invalid option \`encoding: ${serializeEncoding(encoding)}\`.
2336
2350
  Please rename it to one of: ${correctEncodings}.`);
2337
2351
  };
2338
- const TEXT_ENCODINGS = new Set(["utf8", "utf16le"]);
2339
- const BINARY_ENCODINGS = new Set([
2352
+ const TEXT_ENCODINGS = /* @__PURE__ */ new Set(["utf8", "utf16le"]);
2353
+ const BINARY_ENCODINGS = /* @__PURE__ */ new Set([
2340
2354
  "buffer",
2341
2355
  "hex",
2342
2356
  "base64",
@@ -2344,7 +2358,7 @@ const BINARY_ENCODINGS = new Set([
2344
2358
  "latin1",
2345
2359
  "ascii"
2346
2360
  ]);
2347
- const ENCODINGS = new Set([...TEXT_ENCODINGS, ...BINARY_ENCODINGS]);
2361
+ const ENCODINGS = /* @__PURE__ */ new Set([...TEXT_ENCODINGS, ...BINARY_ENCODINGS]);
2348
2362
  const getCorrectEncoding = (encoding) => {
2349
2363
  if (encoding === null) return "buffer";
2350
2364
  if (typeof encoding !== "string") return;
@@ -2391,7 +2405,8 @@ const normalizeOptions = (filePath, rawArguments, rawOptions) => {
2391
2405
  rawOptions.cwd = normalizeCwd(rawOptions.cwd);
2392
2406
  const [processedFile, processedArguments, processedOptions] = handleNodeOption(filePath, rawArguments, rawOptions);
2393
2407
  const { command: file, args: commandArguments, options: initialOptions } = import_cross_spawn.default._parse(processedFile, processedArguments, processedOptions);
2394
- const options = addDefaultOptions(normalizeFdSpecificOptions(initialOptions));
2408
+ const fdOptions = normalizeFdSpecificOptions(initialOptions);
2409
+ const options = addDefaultOptions(fdOptions);
2395
2410
  validateTimeout(options);
2396
2411
  validateEncoding(options);
2397
2412
  validateIpcInputOption(options);
@@ -2592,14 +2607,17 @@ const getStreamContents$1 = async (stream, { init, convertChunk, getSize, trunca
2592
2607
  const state = init();
2593
2608
  state.length = 0;
2594
2609
  try {
2595
- for await (const chunk of asyncIterable) appendChunk({
2596
- convertedChunk: convertChunk[getChunkType(chunk)](chunk, state),
2597
- state,
2598
- getSize,
2599
- truncateChunk,
2600
- addChunk,
2601
- maxBuffer
2602
- });
2610
+ for await (const chunk of asyncIterable) {
2611
+ const convertedChunk = convertChunk[getChunkType(chunk)](chunk, state);
2612
+ appendChunk({
2613
+ convertedChunk,
2614
+ state,
2615
+ getSize,
2616
+ truncateChunk,
2617
+ addChunk,
2618
+ maxBuffer
2619
+ });
2620
+ }
2603
2621
  appendFinalChunk({
2604
2622
  state,
2605
2623
  convertChunk,
@@ -2885,7 +2903,8 @@ const getErrorPrefix = ({ originalError, timedOut, timeout, isMaxBuffer, maxBuff
2885
2903
  const getForcefulSuffix = (isForcefullyTerminated, forceKillAfterDelay) => isForcefullyTerminated ? ` and was forcefully terminated after ${forceKillAfterDelay} milliseconds` : "";
2886
2904
  const getOriginalMessage = (originalError, cwd) => {
2887
2905
  if (originalError instanceof DiscardedError) return;
2888
- const escapedOriginalMessage = escapeLines(fixCwdError(isExecaError(originalError) ? originalError.originalMessage : String(originalError?.message ?? originalError), cwd));
2906
+ const originalMessage = isExecaError(originalError) ? originalError.originalMessage : String(originalError?.message ?? originalError);
2907
+ const escapedOriginalMessage = escapeLines(fixCwdError(originalMessage, cwd));
2889
2908
  return escapedOriginalMessage === "" ? void 0 : escapedOriginalMessage;
2890
2909
  };
2891
2910
  const serializeIpcMessage = (ipcMessage) => typeof ipcMessage === "string" ? ipcMessage : (0, node_util.inspect)(ipcMessage);
@@ -3096,26 +3115,28 @@ function prettyMilliseconds(milliseconds, options) {
3096
3115
  add(Number(parsed.hours), "hour", "h");
3097
3116
  }
3098
3117
  add(Number(parsed.minutes), "minute", "m");
3099
- if (!options.hideSeconds) if (options.separateMilliseconds || options.formatSubMilliseconds || !options.colonNotation && milliseconds < 1e3 && !options.subSecondsAsDecimals) {
3100
- const seconds = Number(parsed.seconds);
3101
- const milliseconds = Number(parsed.milliseconds);
3102
- const microseconds = Number(parsed.microseconds);
3103
- const nanoseconds = Number(parsed.nanoseconds);
3104
- add(seconds, "second", "s");
3105
- if (options.formatSubMilliseconds) {
3106
- add(milliseconds, "millisecond", "ms");
3107
- add(microseconds, "microsecond", "µs");
3108
- add(nanoseconds, "nanosecond", "ns");
3118
+ if (!options.hideSeconds) {
3119
+ if (options.separateMilliseconds || options.formatSubMilliseconds || !options.colonNotation && milliseconds < 1e3 && !options.subSecondsAsDecimals) {
3120
+ const seconds = Number(parsed.seconds);
3121
+ const milliseconds = Number(parsed.milliseconds);
3122
+ const microseconds = Number(parsed.microseconds);
3123
+ const nanoseconds = Number(parsed.nanoseconds);
3124
+ add(seconds, "second", "s");
3125
+ if (options.formatSubMilliseconds) {
3126
+ add(milliseconds, "millisecond", "ms");
3127
+ add(microseconds, "microsecond", "µs");
3128
+ add(nanoseconds, "nanosecond", "ns");
3129
+ } else {
3130
+ const millisecondsAndBelow = milliseconds + microseconds / 1e3 + nanoseconds / 1e6;
3131
+ const millisecondsDecimalDigits = typeof options.millisecondsDecimalDigits === "number" ? options.millisecondsDecimalDigits : 0;
3132
+ const millisecondsString = millisecondsDecimalDigits ? millisecondsAndBelow.toFixed(millisecondsDecimalDigits) : millisecondsAndBelow >= 1 ? Math.round(millisecondsAndBelow) : Math.ceil(millisecondsAndBelow);
3133
+ add(Number.parseFloat(millisecondsString), "millisecond", "ms", millisecondsString);
3134
+ }
3109
3135
  } else {
3110
- const millisecondsAndBelow = milliseconds + microseconds / 1e3 + nanoseconds / 1e6;
3111
- const millisecondsDecimalDigits = typeof options.millisecondsDecimalDigits === "number" ? options.millisecondsDecimalDigits : 0;
3112
- const millisecondsString = millisecondsDecimalDigits ? millisecondsAndBelow.toFixed(millisecondsDecimalDigits) : millisecondsAndBelow >= 1 ? Math.round(millisecondsAndBelow) : Math.ceil(millisecondsAndBelow);
3113
- add(Number.parseFloat(millisecondsString), "millisecond", "ms", millisecondsString);
3136
+ const secondsFixed = floorDecimals((isBigInt ? Number(milliseconds % ONE_DAY_IN_MILLISECONDS) : milliseconds) / 1e3 % 60, typeof options.secondsDecimalDigits === "number" ? options.secondsDecimalDigits : 1);
3137
+ const secondsString = options.keepDecimalsOnWholeSeconds ? secondsFixed : secondsFixed.replace(/\.0+$/, "");
3138
+ add(Number.parseFloat(secondsString), "second", "s", secondsString);
3114
3139
  }
3115
- } else {
3116
- const secondsFixed = floorDecimals((isBigInt ? Number(milliseconds % ONE_DAY_IN_MILLISECONDS) : milliseconds) / 1e3 % 60, typeof options.secondsDecimalDigits === "number" ? options.secondsDecimalDigits : 1);
3117
- const secondsString = options.keepDecimalsOnWholeSeconds ? secondsFixed : secondsFixed.replace(/\.0+$/, "");
3118
- add(Number.parseFloat(secondsString), "second", "s", secondsString);
3119
3140
  }
3120
3141
  if (result.length === 0) return sign + "0" + (options.verbose ? " milliseconds" : "ms");
3121
3142
  const separator = options.colonNotation ? ":" : " ";
@@ -3140,9 +3161,10 @@ const logResult = (result, verboseInfo) => {
3140
3161
  logDuration(result, verboseInfo);
3141
3162
  };
3142
3163
  const logDuration = (result, verboseInfo) => {
3164
+ const verboseMessage = `(done in ${prettyMilliseconds(result.durationMs)})`;
3143
3165
  verboseLog({
3144
3166
  type: "duration",
3145
- verboseMessage: `(done in ${prettyMilliseconds(result.durationMs)})`,
3167
+ verboseMessage,
3146
3168
  verboseInfo,
3147
3169
  result
3148
3170
  });
@@ -3210,10 +3232,10 @@ const isTransformOptions = (value) => isPlainObject(value) && (value.transform !
3210
3232
  const isUrl = (value) => Object.prototype.toString.call(value) === "[object URL]";
3211
3233
  const isRegularUrl = (value) => isUrl(value) && value.protocol !== "file:";
3212
3234
  const isFilePathObject = (value) => isPlainObject(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => FILE_PATH_KEYS.has(key)) && isFilePathString(value.file);
3213
- const FILE_PATH_KEYS = new Set(["file", "append"]);
3235
+ const FILE_PATH_KEYS = /* @__PURE__ */ new Set(["file", "append"]);
3214
3236
  const isFilePathString = (file) => typeof file === "string";
3215
3237
  const isUnknownStdioString = (type, value) => type === "native" && typeof value === "string" && !KNOWN_STDIO_STRINGS.has(value);
3216
- const KNOWN_STDIO_STRINGS = new Set([
3238
+ const KNOWN_STDIO_STRINGS = /* @__PURE__ */ new Set([
3217
3239
  "ipc",
3218
3240
  "ignore",
3219
3241
  "inherit",
@@ -3227,24 +3249,24 @@ const isTransformStream = (value) => isReadableStream(value?.readable) && isWrit
3227
3249
  const isAsyncIterableObject = (value) => isObject(value) && typeof value[Symbol.asyncIterator] === "function";
3228
3250
  const isIterableObject = (value) => isObject(value) && typeof value[Symbol.iterator] === "function";
3229
3251
  const isObject = (value) => typeof value === "object" && value !== null;
3230
- const TRANSFORM_TYPES = new Set([
3252
+ const TRANSFORM_TYPES = /* @__PURE__ */ new Set([
3231
3253
  "generator",
3232
3254
  "asyncGenerator",
3233
3255
  "duplex",
3234
3256
  "webTransform"
3235
3257
  ]);
3236
- const FILE_TYPES = new Set([
3258
+ const FILE_TYPES = /* @__PURE__ */ new Set([
3237
3259
  "fileUrl",
3238
3260
  "filePath",
3239
3261
  "fileNumber"
3240
3262
  ]);
3241
- const SPECIAL_DUPLICATE_TYPES_SYNC = new Set(["fileUrl", "filePath"]);
3242
- const SPECIAL_DUPLICATE_TYPES = new Set([
3263
+ const SPECIAL_DUPLICATE_TYPES_SYNC = /* @__PURE__ */ new Set(["fileUrl", "filePath"]);
3264
+ const SPECIAL_DUPLICATE_TYPES = /* @__PURE__ */ new Set([
3243
3265
  ...SPECIAL_DUPLICATE_TYPES_SYNC,
3244
3266
  "webStream",
3245
3267
  "nodeStream"
3246
3268
  ]);
3247
- const FORBID_DUPLICATE_TYPES = new Set(["webTransform", "duplex"]);
3269
+ const FORBID_DUPLICATE_TYPES = /* @__PURE__ */ new Set(["webTransform", "duplex"]);
3248
3270
  const TYPE_TO_MESSAGE = {
3249
3271
  generator: "a generator",
3250
3272
  asyncGenerator: "an async generator",
@@ -3577,7 +3599,8 @@ const validateDuplicateStreamSync = ({ otherStdioItems, type, value, optionName,
3577
3599
  const getDuplicateStreamInstance = ({ otherStdioItems, type, value, optionName, direction }) => {
3578
3600
  const duplicateStdioItems = otherStdioItems.filter((stdioItem) => hasSameValue(stdioItem, value));
3579
3601
  if (duplicateStdioItems.length === 0) return;
3580
- throwOnDuplicateStream(duplicateStdioItems.find((stdioItem) => stdioItem.direction !== direction), optionName, type);
3602
+ const differentStdioItem = duplicateStdioItems.find((stdioItem) => stdioItem.direction !== direction);
3603
+ throwOnDuplicateStream(differentStdioItem, optionName, type);
3581
3604
  return direction === "output" ? duplicateStdioItems[0].stream : void 0;
3582
3605
  };
3583
3606
  const hasSameValue = ({ type, value }, secondValue) => {
@@ -3586,7 +3609,8 @@ const hasSameValue = ({ type, value }, secondValue) => {
3586
3609
  return value === secondValue;
3587
3610
  };
3588
3611
  const validateDuplicateTransform = ({ otherStdioItems, type, value, optionName }) => {
3589
- throwOnDuplicateStream(otherStdioItems.find(({ value: { transform } }) => transform === value.transform), optionName, type);
3612
+ const duplicateStdioItem = otherStdioItems.find(({ value: { transform } }) => transform === value.transform);
3613
+ throwOnDuplicateStream(duplicateStdioItem, optionName, type);
3590
3614
  };
3591
3615
  const throwOnDuplicateStream = (stdioItem, optionName, type) => {
3592
3616
  if (stdioItem !== void 0) throw new TypeError(`The \`${stdioItem.optionName}\` and \`${optionName}\` options must not target ${TYPE_TO_MESSAGE[type]} that is the same.`);
@@ -3594,13 +3618,14 @@ const throwOnDuplicateStream = (stdioItem, optionName, type) => {
3594
3618
  //#endregion
3595
3619
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/stdio/handle.js
3596
3620
  const handleStdio = (addProperties, options, verboseInfo, isSync) => {
3621
+ const initialFileDescriptors = normalizeStdioOption(options, verboseInfo, isSync).map((stdioOption, fdNumber) => getFileDescriptor({
3622
+ stdioOption,
3623
+ fdNumber,
3624
+ options,
3625
+ isSync
3626
+ }));
3597
3627
  const fileDescriptors = getFinalFileDescriptors({
3598
- initialFileDescriptors: normalizeStdioOption(options, verboseInfo, isSync).map((stdioOption, fdNumber) => getFileDescriptor({
3599
- stdioOption,
3600
- fdNumber,
3601
- options,
3602
- isSync
3603
- })),
3628
+ initialFileDescriptors,
3604
3629
  addProperties,
3605
3630
  options,
3606
3631
  isSync
@@ -3617,13 +3642,14 @@ const getFileDescriptor = ({ stdioOption, fdNumber, options, isSync }) => {
3617
3642
  optionName
3618
3643
  });
3619
3644
  const direction = getStreamDirection(initialStdioItems, fdNumber, optionName);
3620
- const normalizedStdioItems = normalizeTransforms(initialStdioItems.map((stdioItem) => handleNativeStream({
3645
+ const stdioItems = initialStdioItems.map((stdioItem) => handleNativeStream({
3621
3646
  stdioItem,
3622
3647
  isStdioArray,
3623
3648
  fdNumber,
3624
3649
  direction,
3625
3650
  isSync
3626
- })), optionName, direction, options);
3651
+ }));
3652
+ const normalizedStdioItems = normalizeTransforms(stdioItems, optionName, direction, options);
3627
3653
  const objectMode = getFdObjectMode(normalizedStdioItems, direction);
3628
3654
  validateFileObjectMode(normalizedStdioItems, objectMode);
3629
3655
  return {
@@ -3633,7 +3659,8 @@ const getFileDescriptor = ({ stdioOption, fdNumber, options, isSync }) => {
3633
3659
  };
3634
3660
  };
3635
3661
  const initializeStdioItems = ({ stdioOption, fdNumber, options, optionName }) => {
3636
- const stdioItems = filterDuplicates([...(Array.isArray(stdioOption) ? stdioOption : [stdioOption]).map((value) => initializeStdioItem(value, optionName)), ...handleInputOptions(options, fdNumber)]);
3662
+ const initialStdioItems = [...(Array.isArray(stdioOption) ? stdioOption : [stdioOption]).map((value) => initializeStdioItem(value, optionName)), ...handleInputOptions(options, fdNumber)];
3663
+ const stdioItems = filterDuplicates(initialStdioItems);
3637
3664
  const isStdioArray = stdioItems.length > 1;
3638
3665
  validateStdioArray(stdioItems, isStdioArray, optionName);
3639
3666
  validateStreams(stdioItems);
@@ -3652,7 +3679,7 @@ const validateStdioArray = (stdioItems, isStdioArray, optionName) => {
3652
3679
  if (!isStdioArray) return;
3653
3680
  for (const { value, optionName } of stdioItems) if (INVALID_STDIO_ARRAY_OPTIONS.has(value)) throw new Error(`The \`${optionName}\` option must not include \`${value}\`.`);
3654
3681
  };
3655
- const INVALID_STDIO_ARRAY_OPTIONS = new Set(["ignore", "ipc"]);
3682
+ const INVALID_STDIO_ARRAY_OPTIONS = /* @__PURE__ */ new Set(["ignore", "ipc"]);
3656
3683
  const validateStreams = (stdioItems) => {
3657
3684
  for (const stdioItem of stdioItems) validateFileStdio(stdioItem);
3658
3685
  };
@@ -3981,7 +4008,10 @@ const generatorToStream = ({ value, value: { transform, final, writableObjectMod
3981
4008
  const runGeneratorsSync = (chunks, stdioItems, encoding, isInput) => {
3982
4009
  const generators = stdioItems.filter(({ type }) => type === "generator");
3983
4010
  const reversedGenerators = isInput ? generators.reverse() : generators;
3984
- for (const { value, optionName } of reversedGenerators) chunks = runTransformSync(addInternalGenerators(value, encoding, optionName), chunks);
4011
+ for (const { value, optionName } of reversedGenerators) {
4012
+ const generators = addInternalGenerators(value, encoding, optionName);
4013
+ chunks = runTransformSync(generators, chunks);
4014
+ }
3985
4015
  return chunks;
3986
4016
  };
3987
4017
  const addInternalGenerators = ({ transform, final, binary, writableObjectMode, readableObjectMode, preserveNewlines }, encoding, optionName) => {
@@ -4017,7 +4047,8 @@ const addInputOptionSync = (fileDescriptors, fdNumber, options) => {
4017
4047
  const [{ type, optionName }] = allStdioItems;
4018
4048
  throw new TypeError(`Only the \`stdin\` option, not \`${optionName}\`, can be ${TYPE_TO_MESSAGE[type]} with synchronous methods.`);
4019
4049
  }
4020
- options.input = joinToUint8Array(allStdioItems.map(({ contents }) => contents).map((contents) => applySingleInputGeneratorsSync(contents, stdioItems)));
4050
+ const transformedContents = allStdioItems.map(({ contents }) => contents).map((contents) => applySingleInputGeneratorsSync(contents, stdioItems));
4051
+ options.input = joinToUint8Array(transformedContents);
4021
4052
  };
4022
4053
  const applySingleInputGeneratorsSync = (contents, stdioItems) => {
4023
4054
  const newContents = runGeneratorsSync(contents, stdioItems, "utf8", true);
@@ -4032,7 +4063,7 @@ const validateSerializable = (newContents) => {
4032
4063
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/verbose/output.js
4033
4064
  const shouldLogOutput = ({ stdioItems, encoding, verboseInfo, fdNumber }) => fdNumber !== "all" && isFullVerbose(verboseInfo, fdNumber) && !BINARY_ENCODINGS.has(encoding) && fdUsesVerbose(fdNumber) && (stdioItems.some(({ type, value }) => type === "native" && PIPED_STDIO_VALUES.has(value)) || stdioItems.every(({ type }) => TRANSFORM_TYPES.has(type)));
4034
4065
  const fdUsesVerbose = (fdNumber) => fdNumber === 1 || fdNumber === 2;
4035
- const PIPED_STDIO_VALUES = new Set(["pipe", "overlapped"]);
4066
+ const PIPED_STDIO_VALUES = /* @__PURE__ */ new Set(["pipe", "overlapped"]);
4036
4067
  const logLines = async (linesIterable, stream, fdNumber, verboseInfo) => {
4037
4068
  for await (const line of linesIterable) if (!isPipingStream(stream)) logLine(line, fdNumber, verboseInfo);
4038
4069
  };
@@ -4041,9 +4072,10 @@ const logLinesSync = (linesArray, fdNumber, verboseInfo) => {
4041
4072
  };
4042
4073
  const isPipingStream = (stream) => stream._readableState.pipes.length > 0;
4043
4074
  const logLine = (line, fdNumber, verboseInfo) => {
4075
+ const verboseMessage = serializeVerboseMessage(line);
4044
4076
  verboseLog({
4045
4077
  type: "output",
4046
- verboseMessage: serializeVerboseMessage(line),
4078
+ verboseMessage,
4047
4079
  fdNumber,
4048
4080
  verboseInfo
4049
4081
  });
@@ -4069,10 +4101,12 @@ const transformOutputSync = ({ fileDescriptors, syncResult: { output }, options,
4069
4101
  };
4070
4102
  const transformOutputResultSync = ({ result, fileDescriptors, fdNumber, state, outputFiles, isMaxBuffer, verboseInfo }, { buffer, encoding, lines, stripFinalNewline, maxBuffer }) => {
4071
4103
  if (result === null) return;
4072
- const uint8ArrayResult = bufferToUint8Array(truncateMaxBufferSync(result, isMaxBuffer, maxBuffer));
4104
+ const truncatedResult = truncateMaxBufferSync(result, isMaxBuffer, maxBuffer);
4105
+ const uint8ArrayResult = bufferToUint8Array(truncatedResult);
4073
4106
  const { stdioItems, objectMode } = fileDescriptors[fdNumber];
4107
+ const chunks = runOutputGeneratorsSync([uint8ArrayResult], stdioItems, encoding, state);
4074
4108
  const { serializedResult, finalResult = serializedResult } = serializeChunks({
4075
- chunks: runOutputGeneratorsSync([uint8ArrayResult], stdioItems, encoding, state),
4109
+ chunks,
4076
4110
  objectMode,
4077
4111
  encoding,
4078
4112
  lines,
@@ -4196,7 +4230,7 @@ const getResultError = (error, exitCode, signal) => {
4196
4230
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/methods/main-sync.js
4197
4231
  const execaCoreSync = (rawFile, rawArguments, rawOptions) => {
4198
4232
  const { file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors } = handleSyncArguments(rawFile, rawArguments, rawOptions);
4199
- return handleResult(spawnSubprocessSync({
4233
+ const result = spawnSubprocessSync({
4200
4234
  file,
4201
4235
  commandArguments,
4202
4236
  options,
@@ -4205,11 +4239,13 @@ const execaCoreSync = (rawFile, rawArguments, rawOptions) => {
4205
4239
  verboseInfo,
4206
4240
  fileDescriptors,
4207
4241
  startTime
4208
- }), verboseInfo, options);
4242
+ });
4243
+ return handleResult(result, verboseInfo, options);
4209
4244
  };
4210
4245
  const handleSyncArguments = (rawFile, rawArguments, rawOptions) => {
4211
4246
  const { command, escapedCommand, startTime, verboseInfo } = handleCommand(rawFile, rawArguments, rawOptions);
4212
- const { file, commandArguments, options } = normalizeOptions(rawFile, rawArguments, normalizeSyncOptions(rawOptions));
4247
+ const syncOptions = normalizeSyncOptions(rawOptions);
4248
+ const { file, commandArguments, options } = normalizeOptions(rawFile, rawArguments, syncOptions);
4213
4249
  validateSyncOptions(options);
4214
4250
  return {
4215
4251
  file,
@@ -4254,14 +4290,16 @@ const spawnSubprocessSync = ({ file, commandArguments, options, command, escaped
4254
4290
  isMaxBuffer,
4255
4291
  verboseInfo
4256
4292
  });
4293
+ const stdio = output.map((stdioOutput, fdNumber) => stripNewline(stdioOutput, options, fdNumber));
4294
+ const all = stripNewline(getAllSync(output, options), options, "all");
4257
4295
  return getSyncResult({
4258
4296
  error,
4259
4297
  exitCode,
4260
4298
  signal,
4261
4299
  timedOut,
4262
4300
  isMaxBuffer,
4263
- stdio: output.map((stdioOutput, fdNumber) => stripNewline(stdioOutput, options, fdNumber)),
4264
- all: stripNewline(getAllSync(output, options), options, "all"),
4301
+ stdio,
4302
+ all,
4265
4303
  options,
4266
4304
  command,
4267
4305
  escapedCommand,
@@ -4271,7 +4309,8 @@ const spawnSubprocessSync = ({ file, commandArguments, options, command, escaped
4271
4309
  const runSubprocessSync = ({ file, commandArguments, options, command, escapedCommand, fileDescriptors, startTime }) => {
4272
4310
  try {
4273
4311
  addInputOptionsSync(fileDescriptors, options);
4274
- return (0, node_child_process.spawnSync)(file, commandArguments, normalizeSpawnSyncOptions(options));
4312
+ const normalizedOptions = normalizeSpawnSyncOptions(options);
4313
+ return (0, node_child_process.spawnSync)(file, commandArguments, normalizedOptions);
4275
4314
  } catch (error) {
4276
4315
  return makeEarlyError({
4277
4316
  error,
@@ -4485,17 +4524,18 @@ const handleEarlyError = ({ error, command, escapedCommand, fileDescriptors, opt
4485
4524
  writable,
4486
4525
  duplex
4487
4526
  });
4527
+ const earlyError = makeEarlyError({
4528
+ error,
4529
+ command,
4530
+ escapedCommand,
4531
+ fileDescriptors,
4532
+ options,
4533
+ startTime,
4534
+ isSync: false
4535
+ });
4488
4536
  return {
4489
4537
  subprocess,
4490
- promise: handleDummyPromise(makeEarlyError({
4491
- error,
4492
- command,
4493
- escapedCommand,
4494
- fileDescriptors,
4495
- options,
4496
- startTime,
4497
- isSync: false
4498
- }), verboseInfo, options)
4538
+ promise: handleDummyPromise(earlyError, verboseInfo, options)
4499
4539
  };
4500
4540
  };
4501
4541
  const createDummyStreams = (subprocess, fileDescriptors) => {
@@ -4679,8 +4719,10 @@ const endWhenStreamsDone = async ({ passThroughStream, stream, streams, ended, a
4679
4719
  controller.abort();
4680
4720
  updateMaxListeners(passThroughStream, -PASSTHROUGH_LISTENERS_PER_STREAM);
4681
4721
  }
4682
- if (streams.size > 0 && streams.size === ended.size + aborted.size) if (ended.size === 0 && aborted.size > 0) abortStream(passThroughStream);
4683
- else endStream(passThroughStream);
4722
+ if (streams.size > 0 && streams.size === ended.size + aborted.size) {
4723
+ if (ended.size === 0 && aborted.size > 0) abortStream(passThroughStream);
4724
+ else endStream(passThroughStream);
4725
+ }
4684
4726
  };
4685
4727
  const afterMergedStreamFinished = async (onFinished, stream, { signal }) => {
4686
4728
  try {
@@ -4786,7 +4828,10 @@ const pipeOutputAsync = (subprocess, fileDescriptors, controller) => {
4786
4828
  controller
4787
4829
  });
4788
4830
  }
4789
- for (const [outputStream, inputStreams] of pipeGroups.entries()) pipeStreams(inputStreams.length === 1 ? inputStreams[0] : mergeStreams(inputStreams), outputStream);
4831
+ for (const [outputStream, inputStreams] of pipeGroups.entries()) {
4832
+ const inputStream = inputStreams.length === 1 ? inputStreams[0] : mergeStreams(inputStreams);
4833
+ pipeStreams(inputStream, outputStream);
4834
+ }
4790
4835
  };
4791
4836
  const pipeTransform = (subprocess, stream, direction, fdNumber) => {
4792
4837
  if (direction === "output") pipeStreams(subprocess.stdio[fdNumber], stream);
@@ -5275,12 +5320,13 @@ const stopReadingOnStreamEnd = async (onStreamEnd, controller, stream) => {
5275
5320
  }
5276
5321
  };
5277
5322
  const iterateOnStream = ({ stream, controller, binary, shouldEncode, encoding, shouldSplit, preserveNewlines }) => {
5323
+ const onStdoutChunk = (0, node_events.on)(stream, "data", {
5324
+ signal: controller.signal,
5325
+ highWaterMark: HIGH_WATER_MARK,
5326
+ highWatermark: HIGH_WATER_MARK
5327
+ });
5278
5328
  return iterateOnData({
5279
- onStdoutChunk: (0, node_events.on)(stream, "data", {
5280
- signal: controller.signal,
5281
- highWaterMark: HIGH_WATER_MARK,
5282
- highWatermark: HIGH_WATER_MARK
5283
- }),
5329
+ onStdoutChunk,
5284
5330
  controller,
5285
5331
  binary,
5286
5332
  shouldEncode,
@@ -5324,12 +5370,13 @@ const getStreamOutput = async ({ stream, onStreamEnd, fdNumber, encoding, buffer
5324
5370
  await Promise.all([resumeStream(stream), logPromise]);
5325
5371
  return;
5326
5372
  }
5373
+ const stripFinalNewlineValue = getStripFinalNewline(stripFinalNewline, fdNumber);
5327
5374
  const iterable = iterateForResult({
5328
5375
  stream,
5329
5376
  onStreamEnd,
5330
5377
  lines,
5331
5378
  encoding,
5332
- stripFinalNewline: getStripFinalNewline(stripFinalNewline, fdNumber),
5379
+ stripFinalNewline: stripFinalNewlineValue,
5333
5380
  allMixed
5334
5381
  });
5335
5382
  const [output] = await Promise.all([getStreamContents({
@@ -5349,14 +5396,15 @@ const logOutputAsync = async ({ stream, onStreamEnd, fdNumber, encoding, allMixe
5349
5396
  verboseInfo,
5350
5397
  fdNumber
5351
5398
  })) return;
5352
- await logLines(iterateForResult({
5399
+ const linesIterable = iterateForResult({
5353
5400
  stream,
5354
5401
  onStreamEnd,
5355
5402
  lines: true,
5356
5403
  encoding,
5357
5404
  stripFinalNewline: true,
5358
5405
  allMixed
5359
- }), stream, fdNumber, verboseInfo);
5406
+ });
5407
+ await logLines(linesIterable, stream, fdNumber, verboseInfo);
5360
5408
  };
5361
5409
  const resumeStream = async (stream) => {
5362
5410
  await (0, node_timers_promises.setImmediate)();
@@ -5502,9 +5550,10 @@ const getAllMixed = ({ all, stdout, stderr }) => all && stdout && stderr && stdo
5502
5550
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/verbose/ipc.js
5503
5551
  const shouldLogIpc = (verboseInfo) => isFullVerbose(verboseInfo, "ipc");
5504
5552
  const logIpcOutput = (message, verboseInfo) => {
5553
+ const verboseMessage = serializeVerboseMessage(message);
5505
5554
  verboseLog({
5506
5555
  type: "ipc",
5507
- verboseMessage: serializeVerboseMessage(message),
5556
+ verboseMessage,
5508
5557
  fdNumber: "ipc",
5509
5558
  verboseInfo
5510
5559
  });
@@ -5900,14 +5949,15 @@ const onDuplexDestroy = async ({ subprocessStdout, subprocessStdin, subprocess,
5900
5949
  const createIterable = (subprocess, encoding, { from, binary: binaryOption = false, preserveNewlines = false } = {}) => {
5901
5950
  const binary = binaryOption || BINARY_ENCODINGS.has(encoding);
5902
5951
  const subprocessStdout = getFromStream(subprocess, from);
5903
- return iterateOnStdoutData(iterateOnSubprocessStream({
5952
+ const onStdoutData = iterateOnSubprocessStream({
5904
5953
  subprocessStdout,
5905
5954
  subprocess,
5906
5955
  binary,
5907
5956
  shouldEncode: true,
5908
5957
  encoding,
5909
5958
  preserveNewlines
5910
- }), subprocessStdout, subprocess);
5959
+ });
5960
+ return iterateOnStdoutData(onStdoutData, subprocessStdout, subprocess);
5911
5961
  };
5912
5962
  const iterateOnStdoutData = async function* (onStdoutData, subprocessStdout, subprocess) {
5913
5963
  try {
@@ -6067,19 +6117,22 @@ const handlePromise = async ({ subprocess, options, startTime, verboseInfo, file
6067
6117
  });
6068
6118
  controller.abort();
6069
6119
  onInternalError.resolve();
6070
- return handleResult(getAsyncResult({
6120
+ const stdio = stdioResults.map((stdioResult, fdNumber) => stripNewline(stdioResult, options, fdNumber));
6121
+ const all = stripNewline(allResult, options, "all");
6122
+ const result = getAsyncResult({
6071
6123
  errorInfo,
6072
6124
  exitCode,
6073
6125
  signal,
6074
- stdio: stdioResults.map((stdioResult, fdNumber) => stripNewline(stdioResult, options, fdNumber)),
6075
- all: stripNewline(allResult, options, "all"),
6126
+ stdio,
6127
+ all,
6076
6128
  ipcOutput,
6077
6129
  context,
6078
6130
  options,
6079
6131
  command,
6080
6132
  escapedCommand,
6081
6133
  startTime
6082
- }), verboseInfo, options);
6134
+ });
6135
+ return handleResult(result, verboseInfo, options);
6083
6136
  };
6084
6137
  const getAsyncResult = ({ errorInfo, exitCode, signal, stdio, all, ipcOutput, context, options, command, escapedCommand, startTime }) => "error" in errorInfo ? makeError({
6085
6138
  error: errorInfo.error,
@@ -6123,7 +6176,7 @@ const mergeOption = (optionName, boundOptionValue, optionValue) => {
6123
6176
  };
6124
6177
  return optionValue;
6125
6178
  };
6126
- const DEEP_OPTIONS = new Set(["env", ...FD_SPECIFIC_OPTIONS]);
6179
+ const DEEP_OPTIONS = /* @__PURE__ */ new Set(["env", ...FD_SPECIFIC_OPTIONS]);
6127
6180
  //#endregion
6128
6181
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/methods/create.js
6129
6182
  const createExeca = (mapArguments, boundOptions, deepOptions, setBoundExeca) => {
@@ -6150,7 +6203,8 @@ const callBoundExeca = ({ mapArguments, deepOptions = {}, boundOptions = {}, set
6150
6203
  return isSync ? execaCoreSync(file, commandArguments, options) : execaCoreAsync(file, commandArguments, options, createNested);
6151
6204
  };
6152
6205
  const parseArguments = ({ mapArguments, firstArgument, nextArguments, deepOptions, boundOptions }) => {
6153
- const [initialFile, initialArguments, initialOptions] = normalizeParameters(...isTemplateString(firstArgument) ? parseTemplates(firstArgument, nextArguments) : [firstArgument, ...nextArguments]);
6206
+ const callArguments = isTemplateString(firstArgument) ? parseTemplates(firstArgument, nextArguments) : [firstArgument, ...nextArguments];
6207
+ const [initialFile, initialArguments, initialOptions] = normalizeParameters(...callArguments);
6154
6208
  const mergedOptions = mergeOptions(mergeOptions(deepOptions, boundOptions), initialOptions);
6155
6209
  const { file = initialFile, commandArguments = initialArguments, options = mergedOptions, isSync = false } = mapArguments({
6156
6210
  file: initialFile,
@@ -6221,7 +6275,7 @@ const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcEx
6221
6275
  //#endregion
6222
6276
  //#region src/cloudFrontInvalidation.ts
6223
6277
  const DEFAULT_POLL_INTERVAL_MS = 2e3;
6224
- const DEFAULT_TIMEOUT_MS = 300 * 1e3;
6278
+ const DEFAULT_TIMEOUT_MS = 3e5;
6225
6279
  const sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
6226
6280
  const invalidateCloudFront = async (client, distributionId, paths, options) => {
6227
6281
  if (paths.length === 0) return;
@@ -6250,9 +6304,10 @@ const invalidateCloudFront = async (client, distributionId, paths, options) => {
6250
6304
  };
6251
6305
  //#endregion
6252
6306
  //#region src/dynamoDB.ts
6253
- const DYNAMODB_MAX_METADATA_ITEM_BYTES = 8 * 1024;
6254
- const DYNAMODB_MAX_CATALOG_ITEM_BYTES = 400 * 1024;
6307
+ const DYNAMODB_MAX_METADATA_ITEM_BYTES = 8192;
6308
+ const DYNAMODB_MAX_CATALOG_ITEM_BYTES = 409600;
6255
6309
  var DynamoDBMetadataItemSizeError = class extends Error {
6310
+ byteLength;
6256
6311
  name = "DynamoDBMetadataItemSizeError";
6257
6312
  constructor(byteLength) {
6258
6313
  super(`DynamoDB metadata item is ${byteLength} bytes; maximum is ${DYNAMODB_MAX_METADATA_ITEM_BYTES}`);
@@ -6265,6 +6320,7 @@ const boundedDynamoDBMetadataItem = (item) => {
6265
6320
  return item;
6266
6321
  };
6267
6322
  var DynamoDBCatalogItemSizeError = class extends Error {
6323
+ byteLength;
6268
6324
  name = "DynamoDBCatalogItemSizeError";
6269
6325
  constructor(byteLength) {
6270
6326
  super(`DynamoDB catalog item is ${byteLength} bytes; maximum is ${DYNAMODB_MAX_CATALOG_ITEM_BYTES}`);
@@ -6325,7 +6381,6 @@ const parseDynamoDBItem = (value) => {
6325
6381
  version,
6326
6382
  row
6327
6383
  };
6328
- if (typeof gsi1pk !== "string" || typeof gsi1sk !== "string") throw new DynamoDBStoredItemError();
6329
6384
  if (pk === "bundles" && isBundleRow(row)) {
6330
6385
  if (typeof relationCount !== "number" || typeof ownedPatchCount !== "number") throw new DynamoDBStoredItemError();
6331
6386
  return {
@@ -6334,12 +6389,10 @@ const parseDynamoDBItem = (value) => {
6334
6389
  version,
6335
6390
  relation_count: relationCount,
6336
6391
  owned_patch_count: ownedPatchCount,
6337
- gsi1pk,
6338
- gsi1sk,
6339
6392
  row
6340
6393
  };
6341
6394
  }
6342
- if (pk === "bundle_patches" && isPatchRow(row)) return {
6395
+ if (pk === "bundle_patches" && typeof gsi1pk === "string" && typeof gsi1sk === "string" && isPatchRow(row)) return {
6343
6396
  pk,
6344
6397
  sk,
6345
6398
  version,
@@ -6349,7 +6402,6 @@ const parseDynamoDBItem = (value) => {
6349
6402
  };
6350
6403
  throw new DynamoDBStoredItemError();
6351
6404
  };
6352
- const bundlePlatformPartition = (row) => `bundle#${row.platform}`;
6353
6405
  const patchOwnerPartition = (bundleId) => `patch-owner#${bundleId}`;
6354
6406
  const patchOrderKey = (row) => `${row.order_index.toString().padStart(10, "0")}#${row.id}`;
6355
6407
  const toDynamoDBBundleItem = (row, version = 1, relationCount = 0, ownedPatchCount = 0) => ({
@@ -6358,8 +6410,6 @@ const toDynamoDBBundleItem = (row, version = 1, relationCount = 0, ownedPatchCou
6358
6410
  version,
6359
6411
  relation_count: relationCount,
6360
6412
  owned_patch_count: ownedPatchCount,
6361
- gsi1pk: bundlePlatformPartition(row),
6362
- gsi1sk: row.id,
6363
6413
  row
6364
6414
  });
6365
6415
  const toDynamoDBPatchItem = (row, version = 1) => {
@@ -6716,6 +6766,7 @@ const queryOwnerPatchIds = async (store, indexName, bundleId) => {
6716
6766
  })).filter((item) => item.pk === "bundle_patches").map(({ sk }) => sk);
6717
6767
  };
6718
6768
  var DynamoDBTransactionLimitError = class extends Error {
6769
+ actionCount;
6719
6770
  name = "DynamoDBTransactionLimitError";
6720
6771
  constructor(actionCount) {
6721
6772
  super(`DynamoDB transaction requires ${actionCount} actions; maximum is 100`);
@@ -6796,6 +6847,7 @@ const commitDynamoDBTransaction = async (store, actions) => {
6796
6847
  const DYNAMODB_BATCH_GET_ATTEMPTS = 5;
6797
6848
  const DYNAMODB_BATCH_GET_BASE_DELAY_MS = 25;
6798
6849
  var DynamoDBBatchGetExhaustedError = class extends Error {
6850
+ unprocessedKeyCount;
6799
6851
  name = "DynamoDBBatchGetExhaustedError";
6800
6852
  constructor(unprocessedKeyCount) {
6801
6853
  super(`DynamoDB did not process ${unprocessedKeyCount} batch-get keys after ${DYNAMODB_BATCH_GET_ATTEMPTS} attempts`);
@@ -6848,6 +6900,8 @@ const loadMetadataCount = async (store, model) => {
6848
6900
  return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
6849
6901
  };
6850
6902
  var DynamoDBPatchIndexConsistencyError = class extends Error {
6903
+ bundleId;
6904
+ expectedCount;
6851
6905
  name = "DynamoDBPatchIndexConsistencyError";
6852
6906
  constructor(bundleId, expectedCount) {
6853
6907
  super(`DynamoDB patch index did not converge to ${expectedCount} rows for bundle "${bundleId}"`);
@@ -6875,7 +6929,8 @@ const queryCompleteOwnersPatches = async (store, indexName, bundleIds) => {
6875
6929
  let failedOwner = firstOwner;
6876
6930
  for (let attempt = 0; attempt < 3; attempt++) {
6877
6931
  const candidateIdsByOwner = await Promise.all(owners.map(({ sk }) => queryOwnerPatchIds(store, indexName, sk)));
6878
- const patches = await loadPatchItemsById(store, candidateIdsByOwner.flat());
6932
+ const candidateIds = candidateIdsByOwner.flat();
6933
+ const patches = await loadPatchItemsById(store, candidateIds);
6879
6934
  const patchesById = new Map(patches.map((patch) => [patch.sk, patch]));
6880
6935
  const mismatchedOwner = owners.find((owner, ownerIndex) => {
6881
6936
  const ids = candidateIdsByOwner[ownerIndex] ?? [];
@@ -6976,7 +7031,7 @@ const createDynamoDBBundle = async (store, row) => {
6976
7031
  } }]);
6977
7032
  };
6978
7033
  const createDynamoDBPatch = async (store, row) => {
6979
- const bundleIds = [...new Set([row.bundle_id, row.base_bundle_id])];
7034
+ const bundleIds = [.../* @__PURE__ */ new Set([row.bundle_id, row.base_bundle_id])];
6980
7035
  const counter = metadataUpdate(store, { bundle_patches: 1 });
6981
7036
  if (!counter) return;
6982
7037
  await commitDynamoDBTransaction(store, [
@@ -7012,9 +7067,10 @@ const deleteAction = (store, item) => ({ Delete: {
7012
7067
  const deleteDynamoDBPatch = async (store, item) => {
7013
7068
  const counter = metadataUpdate(store, { bundle_patches: -1 });
7014
7069
  if (!counter) return;
7070
+ const bundleIds = [.../* @__PURE__ */ new Set([item.row.bundle_id, item.row.base_bundle_id])];
7015
7071
  await commitDynamoDBTransaction(store, [
7016
7072
  counter,
7017
- ...[...new Set([item.row.bundle_id, item.row.base_bundle_id])].map((id) => updateBundleRelation(store, id, -1, id === item.row.bundle_id ? -1 : 0)),
7073
+ ...bundleIds.map((id) => updateBundleRelation(store, id, -1, id === item.row.bundle_id ? -1 : 0)),
7018
7074
  deleteAction(store, item)
7019
7075
  ]);
7020
7076
  };
@@ -7025,7 +7081,7 @@ const deleteBundle = async (store, bundle, patches) => {
7025
7081
  });
7026
7082
  if (!counter) return;
7027
7083
  const otherEndpointCounts = /* @__PURE__ */ new Map();
7028
- for (const { row } of patches) for (const id of new Set([row.bundle_id, row.base_bundle_id])) {
7084
+ for (const { row } of patches) for (const id of /* @__PURE__ */ new Set([row.bundle_id, row.base_bundle_id])) {
7029
7085
  if (id === bundle.sk) continue;
7030
7086
  const current = otherEndpointCounts.get(id) ?? {
7031
7087
  owned: 0,
@@ -7076,6 +7132,9 @@ const exactDynamoDBField = (where, fieldName) => {
7076
7132
  return typeof value === "string" ? value : void 0;
7077
7133
  };
7078
7134
  const createDynamoDBCrud = (store, updateIndexName) => ({
7135
+ recordInsights: (input) => recordDynamoDBInsightsEvent(store, input),
7136
+ findLatestInsightsEvents: (input) => createDynamoDBInsightsTable(store).findLatestEvents(input),
7137
+ countLatestInsightsEvents: (input) => createDynamoDBInsightsTable(store).countLatestEvents(input),
7079
7138
  async create(input) {
7080
7139
  switch (input.model) {
7081
7140
  case "bundles":
@@ -7232,14 +7291,19 @@ const createDynamoDBCrud = (store, updateIndexName) => ({
7232
7291
  if (count !== void 0) return count;
7233
7292
  }
7234
7293
  switch (input.model) {
7235
- case "bundles": return countDistinctDynamoDBRows((await loadBundleItems(store)).map(({ row }) => row).filter((row) => matchesDynamoDBWhere(row, input.where)), distinctFields(input.distinct));
7294
+ case "bundles": {
7295
+ const rows = (await loadBundleItems(store)).map(({ row }) => row).filter((row) => matchesDynamoDBWhere(row, input.where));
7296
+ return countDistinctDynamoDBRows(rows, distinctFields(input.distinct));
7297
+ }
7236
7298
  case "bundle_patches": {
7237
7299
  const ownerId = exactDynamoDBPatchOwner(input.where);
7238
- return countDistinctDynamoDBRows((ownerId ? await queryCompleteOwnerPatches(store, updateIndexName, ownerId) : (await loadPatchItems(store)).map(({ row }) => row)).filter((row) => matchesDynamoDBWhere(row, input.where)), distinctFields(input.distinct));
7300
+ const rows = (ownerId ? await queryCompleteOwnerPatches(store, updateIndexName, ownerId) : (await loadPatchItems(store)).map(({ row }) => row)).filter((row) => matchesDynamoDBWhere(row, input.where));
7301
+ return countDistinctDynamoDBRows(rows, distinctFields(input.distinct));
7239
7302
  }
7240
7303
  case "releases": {
7241
7304
  const scopeKey = exactDynamoDBField(input.where, "scope_key");
7242
- return countDistinctDynamoDBRows((scopeKey === void 0 ? await loadReleaseItems(store) : await loadReleaseItemsByScope(store, scopeKey)).map(({ row }) => row).filter((row) => matchesDynamoDBWhere(row, input.where)), distinctFields(input.distinct));
7305
+ const rows = (scopeKey === void 0 ? await loadReleaseItems(store) : await loadReleaseItemsByScope(store, scopeKey)).map(({ row }) => row).filter((row) => matchesDynamoDBWhere(row, input.where));
7306
+ return countDistinctDynamoDBRows(rows, distinctFields(input.distinct));
7243
7307
  }
7244
7308
  }
7245
7309
  throw new DynamoDBUnsupportedModelError();
@@ -7257,7 +7321,6 @@ const createDynamoDBCrud = (store, updateIndexName) => ({
7257
7321
  if (ownerId === void 0) break;
7258
7322
  return (await queryCompleteOwnerPatches(store, updateIndexName, ownerId)).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
7259
7323
  }
7260
- break;
7261
7324
  case "channels":
7262
7325
  if (id !== void 0) return (await loadChannelItem(store, id))?.row ?? null;
7263
7326
  return (await loadChannelItems(store)).map(({ row }) => row).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
@@ -7313,6 +7376,7 @@ const createDynamoDBCrud = (store, updateIndexName) => ({
7313
7376
  deleteChannel: (input) => deleteDynamoDBChannel(store, input)
7314
7377
  });
7315
7378
  var DynamoDBDuplicatePatchError = class extends Error {
7379
+ patchId;
7316
7380
  name = "DynamoDBDuplicatePatchError";
7317
7381
  constructor(patchId) {
7318
7382
  super(`DynamoDB bundle mutation contains duplicate patch "${patchId}"`);
@@ -7425,7 +7489,6 @@ const compileAndCommitDynamoDBChanges = async (store, input) => {
7425
7489
  const originalApiKeys = /* @__PURE__ */ new Map();
7426
7490
  const apiKeys = /* @__PURE__ */ new Map();
7427
7491
  const apiKeyHashes = /* @__PURE__ */ new Map();
7428
- const insights = /* @__PURE__ */ new Map();
7429
7492
  const rememberApiKey = (value) => {
7430
7493
  if (value === null || apiKeys.has(value.row.id)) return;
7431
7494
  originalApiKeys.set(value.row.id, value);
@@ -7548,48 +7611,40 @@ const compileAndCommitDynamoDBChanges = async (store, input) => {
7548
7611
  patches.set(change.row.id, change.row);
7549
7612
  } else for (const [id, patch] of patches) if (patch.bundle_id === change.where.bundleId) patches.delete(id);
7550
7613
  break;
7551
- case "insights": {
7552
- const key = insightsSortKey(change.row);
7553
- if (insights.has(key)) throw new DynamoDBCommitStateError(`Insights event "${change.row.id}" is duplicated`);
7554
- insights.set(key, change.row);
7555
- break;
7614
+ case "apiKeys": if (change.operation === "insert") {
7615
+ rememberApiKey(await loadApiKeyByHash(store, change.row.hash));
7616
+ if (apiKeyHashes.has(change.row.hash)) break;
7617
+ rememberApiKey(await loadApiKey(store, change.row.id));
7618
+ if (apiKeys.has(change.row.id)) throw new DynamoDBCommitStateError(`API key id "${change.row.id}" already exists`);
7619
+ const inserted = {
7620
+ row: change.row,
7621
+ version: 1
7622
+ };
7623
+ apiKeys.set(change.row.id, inserted);
7624
+ apiKeyHashes.set(change.row.hash, change.row.id);
7625
+ } else {
7626
+ rememberApiKey(await loadApiKey(store, change.where.id));
7627
+ const current = apiKeys.get(change.where.id);
7628
+ if (current === void 0) return {
7629
+ committed: false,
7630
+ conflict: {
7631
+ changeIndex,
7632
+ reason: "not_found"
7633
+ }
7634
+ };
7635
+ apiKeys.set(change.where.id, {
7636
+ row: {
7637
+ ...current.row,
7638
+ revoked_at_ms: change.update.revokedAtMs
7639
+ },
7640
+ version: current.version
7641
+ });
7556
7642
  }
7557
- case "apiKeys":
7558
- if (change.operation === "insert") {
7559
- rememberApiKey(await loadApiKeyByHash(store, change.row.hash));
7560
- if (apiKeyHashes.has(change.row.hash)) break;
7561
- rememberApiKey(await loadApiKey(store, change.row.id));
7562
- if (apiKeys.has(change.row.id)) throw new DynamoDBCommitStateError(`API key id "${change.row.id}" already exists`);
7563
- const inserted = {
7564
- row: change.row,
7565
- version: 1
7566
- };
7567
- apiKeys.set(change.row.id, inserted);
7568
- apiKeyHashes.set(change.row.hash, change.row.id);
7569
- } else {
7570
- rememberApiKey(await loadApiKey(store, change.where.id));
7571
- const current = apiKeys.get(change.where.id);
7572
- if (current === void 0) return {
7573
- committed: false,
7574
- conflict: {
7575
- changeIndex,
7576
- reason: "not_found"
7577
- }
7578
- };
7579
- apiKeys.set(change.where.id, {
7580
- row: {
7581
- ...current.row,
7582
- revoked_at_ms: change.update.revokedAtMs
7583
- },
7584
- version: current.version
7585
- });
7586
- }
7587
- break;
7588
7643
  }
7589
7644
  const relationCounts = /* @__PURE__ */ new Map();
7590
7645
  const ownedPatchCounts = /* @__PURE__ */ new Map();
7591
7646
  for (const patch of patches.values()) {
7592
- for (const id of new Set([patch.bundle_id, patch.base_bundle_id])) relationCounts.set(id, (relationCounts.get(id) ?? 0) + 1);
7647
+ for (const id of /* @__PURE__ */ new Set([patch.bundle_id, patch.base_bundle_id])) relationCounts.set(id, (relationCounts.get(id) ?? 0) + 1);
7593
7648
  ownedPatchCounts.set(patch.bundle_id, (ownedPatchCounts.get(patch.bundle_id) ?? 0) + 1);
7594
7649
  }
7595
7650
  const channelReferenceCounts = /* @__PURE__ */ new Map();
@@ -7698,7 +7753,7 @@ const compileAndCommitDynamoDBChanges = async (store, input) => {
7698
7753
  ...original ? { ExpressionAttributeValues: { ":version": original.version } } : {}
7699
7754
  } });
7700
7755
  }
7701
- const changedReleaseIds = new Set([...new Set([...originalReleases.keys(), ...releases.keys()])].filter((id) => {
7756
+ const changedReleaseIds = new Set([.../* @__PURE__ */ new Set([...originalReleases.keys(), ...releases.keys()])].filter((id) => {
7702
7757
  const original = originalReleases.get(id)?.row;
7703
7758
  const next = releases.get(id);
7704
7759
  return original === void 0 || next === void 0 || !rowsEqual(original, next);
@@ -7740,17 +7795,6 @@ const compileAndCommitDynamoDBChanges = async (store, input) => {
7740
7795
  bundle_patches: patches.size - originalPatches.size
7741
7796
  });
7742
7797
  if (counter !== void 0) actions.push(counter);
7743
- for (const [key, row] of insights) actions.push({ Put: {
7744
- TableName: store.tableName,
7745
- Item: boundedDynamoDBMetadataItem({
7746
- pk: DYNAMODB_INSIGHTS_PARTITION,
7747
- sk: key,
7748
- version: 1,
7749
- row
7750
- }),
7751
- ConditionExpression: "attribute_not_exists(#pk)",
7752
- ExpressionAttributeNames: { "#pk": "pk" }
7753
- } });
7754
7798
  for (const [id, current] of apiKeys) {
7755
7799
  const original = originalApiKeys.get(id);
7756
7800
  if (original !== void 0 && rowsEqual(original.row, current.row)) continue;
@@ -7785,13 +7829,22 @@ const createDynamoDBCommit = (store) => async (input) => {
7785
7829
  }
7786
7830
  };
7787
7831
  const DYNAMODB_INSIGHTS_PARTITION = "bundle_events";
7832
+ const DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION = "_hot-updater#insights-installations";
7833
+ const DYNAMODB_INSIGHTS_EVENT_IDS_PARTITION = "_hot-updater#insights-event-ids";
7834
+ const DYNAMODB_INSIGHTS_BUNDLE_PREFIX = "_hot-updater#insights-bundle#";
7788
7835
  const DYNAMODB_API_KEY_PARTITION = "api_keys";
7789
7836
  const DYNAMODB_API_KEY_HASH_PARTITION = "_hot-updater#api-key-hashes";
7837
+ const DYNAMODB_INSIGHTS_MOVEMENT_PREFIX = "_hot-updater#insights-movement#";
7838
+ const DYNAMODB_INSIGHTS_USER_PREFIX = "_hot-updater#insights-user#";
7839
+ const DYNAMODB_INSIGHTS_SCOPE_PREFIX = "_hot-updater#insights-scope#";
7840
+ const DYNAMODB_INSIGHTS_RECORD_ATTEMPTS = 3;
7790
7841
  const hasValidBundleEventShape = (value) => {
7791
7842
  const type = field(value, "type");
7792
7843
  const fromBundleId = field(value, "from_bundle_id");
7793
- const updateStrategy = field(value, "update_strategy");
7794
- return (type === "UPDATE_APPLIED" || type === "RECOVERED" || type === "RELEASE_ADOPTED") && typeof fromBundleId === "string" && (updateStrategy === "fingerprint" || updateStrategy === "appVersion") || type === "UNCHANGED" && fromBundleId === null && updateStrategy === null;
7844
+ const metadata = field(value, "metadata");
7845
+ if (!(0, _hot_updater_plugin_core.isDatabaseBundleEventMetadata)(metadata)) return false;
7846
+ const updateStrategy = metadata.update_strategy;
7847
+ return (type === "UPDATE_DOWNLOADED" || type === "UPDATE_APPLIED" || type === "RECOVERED") && typeof fromBundleId === "string" && (updateStrategy === "fingerprint" || updateStrategy === "appVersion") || type === "UNCHANGED" && fromBundleId === null && updateStrategy === null;
7795
7848
  };
7796
7849
  const isBundleEventRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && typeof field(value, "install_id") === "string" && isNullableString(field(value, "from_release_id")) && isNullableString(field(value, "to_release_id")) && typeof field(value, "to_bundle_id") === "string" && (field(value, "platform") === "ios" || field(value, "platform") === "android") && typeof field(value, "received_at_ms") === "number" && hasValidBundleEventShape(value);
7797
7850
  const isApiKeyRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && typeof field(value, "hash") === "string" && typeof field(value, "name") === "string" && typeof field(value, "prefix") === "string" && field(value, "role") === "client" && typeof field(value, "created_at_ms") === "number" && (field(value, "revoked_at_ms") === null || typeof field(value, "revoked_at_ms") === "number");
@@ -7804,51 +7857,302 @@ const parseOfficialRowItem = (value, partition, isRow) => {
7804
7857
  };
7805
7858
  const timestampSortKey = (timestampMs) => Math.trunc(timestampMs).toString().padStart(16, "0");
7806
7859
  const insightsSortKey = (row) => `${timestampSortKey(row.received_at_ms)}#${row.id}`;
7807
- const createDynamoDBInsightsTable = (store) => ({
7808
- async append(row) {
7809
- await store.client.send(new _aws_sdk_lib_dynamodb.PutCommand({
7860
+ const insightsMovementPartition = (installId) => `${DYNAMODB_INSIGHTS_MOVEMENT_PREFIX}${installId}`;
7861
+ const insightsUserPartition = (userId) => `${DYNAMODB_INSIGHTS_USER_PREFIX}${userId}`;
7862
+ const insightsScopePartition = (scope) => `${DYNAMODB_INSIGHTS_SCOPE_PREFIX}${(0, node_crypto.createHash)("sha256").update(JSON.stringify([scope.platform, scope.channel]), "utf8").digest("hex")}`;
7863
+ const toInsightsScopeItem = (row) => ({
7864
+ pk: insightsScopePartition(row),
7865
+ sk: row.install_id,
7866
+ received_at_ms: row.received_at_ms,
7867
+ type: row.type,
7868
+ from_bundle_id: row.from_bundle_id,
7869
+ to_bundle_id: row.to_bundle_id
7870
+ });
7871
+ const insightsBundlePartition = (filter) => {
7872
+ const scope = JSON.stringify([
7873
+ filter.platform,
7874
+ filter.channel,
7875
+ filter.type,
7876
+ filter.type === "RECOVERED" ? filter.fromBundleId : filter.toBundleId
7877
+ ]);
7878
+ return `${DYNAMODB_INSIGHTS_BUNDLE_PREFIX}${(0, node_crypto.createHash)("sha256").update(scope, "utf8").digest("hex")}`;
7879
+ };
7880
+ const toInsightsBundleItem = (row) => boundedDynamoDBMetadataItem({
7881
+ pk: insightsBundlePartition({
7882
+ platform: row.platform,
7883
+ channel: row.channel,
7884
+ ...row.type === "RECOVERED" ? {
7885
+ type: row.type,
7886
+ fromBundleId: row.from_bundle_id
7887
+ } : {
7888
+ type: row.type,
7889
+ toBundleId: row.to_bundle_id
7890
+ }
7891
+ }),
7892
+ sk: insightsSortKey(row),
7893
+ version: 1,
7894
+ row
7895
+ });
7896
+ const toInsightsEventItem = (row) => {
7897
+ const orderKey = insightsSortKey(row);
7898
+ return boundedDynamoDBMetadataItem({
7899
+ pk: DYNAMODB_INSIGHTS_PARTITION,
7900
+ sk: orderKey,
7901
+ version: 1,
7902
+ row,
7903
+ ...(0, _hot_updater_plugin_core.isInsightsMovementEvent)(row) ? {
7904
+ gsi1pk: insightsMovementPartition(row.install_id),
7905
+ gsi1sk: orderKey
7906
+ } : {}
7907
+ });
7908
+ };
7909
+ const toInsightsInstallationItem = (row) => boundedDynamoDBMetadataItem({
7910
+ pk: DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION,
7911
+ sk: row.install_id,
7912
+ order_key: insightsSortKey(row),
7913
+ version: 1,
7914
+ row
7915
+ });
7916
+ const toInsightsUserItem = (row) => boundedDynamoDBMetadataItem({
7917
+ pk: insightsUserPartition(row.user_id),
7918
+ sk: row.install_id,
7919
+ order_key: insightsSortKey(row),
7920
+ version: 1,
7921
+ row
7922
+ });
7923
+ const parseInsightsInstallationItem = (value, partition) => {
7924
+ const row = value.row;
7925
+ if (value.pk !== partition || typeof value.sk !== "string" || typeof value.order_key !== "string" || value.version !== 1 || !isBundleEventRow(row) || value.sk !== row.install_id || value.order_key !== insightsSortKey(row)) throw new DynamoDBStoredItemError();
7926
+ return {
7927
+ ...value,
7928
+ row
7929
+ };
7930
+ };
7931
+ const loadInsightsInstallationItem = async (store, installId) => {
7932
+ const { Item } = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
7933
+ TableName: store.tableName,
7934
+ Key: {
7935
+ pk: DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION,
7936
+ sk: installId
7937
+ },
7938
+ ConsistentRead: true
7939
+ }));
7940
+ return Item === void 0 ? null : parseInsightsInstallationItem(Item, DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION);
7941
+ };
7942
+ const advancesInsightsInstallation = (row, current) => row.received_at_ms > current.received_at_ms || row.received_at_ms === current.received_at_ms && row.id > current.id;
7943
+ const recordDynamoDBInsightsEvent = async (store, { event: row }) => {
7944
+ const next = row;
7945
+ const eventItem = toInsightsEventItem(row);
7946
+ const bundleItem = toInsightsBundleItem(row);
7947
+ const identityKey = {
7948
+ pk: DYNAMODB_INSIGHTS_EVENT_IDS_PARTITION,
7949
+ sk: row.id
7950
+ };
7951
+ for (let attempt = 0; attempt < DYNAMODB_INSIGHTS_RECORD_ATTEMPTS; attempt++) {
7952
+ const { Item: accepted } = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
7810
7953
  TableName: store.tableName,
7811
- Item: boundedDynamoDBMetadataItem({
7812
- pk: DYNAMODB_INSIGHTS_PARTITION,
7813
- sk: insightsSortKey(row),
7814
- version: 1,
7815
- row
7816
- }),
7817
- ConditionExpression: "attribute_not_exists(#pk)",
7818
- ExpressionAttributeNames: { "#pk": "pk" }
7954
+ Key: identityKey,
7955
+ ConsistentRead: true
7819
7956
  }));
7957
+ if (accepted !== void 0) return;
7958
+ const current = await loadInsightsInstallationItem(store, row.install_id);
7959
+ const actions = [
7960
+ { Put: {
7961
+ TableName: store.tableName,
7962
+ Item: identityKey,
7963
+ ConditionExpression: "attribute_not_exists(#pk)",
7964
+ ExpressionAttributeNames: { "#pk": "pk" }
7965
+ } },
7966
+ { Put: {
7967
+ TableName: store.tableName,
7968
+ Item: eventItem
7969
+ } },
7970
+ { Put: {
7971
+ TableName: store.tableName,
7972
+ Item: bundleItem
7973
+ } }
7974
+ ];
7975
+ if (current === null || advancesInsightsInstallation(next, current.row)) {
7976
+ actions.push({ Put: {
7977
+ TableName: store.tableName,
7978
+ Item: toInsightsInstallationItem(next),
7979
+ ConditionExpression: current === null ? "attribute_not_exists(#pk)" : "#orderKey = :currentOrderKey",
7980
+ ExpressionAttributeNames: current === null ? { "#pk": "pk" } : { "#orderKey": "order_key" },
7981
+ ...current === null ? {} : { ExpressionAttributeValues: { ":currentOrderKey": current.order_key } }
7982
+ } });
7983
+ if (current !== null && insightsScopePartition(current.row) !== insightsScopePartition(next)) actions.push({ Delete: {
7984
+ TableName: store.tableName,
7985
+ Key: {
7986
+ pk: insightsScopePartition(current.row),
7987
+ sk: current.row.install_id
7988
+ }
7989
+ } });
7990
+ actions.push({ Put: {
7991
+ TableName: store.tableName,
7992
+ Item: toInsightsScopeItem(next)
7993
+ } });
7994
+ if (current !== null && current.row.user_id !== null && current.row.user_id !== next.user_id) actions.push({ Delete: {
7995
+ TableName: store.tableName,
7996
+ Key: {
7997
+ pk: insightsUserPartition(current.row.user_id),
7998
+ sk: current.row.install_id
7999
+ }
8000
+ } });
8001
+ if (next.user_id !== null) actions.push({ Put: {
8002
+ TableName: store.tableName,
8003
+ Item: toInsightsUserItem({
8004
+ ...next,
8005
+ user_id: next.user_id
8006
+ })
8007
+ } });
8008
+ }
8009
+ try {
8010
+ await commitDynamoDBTransaction(store, actions);
8011
+ return;
8012
+ } catch (error) {
8013
+ if (!isDynamoDBTransactionConflict(error)) throw error;
8014
+ const { Item } = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
8015
+ TableName: store.tableName,
8016
+ Key: identityKey,
8017
+ ConsistentRead: true
8018
+ }));
8019
+ if (Item !== void 0) return;
8020
+ if (attempt === 2) throw error;
8021
+ }
8022
+ }
8023
+ };
8024
+ const insightsEventRange = (input) => {
8025
+ const upperExclusive = input.after ? `${timestampSortKey(input.after.receivedAtMs)}#${input.after.id}` : `${timestampSortKey(input.beforeReceivedAtMs)}#`;
8026
+ const upper = `${upperExclusive.slice(0, -1)}${String.fromCharCode(upperExclusive.charCodeAt(upperExclusive.length - 1) - 1)}~`;
8027
+ const movement = input.filter.kind === "installationMovement";
8028
+ const partition = movement ? insightsMovementPartition(input.filter.installId) : input.filter.kind === "bundle" ? insightsBundlePartition(input.filter) : DYNAMODB_INSIGHTS_PARTITION;
8029
+ return {
8030
+ partition,
8031
+ query: {
8032
+ ...movement ? { IndexName: DYNAMODB_UPDATE_INDEX_NAME } : { ConsistentRead: true },
8033
+ KeyConditionExpression: "#partition = :partition AND #order BETWEEN :since AND :upper",
8034
+ ExpressionAttributeNames: {
8035
+ "#partition": movement ? "gsi1pk" : "pk",
8036
+ "#order": movement ? "gsi1sk" : "sk"
8037
+ },
8038
+ ExpressionAttributeValues: {
8039
+ ":partition": partition,
8040
+ ":since": `${timestampSortKey(input.sinceMs ?? 0)}#`,
8041
+ ":upper": upper
8042
+ }
8043
+ }
8044
+ };
8045
+ };
8046
+ const createDynamoDBInsightsTable = (store) => ({
8047
+ recordEvent: (input) => recordDynamoDBInsightsEvent(store, input),
8048
+ async listEvents(input) {
8049
+ if ((input.sinceMs ?? 0) === input.beforeReceivedAtMs) return [];
8050
+ const range = insightsEventRange(input);
8051
+ const rows = [];
8052
+ let exclusiveStartKey;
8053
+ do {
8054
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
8055
+ TableName: store.tableName,
8056
+ ...range.query,
8057
+ ExclusiveStartKey: exclusiveStartKey,
8058
+ Limit: input.limit - rows.length,
8059
+ ScanIndexForward: false
8060
+ }));
8061
+ rows.push(...(page.Items ?? []).slice(0, input.limit - rows.length).map((item) => parseOfficialRowItem(item, input.filter.kind === "bundle" ? range.partition : DYNAMODB_INSIGHTS_PARTITION, isBundleEventRow).row));
8062
+ exclusiveStartKey = page.LastEvaluatedKey;
8063
+ } while (rows.length < input.limit && exclusiveStartKey !== void 0);
8064
+ return rows;
7820
8065
  },
7821
- async scan(input) {
7822
- if (input.limit <= 0) return [];
7823
- if (input.after !== void 0 && input.after.receivedAtMs >= input.beforeReceivedAtMs) return [];
8066
+ async findLatestEvents(input) {
8067
+ if ("installId" in input) {
8068
+ const stored = await loadInsightsInstallationItem(store, input.installId);
8069
+ return stored === null ? [] : [stored.row];
8070
+ }
8071
+ const partition = insightsUserPartition(input.userId);
7824
8072
  const rows = [];
7825
- const afterKey = input.after === void 0 ? void 0 : `${timestampSortKey(input.after.receivedAtMs)}#${input.after.id}`;
7826
8073
  let exclusiveStartKey;
7827
8074
  do {
7828
8075
  const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
7829
8076
  TableName: store.tableName,
8077
+ ConsistentRead: true,
7830
8078
  ExclusiveStartKey: exclusiveStartKey,
7831
- KeyConditionExpression: afterKey === void 0 ? "#pk = :pk AND #sk < :before" : "#pk = :pk AND #sk BETWEEN :after AND :before",
8079
+ KeyConditionExpression: input.afterInstallId === void 0 ? "#pk = :pk" : "#pk = :pk AND #sk > :after",
7832
8080
  ExpressionAttributeNames: {
7833
8081
  "#pk": "pk",
7834
- "#sk": "sk"
8082
+ ...input.afterInstallId === void 0 ? {} : { "#sk": "sk" }
7835
8083
  },
7836
8084
  ExpressionAttributeValues: {
7837
- ":before": `${timestampSortKey(input.beforeReceivedAtMs)}#`,
7838
- ":pk": DYNAMODB_INSIGHTS_PARTITION,
7839
- ...afterKey === void 0 ? {} : { ":after": afterKey }
8085
+ ":pk": partition,
8086
+ ...input.afterInstallId === void 0 ? {} : { ":after": input.afterInstallId }
7840
8087
  },
7841
- Limit: input.limit - rows.length + (afterKey === void 0 ? 0 : 1),
8088
+ Limit: input.limit - rows.length,
7842
8089
  ScanIndexForward: true
7843
8090
  }));
7844
- for (const item of page.Items ?? []) {
7845
- if (item.sk === afterKey) continue;
7846
- rows.push(parseOfficialRowItem(item, DYNAMODB_INSIGHTS_PARTITION, isBundleEventRow).row);
7847
- if (rows.length === input.limit) return rows;
8091
+ for (const item of (page.Items ?? []).slice(0, input.limit - rows.length)) {
8092
+ const stored = parseInsightsInstallationItem(item, partition);
8093
+ const current = await loadInsightsInstallationItem(store, stored.row.install_id);
8094
+ if (current?.row.user_id === input.userId) rows.push(current.row);
7848
8095
  }
7849
8096
  exclusiveStartKey = page.LastEvaluatedKey;
7850
- } while (exclusiveStartKey !== void 0);
8097
+ } while (rows.length < input.limit && exclusiveStartKey !== void 0);
7851
8098
  return rows;
8099
+ },
8100
+ async countLatestEvents(input) {
8101
+ const bundleConditions = input.bundle?.map((bundle, group) => `#bundle${group} = :bundle${group} AND #type IN (${bundle.types.map((_, i) => `:type${group}_${i}`).join(", ")})`);
8102
+ const bundleFilter = bundleConditions === void 0 ? "" : ` AND ${bundleConditions.length === 1 ? bundleConditions[0] : `(${bundleConditions.join(" OR ")})`}`;
8103
+ let count = 0;
8104
+ let exclusiveStartKey;
8105
+ do {
8106
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
8107
+ TableName: store.tableName,
8108
+ ConsistentRead: true,
8109
+ ExclusiveStartKey: exclusiveStartKey,
8110
+ KeyConditionExpression: "#pk = :pk",
8111
+ FilterExpression: "#received >= :since" + bundleFilter,
8112
+ ExpressionAttributeNames: {
8113
+ "#pk": "pk",
8114
+ "#received": "received_at_ms",
8115
+ ...input.bundle === void 0 ? {} : {
8116
+ ...Object.fromEntries(input.bundle.map((bundle, group) => [`#bundle${group}`, bundle.field])),
8117
+ "#type": "type"
8118
+ }
8119
+ },
8120
+ ExpressionAttributeValues: {
8121
+ ":pk": insightsScopePartition(input),
8122
+ ":since": input.sinceMs,
8123
+ ...input.bundle === void 0 ? {} : Object.fromEntries(input.bundle.flatMap((bundle, group) => [[`:bundle${group}`, bundle.value], ...bundle.types.map((type, i) => [`:type${group}_${i}`, type])]))
8124
+ },
8125
+ Select: "COUNT",
8126
+ ScanIndexForward: true
8127
+ }));
8128
+ count += page.Count ?? 0;
8129
+ exclusiveStartKey = page.LastEvaluatedKey;
8130
+ } while (exclusiveStartKey !== void 0);
8131
+ return count;
8132
+ },
8133
+ async countEvents(input) {
8134
+ if (input.sinceMs === input.beforeReceivedAtMs) return 0;
8135
+ const { query } = insightsEventRange({
8136
+ ...input,
8137
+ filter: {
8138
+ kind: "bundle",
8139
+ ...input.filter
8140
+ },
8141
+ limit: 1
8142
+ });
8143
+ let count = 0;
8144
+ let exclusiveStartKey;
8145
+ do {
8146
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
8147
+ TableName: store.tableName,
8148
+ ...query,
8149
+ ExclusiveStartKey: exclusiveStartKey,
8150
+ Select: "COUNT"
8151
+ }));
8152
+ count += page.Count ?? 0;
8153
+ exclusiveStartKey = page.LastEvaluatedKey;
8154
+ } while (exclusiveStartKey !== void 0);
8155
+ return count;
7852
8156
  }
7853
8157
  });
7854
8158
  const apiKeyItem = (row, version) => ({
@@ -9106,6 +9410,7 @@ var CloudFrontManager = class {
9106
9410
  //#region iac/dynamodb.ts
9107
9411
  const DYNAMODB_DESCRIBE_TABLE_ACTION = "dynamodb:DescribeTable";
9108
9412
  var DynamoDBTableSchemaError = class extends Error {
9413
+ tableName;
9109
9414
  name = "DynamoDBTableSchemaError";
9110
9415
  constructor(tableName) {
9111
9416
  super(`DynamoDB table "${tableName}" does not match the Hot Updater key and index schema`);
@@ -9113,6 +9418,8 @@ var DynamoDBTableSchemaError = class extends Error {
9113
9418
  }
9114
9419
  };
9115
9420
  var DynamoDBPermissionError = class extends _hot_updater_cli_tools.InitError {
9421
+ tableName;
9422
+ region;
9116
9423
  name = "DynamoDBPermissionError";
9117
9424
  requiredAction = DYNAMODB_DESCRIBE_TABLE_ACTION;
9118
9425
  constructor(tableName, region, cause) {
@@ -9158,7 +9465,43 @@ const hasExpectedSchema = (table) => {
9158
9465
  return keyAttributes.every((attributeName) => table?.AttributeDefinitions?.some(({ AttributeName, AttributeType }) => AttributeName === attributeName && AttributeType === "S")) && table?.BillingModeSummary?.BillingMode === "PAY_PER_REQUEST" && table.OnDemandThroughput?.MaxReadRequestUnits === onDemandThroughput.MaxReadRequestUnits && table.OnDemandThroughput?.MaxWriteRequestUnits === onDemandThroughput.MaxWriteRequestUnits && hasKeySchema(table?.KeySchema, primaryKeySchema) && hasKeySchema(updateIndex?.KeySchema, updateIndexKeySchema) && updateIndex?.OnDemandThroughput?.MaxReadRequestUnits === onDemandThroughput.MaxReadRequestUnits && updateIndex?.OnDemandThroughput?.MaxWriteRequestUnits === onDemandThroughput.MaxWriteRequestUnits && updateIndex?.Projection?.ProjectionType === "ALL";
9159
9466
  };
9160
9467
  const isResourceNotFound = (error) => typeof error === "object" && error !== null && Reflect.get(error, "name") === "ResourceNotFoundException";
9468
+ const buildDynamoDBCreateTableInput = (tableName) => ({
9469
+ AttributeDefinitions: [
9470
+ {
9471
+ AttributeName: "pk",
9472
+ AttributeType: "S"
9473
+ },
9474
+ {
9475
+ AttributeName: "sk",
9476
+ AttributeType: "S"
9477
+ },
9478
+ {
9479
+ AttributeName: "gsi1pk",
9480
+ AttributeType: "S"
9481
+ },
9482
+ {
9483
+ AttributeName: "gsi1sk",
9484
+ AttributeType: "S"
9485
+ }
9486
+ ],
9487
+ BillingMode: "PAY_PER_REQUEST",
9488
+ DeletionProtectionEnabled: true,
9489
+ GlobalSecondaryIndexes: [{
9490
+ IndexName: DYNAMODB_UPDATE_INDEX_NAME,
9491
+ KeySchema: [...updateIndexKeySchema],
9492
+ Projection: { ProjectionType: "ALL" },
9493
+ OnDemandThroughput: onDemandThroughput
9494
+ }],
9495
+ KeySchema: [...primaryKeySchema],
9496
+ OnDemandThroughput: onDemandThroughput,
9497
+ TableName: tableName
9498
+ });
9499
+ const buildDynamoDBBackupInput = (tableName) => ({
9500
+ PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
9501
+ TableName: tableName
9502
+ });
9161
9503
  var DynamoDBManager = class {
9504
+ region;
9162
9505
  client;
9163
9506
  constructor(region, credentials) {
9164
9507
  this.region = region;
@@ -9177,37 +9520,7 @@ var DynamoDBManager = class {
9177
9520
  if (error instanceof Error && error.name === "AccessDeniedException" && error.message.includes(DYNAMODB_DESCRIBE_TABLE_ACTION)) throw new DynamoDBPermissionError(tableName, this.region, error);
9178
9521
  if (!isResourceNotFound(error)) throw error;
9179
9522
  }
9180
- await this.client.createTable({
9181
- AttributeDefinitions: [
9182
- {
9183
- AttributeName: "pk",
9184
- AttributeType: "S"
9185
- },
9186
- {
9187
- AttributeName: "sk",
9188
- AttributeType: "S"
9189
- },
9190
- {
9191
- AttributeName: "gsi1pk",
9192
- AttributeType: "S"
9193
- },
9194
- {
9195
- AttributeName: "gsi1sk",
9196
- AttributeType: "S"
9197
- }
9198
- ],
9199
- BillingMode: "PAY_PER_REQUEST",
9200
- DeletionProtectionEnabled: true,
9201
- GlobalSecondaryIndexes: [{
9202
- IndexName: DYNAMODB_UPDATE_INDEX_NAME,
9203
- KeySchema: [...updateIndexKeySchema],
9204
- Projection: { ProjectionType: "ALL" },
9205
- OnDemandThroughput: onDemandThroughput
9206
- }],
9207
- KeySchema: [...primaryKeySchema],
9208
- OnDemandThroughput: onDemandThroughput,
9209
- TableName: tableName
9210
- });
9523
+ await this.client.createTable(buildDynamoDBCreateTableInput(tableName));
9211
9524
  await (0, _aws_sdk_client_dynamodb.waitUntilTableExists)({
9212
9525
  client: this.client,
9213
9526
  maxWaitTime: 120
@@ -9217,14 +9530,84 @@ var DynamoDBManager = class {
9217
9530
  async ensureLifecycle(tableName) {
9218
9531
  const { ContinuousBackupsDescription } = await this.client.describeContinuousBackups({ TableName: tableName });
9219
9532
  if (ContinuousBackupsDescription?.PointInTimeRecoveryDescription?.PointInTimeRecoveryStatus === "ENABLED") return;
9220
- await this.client.updateContinuousBackups({
9221
- PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
9222
- TableName: tableName
9223
- });
9533
+ await this.client.updateContinuousBackups(buildDynamoDBBackupInput(tableName));
9224
9534
  }
9225
9535
  };
9226
9536
  //#endregion
9227
9537
  //#region iac/iam.ts
9538
+ const buildDynamoDBPolicy = (region, accountId, tableName) => {
9539
+ const tableArn = `arn:aws:dynamodb:${region}:${accountId}:table/${tableName}`;
9540
+ return {
9541
+ Version: "2012-10-17",
9542
+ Statement: [{
9543
+ Action: ["dynamodb:Query"],
9544
+ Effect: "Allow",
9545
+ Resource: [`${tableArn}/index/${DYNAMODB_UPDATE_INDEX_NAME}`]
9546
+ }, {
9547
+ Action: [
9548
+ "dynamodb:BatchGetItem",
9549
+ "dynamodb:DeleteItem",
9550
+ "dynamodb:GetItem",
9551
+ "dynamodb:PutItem",
9552
+ "dynamodb:Query",
9553
+ "dynamodb:TransactWriteItems",
9554
+ "dynamodb:UpdateItem"
9555
+ ],
9556
+ Condition: { "ForAllValues:StringLike": { "dynamodb:LeadingKeys": [
9557
+ "_hot-updater",
9558
+ "bundles",
9559
+ "bundle_patches",
9560
+ "release-scope#*",
9561
+ "release_catalogs",
9562
+ DYNAMODB_RELEASE_ID_PARTITION,
9563
+ DYNAMODB_CHANNEL_PARTITION,
9564
+ DYNAMODB_CHANNEL_NAME_PARTITION,
9565
+ DYNAMODB_INSIGHTS_PARTITION,
9566
+ DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION,
9567
+ DYNAMODB_INSIGHTS_EVENT_IDS_PARTITION,
9568
+ `${DYNAMODB_INSIGHTS_BUNDLE_PREFIX}*`,
9569
+ "_hot-updater#insights-user#*",
9570
+ "_hot-updater#insights-scope#*",
9571
+ DYNAMODB_API_KEY_PARTITION,
9572
+ DYNAMODB_API_KEY_HASH_PARTITION
9573
+ ] } },
9574
+ Effect: "Allow",
9575
+ Resource: [tableArn]
9576
+ }]
9577
+ };
9578
+ };
9579
+ const buildS3Policy = (bucketName) => {
9580
+ return {
9581
+ Version: "2012-10-17",
9582
+ Statement: [{
9583
+ Action: ["s3:ListBucket"],
9584
+ Effect: "Allow",
9585
+ Resource: [`arn:aws:s3:::${bucketName}`]
9586
+ }, {
9587
+ Action: ["s3:GetObject"],
9588
+ Effect: "Allow",
9589
+ Resource: [`arn:aws:s3:::${bucketName}/*`]
9590
+ }]
9591
+ };
9592
+ };
9593
+ const buildSsmPolicy = (region, accountId, parameterName) => {
9594
+ return {
9595
+ Version: "2012-10-17",
9596
+ Statement: [{
9597
+ Effect: "Allow",
9598
+ Action: ["ssm:GetParameter"],
9599
+ Resource: `arn:aws:ssm:${region}:${accountId}:parameter/${parameterName.replace(/^\/+/, "")}`
9600
+ }]
9601
+ };
9602
+ };
9603
+ const LAMBDA_EDGE_TRUST_POLICY = {
9604
+ Version: "2012-10-17",
9605
+ Statement: [{
9606
+ Effect: "Allow",
9607
+ Principal: { Service: ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] },
9608
+ Action: "sts:AssumeRole"
9609
+ }]
9610
+ };
9228
9611
  var IAMManager = class {
9229
9612
  region;
9230
9613
  credentials;
@@ -9241,71 +9624,22 @@ var IAMManager = class {
9241
9624
  });
9242
9625
  }
9243
9626
  async ensureDynamoDBPolicy(iamClient, roleName, accountId, tableName) {
9244
- const tableArn = `arn:aws:dynamodb:${this.region}:${accountId}:table/${tableName}`;
9245
9627
  await iamClient.putRolePolicy({
9246
- PolicyDocument: JSON.stringify({
9247
- Version: "2012-10-17",
9248
- Statement: [{
9249
- Action: ["dynamodb:Query"],
9250
- Effect: "Allow",
9251
- Resource: [`${tableArn}/index/${DYNAMODB_UPDATE_INDEX_NAME}`]
9252
- }, {
9253
- Action: [
9254
- "dynamodb:BatchGetItem",
9255
- "dynamodb:DeleteItem",
9256
- "dynamodb:GetItem",
9257
- "dynamodb:PutItem",
9258
- "dynamodb:Query",
9259
- "dynamodb:TransactWriteItems",
9260
- "dynamodb:UpdateItem"
9261
- ],
9262
- Condition: { "ForAllValues:StringEquals": { "dynamodb:LeadingKeys": [
9263
- "_hot-updater",
9264
- "bundles",
9265
- "bundle_patches",
9266
- DYNAMODB_CHANNEL_PARTITION,
9267
- DYNAMODB_CHANNEL_NAME_PARTITION,
9268
- DYNAMODB_INSIGHTS_PARTITION,
9269
- DYNAMODB_API_KEY_PARTITION,
9270
- DYNAMODB_API_KEY_HASH_PARTITION
9271
- ] } },
9272
- Effect: "Allow",
9273
- Resource: [tableArn]
9274
- }]
9275
- }),
9628
+ PolicyDocument: JSON.stringify(buildDynamoDBPolicy(this.region, accountId, tableName)),
9276
9629
  PolicyName: "HotUpdaterDynamoDBReadAccess",
9277
9630
  RoleName: roleName
9278
9631
  });
9279
9632
  }
9280
9633
  async ensureS3Policy(iamClient, roleName, bucketName) {
9281
9634
  await iamClient.putRolePolicy({
9282
- PolicyDocument: JSON.stringify({
9283
- Version: "2012-10-17",
9284
- Statement: [{
9285
- Action: ["s3:ListBucket"],
9286
- Effect: "Allow",
9287
- Resource: [`arn:aws:s3:::${bucketName}`]
9288
- }, {
9289
- Action: ["s3:GetObject"],
9290
- Effect: "Allow",
9291
- Resource: [`arn:aws:s3:::${bucketName}/*`]
9292
- }]
9293
- }),
9635
+ PolicyDocument: JSON.stringify(buildS3Policy(bucketName)),
9294
9636
  PolicyName: "HotUpdaterS3ReadAccess",
9295
9637
  RoleName: roleName
9296
9638
  });
9297
9639
  }
9298
9640
  async ensureSsmPolicy(iamClient, roleName, accountId, parameterName) {
9299
- const parameterPath = parameterName.replace(/^\/+/, "");
9300
9641
  await iamClient.putRolePolicy({
9301
- PolicyDocument: JSON.stringify({
9302
- Version: "2012-10-17",
9303
- Statement: [{
9304
- Effect: "Allow",
9305
- Action: ["ssm:GetParameter"],
9306
- Resource: `arn:aws:ssm:${this.region}:${accountId}:parameter/${parameterPath}`
9307
- }]
9308
- }),
9642
+ PolicyDocument: JSON.stringify(buildSsmPolicy(this.region, accountId, parameterName)),
9309
9643
  PolicyName: "HotUpdaterSSMAccess",
9310
9644
  RoleName: roleName
9311
9645
  });
@@ -9320,14 +9654,7 @@ var IAMManager = class {
9320
9654
  credentials: this.credentials
9321
9655
  }).getCallerIdentity({})).Account;
9322
9656
  if (!accountId) throw new Error("Failed to get AWS account ID");
9323
- const assumeRolePolicyDocument = JSON.stringify({
9324
- Version: "2012-10-17",
9325
- Statement: [{
9326
- Effect: "Allow",
9327
- Principal: { Service: ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] },
9328
- Action: "sts:AssumeRole"
9329
- }]
9330
- });
9657
+ const assumeRolePolicyDocument = JSON.stringify(LAMBDA_EDGE_TRUST_POLICY);
9331
9658
  const roleName = `hot-updater-edge-${(0, node_crypto.createHash)("sha256").update(options.lambdaName).digest("hex").slice(0, 16)}`;
9332
9659
  try {
9333
9660
  const { Role: existingRole } = await iamClient.getRole({ RoleName: roleName });
@@ -9403,7 +9730,8 @@ var LambdaEdgeDeployer = class {
9403
9730
  async deploy(lambdaRoleArn, lambdaName, config) {
9404
9731
  const cwd = (0, _hot_updater_cli_tools.getCwd)();
9405
9732
  const lambdaPath = require.resolve("@hot-updater/aws/lambda");
9406
- const { tmpDir, removeTmpDir } = await (0, _hot_updater_cli_tools.copyDirToTmp)(path.default.dirname(lambdaPath));
9733
+ const lambdaDir = path.default.dirname(lambdaPath);
9734
+ const { tmpDir, removeTmpDir } = await (0, _hot_updater_cli_tools.copyDirToTmp)(lambdaDir);
9407
9735
  const indexPath = path.default.join(tmpDir, "index.cjs");
9408
9736
  const code = (0, _hot_updater_cli_tools.transformEnv)(indexPath, {
9409
9737
  CLOUDFRONT_KEY_PAIR_ID: config.publicKeyId,
@@ -9711,12 +10039,11 @@ const awsOptions = {
9711
10039
  };`.trim()
9712
10040
  }];
9713
10041
  break;
9714
- case "account":
9715
- helperStatements = [{
9716
- name: "awsOptions",
9717
- strategy: "merge-object",
9718
- replaceIncompatibleProperties: ["credentials"],
9719
- code: `
10042
+ case "account": helperStatements = [{
10043
+ name: "awsOptions",
10044
+ strategy: "merge-object",
10045
+ replaceIncompatibleProperties: ["credentials"],
10046
+ code: `
9720
10047
  const awsOptions = {
9721
10048
  region: process.env.HOT_UPDATER_S3_REGION!,
9722
10049
  credentials: {
@@ -9724,8 +10051,7 @@ const awsOptions = {
9724
10051
  secretAccessKey: process.env.HOT_UPDATER_S3_SECRET_ACCESS_KEY!,
9725
10052
  },
9726
10053
  };`.trim()
9727
- }];
9728
- break;
10054
+ }];
9729
10055
  }
9730
10056
  const builder = new _hot_updater_cli_tools.ConfigBuilder().setBuildType(build).setStorage(storageConfig).setDatabase(databaseConfig).setIntermediateCode(helperStatements.map((statement) => statement.code.trim()).join("\n\n"));
9731
10057
  switch (authMode.mode) {
@@ -9735,13 +10061,10 @@ const awsOptions = {
9735
10061
  named: ["fromSSO"]
9736
10062
  });
9737
10063
  break;
9738
- case "local":
9739
- builder.addImport({
9740
- pkg: "@aws-sdk/credential-providers",
9741
- named: [authMode.profile ? "fromIni" : "fromNodeProviderChain"]
9742
- });
9743
- break;
9744
- case "account": break;
10064
+ case "local": builder.addImport({
10065
+ pkg: "@aws-sdk/credential-providers",
10066
+ named: [authMode.profile ? "fromIni" : "fromNodeProviderChain"]
10067
+ });
9745
10068
  }
9746
10069
  return (0, _hot_updater_cli_tools.createHotUpdaterConfigScaffoldFromBuilder)(builder, { helperStatements });
9747
10070
  };
@@ -9776,7 +10099,7 @@ const isAwsRegion = (value) => {
9776
10099
  return value !== void 0 && Object.hasOwn(regionLocationMap, value);
9777
10100
  };
9778
10101
  const prepareDynamoDBDeployment = async (input) => {
9779
- return new DynamoDBManager(input.region, input.credentials).ensureTable(input.tableName);
10102
+ await new DynamoDBManager(input.region, input.credentials).ensureTable(input.tableName);
9780
10103
  };
9781
10104
  const prepareDynamoDBApiKey = async (input) => {
9782
10105
  return (await (0, _hot_updater_server.provisionApiKey)({
@@ -9905,13 +10228,14 @@ const runInit = async ({ build, envFile }) => {
9905
10228
  dynamodbTableName: resolvedDynamoDBTableName,
9906
10229
  lambdaName
9907
10230
  };
10231
+ const persistCredentialInputs = await (0, _hot_updater_cli_tools.confirmInitInputPersistence)({
10232
+ existingEnv: managedEnv,
10233
+ inputs: resolvedInputs,
10234
+ nonInteractive,
10235
+ provider: initProvider
10236
+ });
9908
10237
  const initEnv = (0, _hot_updater_cli_tools.getInitProviderEnvVars)({
9909
- includeConsentInputs: await (0, _hot_updater_cli_tools.confirmInitInputPersistence)({
9910
- existingEnv: managedEnv,
9911
- inputs: resolvedInputs,
9912
- nonInteractive,
9913
- provider: initProvider
9914
- }),
10238
+ includeConsentInputs: persistCredentialInputs,
9915
10239
  inputs: resolvedInputs,
9916
10240
  provider: initProvider
9917
10241
  });
@@ -10001,6 +10325,12 @@ const runInit = async ({ build, envFile }) => {
10001
10325
  _hot_updater_cli_tools.p.log.success("Done! 🎉");
10002
10326
  };
10003
10327
  //#endregion
10328
+ exports.LAMBDA_EDGE_TRUST_POLICY = LAMBDA_EDGE_TRUST_POLICY;
10329
+ exports.buildDynamoDBBackupInput = buildDynamoDBBackupInput;
10330
+ exports.buildDynamoDBCreateTableInput = buildDynamoDBCreateTableInput;
10331
+ exports.buildDynamoDBPolicy = buildDynamoDBPolicy;
10332
+ exports.buildS3Policy = buildS3Policy;
10333
+ exports.buildSsmPolicy = buildSsmPolicy;
10004
10334
  exports.prepareDynamoDBApiKey = prepareDynamoDBApiKey;
10005
10335
  exports.prepareDynamoDBDeployment = prepareDynamoDBDeployment;
10006
10336
  exports.runInit = runInit;