@awsless/cli 0.1.3 → 0.1.5

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.
Files changed (2) hide show
  1. package/dist/bin.js +385 -320
  2. package/package.json +13 -13
package/dist/bin.js CHANGED
@@ -108480,6 +108480,10 @@ var format = (parts) => {
108480
108480
  if (part instanceof Error) {
108481
108481
  return part.stack ?? part.message;
108482
108482
  }
108483
+ if (Array.isArray(part)) {
108484
+ return part.map((entry) => format([entry])).join(`
108485
+ `);
108486
+ }
108483
108487
  return JSON.stringify(part);
108484
108488
  }).join(" ");
108485
108489
  };
@@ -128397,7 +128401,7 @@ import {
128397
128401
  UpdateKeysCommand
128398
128402
  } from "@aws-sdk/client-cloudfront-keyvaluestore";
128399
128403
 
128400
- // ../../node_modules/.pnpm/@terraforge+core@0.0.43_aws-crt@1.30.0_debug@4.4.3_supports-color@8.1.1__supports-color@8.1.1__graphology-types@0.24.8/node_modules/@terraforge/core/dist/index.mjs
128404
+ // ../../node_modules/.pnpm/@terraforge+core@0.0.44_aws-crt@1.30.0_debug@4.4.3_supports-color@8.1.1__supports-color@8.1.1__graphology-types@0.24.8/node_modules/@terraforge/core/dist/index.mjs
128401
128405
  var import_async_on_exit = __toESM(require_async_on_exit(), 1);
128402
128406
 
128403
128407
  // ../../node_modules/.pnpm/p-limit@6.2.0/node_modules/p-limit/index.js
@@ -131734,7 +131738,7 @@ var getter = (options = {}) => {
131734
131738
  };
131735
131739
  var get = getter();
131736
131740
 
131737
- // ../../node_modules/.pnpm/@terraforge+core@0.0.43_aws-crt@1.30.0_debug@4.4.3_supports-color@8.1.1__supports-color@8.1.1__graphology-types@0.24.8/node_modules/@terraforge/core/dist/index.mjs
131741
+ // ../../node_modules/.pnpm/@terraforge+core@0.0.44_aws-crt@1.30.0_debug@4.4.3_supports-color@8.1.1__supports-color@8.1.1__graphology-types@0.24.8/node_modules/@terraforge/core/dist/index.mjs
131738
131742
  import { appendFile, mkdir, readFile as readFile4, rename, rm, writeFile as writeFile2 } from "fs/promises";
131739
131743
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
131740
131744
  import { DynamoDB } from "@aws-sdk/client-dynamodb";
@@ -132007,7 +132011,7 @@ var unmarshall = (data, options) => {
132007
132011
  return convertToNative({ M: data }, options);
132008
132012
  };
132009
132013
 
132010
- // ../../node_modules/.pnpm/@terraforge+core@0.0.43_aws-crt@1.30.0_debug@4.4.3_supports-color@8.1.1__supports-color@8.1.1__graphology-types@0.24.8/node_modules/@terraforge/core/dist/index.mjs
132014
+ // ../../node_modules/.pnpm/@terraforge+core@0.0.44_aws-crt@1.30.0_debug@4.4.3_supports-color@8.1.1__supports-color@8.1.1__graphology-types@0.24.8/node_modules/@terraforge/core/dist/index.mjs
132011
132015
  import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
132012
132016
  import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
132013
132017
  var nodeMetaSymbol = Symbol("metadata");
@@ -132025,9 +132029,6 @@ var isDataSource = (obj) => {
132025
132029
  return isNode(obj) && obj[nodeMetaSymbol].tag === "data";
132026
132030
  };
132027
132031
  var Group = class Group2 {
132028
- parent;
132029
- type;
132030
- name;
132031
132032
  children = [];
132032
132033
  constructor(parent, type, name) {
132033
132034
  this.parent = parent;
@@ -132073,7 +132074,6 @@ var Group = class Group2 {
132073
132074
  }
132074
132075
  };
132075
132076
  var Stack = class extends Group {
132076
- app;
132077
132077
  dependencies = /* @__PURE__ */ new Set;
132078
132078
  constructor(app, name) {
132079
132079
  super(app, "stack", name);
@@ -132088,7 +132088,6 @@ var findParentStack = (group4) => {
132088
132088
  return findParentStack(group4.parent);
132089
132089
  };
132090
132090
  var App = class extends Group {
132091
- name;
132092
132091
  constructor(name) {
132093
132092
  super(undefined, "app", name);
132094
132093
  this.name = name;
@@ -132102,8 +132101,6 @@ var PENDING = 1;
132102
132101
  var RESOLVED = 2;
132103
132102
  var REJECTED = 3;
132104
132103
  var Future = class Future2 {
132105
- callback;
132106
- volatile;
132107
132104
  listeners = /* @__PURE__ */ new Set;
132108
132105
  status = IDLE;
132109
132106
  data;
@@ -132125,28 +132122,28 @@ var Future = class Future2 {
132125
132122
  }
132126
132123
  }
132127
132124
  pipe(cb) {
132128
- return new Future2((resolve, reject) => {
132125
+ return new Future2((resolve$1, reject) => {
132129
132126
  this.then((value) => {
132130
- Promise.resolve(cb(value)).then((value2) => {
132131
- resolve(value2);
132127
+ Promise.resolve(cb(value)).then((value$1) => {
132128
+ resolve$1(value$1);
132132
132129
  }).catch(reject);
132133
132130
  }, reject);
132134
132131
  }, this.volatile);
132135
132132
  }
132136
- then(resolve, reject) {
132133
+ then(resolve$1, reject) {
132137
132134
  if (this.volatile)
132138
132135
  try {
132139
- Promise.resolve(this.callback(resolve, (error3) => reject?.(error3))).catch((error3) => reject?.(error3));
132136
+ Promise.resolve(this.callback(resolve$1, (error3) => reject?.(error3))).catch((error3) => reject?.(error3));
132140
132137
  } catch (error3) {
132141
132138
  reject?.(error3);
132142
132139
  }
132143
132140
  else if (this.status === RESOLVED)
132144
- resolve(this.data);
132141
+ resolve$1(this.data);
132145
132142
  else if (this.status === REJECTED)
132146
132143
  reject?.(this.error);
132147
132144
  else {
132148
132145
  this.listeners.add({
132149
- resolve,
132146
+ resolve: resolve$1,
132150
132147
  reject
132151
132148
  });
132152
132149
  if (this.status === IDLE) {
@@ -132155,7 +132152,7 @@ var Future = class Future2 {
132155
132152
  if (this.status === PENDING) {
132156
132153
  this.status = RESOLVED;
132157
132154
  this.data = data;
132158
- this.listeners.forEach(({ resolve: resolve2 }) => resolve2(data));
132155
+ this.listeners.forEach(({ resolve: resolve$2 }) => resolve$2(data));
132159
132156
  this.listeners.clear();
132160
132157
  }
132161
132158
  };
@@ -132163,7 +132160,7 @@ var Future = class Future2 {
132163
132160
  if (this.status === PENDING) {
132164
132161
  this.status = REJECTED;
132165
132162
  this.error = error3;
132166
- this.listeners.forEach(({ reject: reject2 }) => reject2?.(error3));
132163
+ this.listeners.forEach(({ reject: reject$1 }) => reject$1?.(error3));
132167
132164
  this.listeners.clear();
132168
132165
  }
132169
132166
  };
@@ -132178,13 +132175,13 @@ var Future = class Future2 {
132178
132175
  };
132179
132176
  var findInputDeps = (props) => {
132180
132177
  const deps = [];
132181
- const find = (props2) => {
132182
- if (props2 instanceof Output)
132183
- deps.push(...props2.dependencies);
132184
- else if (Array.isArray(props2))
132185
- props2.map(find);
132186
- else if (props2?.constructor === Object)
132187
- Object.values(props2).map(find);
132178
+ const find = (props$1) => {
132179
+ if (props$1 instanceof Output)
132180
+ deps.push(...props$1.dependencies);
132181
+ else if (Array.isArray(props$1))
132182
+ props$1.map(find);
132183
+ else if (props$1?.constructor === Object)
132184
+ Object.values(props$1).map(find);
132188
132185
  };
132189
132186
  find(props);
132190
132187
  return deps;
@@ -132207,7 +132204,7 @@ var resolveWithTimeout = async (promise) => {
132207
132204
  }
132208
132205
  };
132209
132206
  var resolveInputs = async (inputs, fallback) => {
132210
- const resolve = async (value, path) => {
132207
+ const resolve$1 = async (value, path) => {
132211
132208
  if (value instanceof Output || value instanceof Future || value instanceof Promise)
132212
132209
  try {
132213
132210
  return await resolveWithTimeout(value);
@@ -132217,31 +132214,30 @@ var resolveInputs = async (inputs, fallback) => {
132217
132214
  throw error3;
132218
132215
  }
132219
132216
  if (Array.isArray(value))
132220
- return Promise.all(value.map((item, index) => resolve(item, [...path, index])));
132217
+ return Promise.all(value.map((item, index) => resolve$1(item, [...path, index])));
132221
132218
  if (value?.constructor === Object) {
132222
- const entries = Object.entries(value);
132223
- const resolved = await Promise.all(entries.map(([key, item]) => resolve(item, [...path, key])));
132219
+ const entries$1 = Object.entries(value);
132220
+ const resolved = await Promise.all(entries$1.map(([key, item]) => resolve$1(item, [...path, key])));
132224
132221
  const result = {};
132225
- entries.forEach(([key], i3) => {
132222
+ entries$1.forEach(([key], i3) => {
132226
132223
  result[key] = resolved[i3];
132227
132224
  });
132228
132225
  return result;
132229
132226
  }
132230
132227
  return value;
132231
132228
  };
132232
- return resolve(inputs, []);
132229
+ return resolve$1(inputs, []);
132233
132230
  };
132234
132231
  var Output = class Output2 extends Future {
132235
- dependencies;
132236
132232
  constructor(dependencies, callback, volatile = false) {
132237
132233
  super(callback, volatile);
132238
132234
  this.dependencies = dependencies;
132239
132235
  }
132240
132236
  pipe(cb) {
132241
- return new Output2(this.dependencies, (resolve, reject) => {
132237
+ return new Output2(this.dependencies, (resolve$1, reject) => {
132242
132238
  this.then((value) => {
132243
- Promise.resolve(cb(value)).then((value2) => {
132244
- resolve(value2);
132239
+ Promise.resolve(cb(value)).then((value$1) => {
132240
+ resolve$1(value$1);
132245
132241
  }).catch(reject);
132246
132242
  }, reject);
132247
132243
  }, this.volatile);
@@ -132257,9 +132253,9 @@ var hasVolatileInput = (props) => {
132257
132253
  return false;
132258
132254
  };
132259
132255
  var combine = (...inputs) => {
132260
- return new Output(new Set(findInputDeps(inputs)), (resolve, reject) => {
132256
+ return new Output(new Set(findInputDeps(inputs)), (resolve$1, reject) => {
132261
132257
  Promise.all(inputs).then(resolveInputs).then((result) => {
132262
- resolve(result);
132258
+ resolve$1(result);
132263
132259
  }, reject);
132264
132260
  }, hasVolatileInput(inputs));
132265
132261
  };
@@ -132283,7 +132279,7 @@ var createUrn = (tag, type, name, parentUrn) => {
132283
132279
  var createMeta = (tag, provider, parent, type, logicalId, input, config) => {
132284
132280
  const urn = createUrn(tag, type, logicalId, parent.urn);
132285
132281
  const stack = findParentStack(parent);
132286
- let output;
132282
+ let output$1;
132287
132283
  let resolved = false;
132288
132284
  return {
132289
132285
  tag,
@@ -132308,16 +132304,16 @@ var createMeta = (tag, provider, parent, type, logicalId, input, config) => {
132308
132304
  return dependencies;
132309
132305
  },
132310
132306
  resolve(data) {
132311
- output = data;
132307
+ output$1 = data;
132312
132308
  resolved = true;
132313
132309
  },
132314
132310
  output(cb) {
132315
- return new Output(/* @__PURE__ */ new Set([this]), (resolve2, reject) => {
132311
+ return new Output(new Set([this]), (resolve$1, reject) => {
132316
132312
  if (!resolved) {
132317
132313
  reject(/* @__PURE__ */ new Error(`Unresolved output for ${tag}: ${urn}`));
132318
132314
  return;
132319
132315
  }
132320
- resolve2(cb(output));
132316
+ resolve$1(cb(output$1));
132321
132317
  }, true);
132322
132318
  }
132323
132319
  };
@@ -132337,7 +132333,6 @@ var createDebugger = (group4) => {
132337
132333
  };
132338
132334
  };
132339
132335
  var AlreadyLockedError = class extends Error {
132340
- urn;
132341
132336
  constructor(urn) {
132342
132337
  super(`Already locked: ${urn}`);
132343
132338
  this.urn = urn;
@@ -132543,9 +132538,6 @@ var allowsDependentReplace = (replaceOnChanges, dependencyPaths) => {
132543
132538
  return false;
132544
132539
  };
132545
132540
  var ResourceError = class ResourceError2 extends Error {
132546
- urn;
132547
- type;
132548
- operation;
132549
132541
  static wrap(urn, type, operation, error3) {
132550
132542
  if (error3 instanceof Error)
132551
132543
  return new ResourceError2(urn, type, operation, error3.message);
@@ -132559,8 +132551,6 @@ var ResourceError = class ResourceError2 extends Error {
132559
132551
  }
132560
132552
  };
132561
132553
  var AppError = class extends Error {
132562
- app;
132563
- issues;
132564
132554
  constructor(app, issues, message4) {
132565
132555
  super(message4);
132566
132556
  this.app = app;
@@ -132589,8 +132579,8 @@ var v1 = (oldAppState) => {
132589
132579
  const stacks = {};
132590
132580
  for (const [urn, stack] of entries(oldAppState.stacks)) {
132591
132581
  const nodes2 = {};
132592
- for (const [urn2, resource] of entries(stack.resources))
132593
- nodes2[urn2] = {
132582
+ for (const [urn$1, resource] of entries(stack.resources))
132583
+ nodes2[urn$1] = {
132594
132584
  ...resource,
132595
132585
  tag: "resource"
132596
132586
  };
@@ -132831,6 +132821,8 @@ var importResource = async (resource, input, opt) => {
132831
132821
  }
132832
132822
  });
132833
132823
  } catch (error3) {
132824
+ if (error3 instanceof ResourceNotFound)
132825
+ throw new ResourceNotFound(`The "${meta.type}" resource import "${meta.config?.import}" doesn't exist. (${meta.urn})`);
132834
132826
  throw ResourceError.wrap(meta.urn, meta.type, "import", error3);
132835
132827
  }
132836
132828
  return {
@@ -133012,11 +133004,11 @@ var deployApp = async (app, opt) => {
133012
133004
  });
133013
133005
  const isFilteredIn = !opt.filters?.length || opt.filters.includes(stackState.name);
133014
133006
  if (!found && isFilteredIn)
133015
- for (const [urn2, nodeState] of entries(stackState.nodes))
133016
- graph.add(urn2, dependentsOn(allNodes, urn2), async () => {
133007
+ for (const [urn$1, nodeState] of entries(stackState.nodes))
133008
+ graph.add(urn$1, dependentsOn(allNodes, urn$1), async () => {
133017
133009
  if (nodeState.tag === "resource")
133018
- await queue(() => deleteResource(appState.idempotentToken, urn2, nodeState, opt));
133019
- delete stackState.nodes[urn2];
133010
+ await queue(() => deleteResource(appState.idempotentToken, urn$1, nodeState, opt));
133011
+ delete stackState.nodes[urn$1];
133020
133012
  });
133021
133013
  }
133022
133014
  for (const stack of stacks) {
@@ -133045,16 +133037,16 @@ var deployApp = async (app, opt) => {
133045
133037
  throw ResourceError.wrap(meta.urn, meta.type, "resolve", error3);
133046
133038
  }
133047
133039
  if (isDataSource(node)) {
133048
- const meta2 = getMeta(node);
133040
+ const meta$1 = getMeta(node);
133049
133041
  if (!nodeState) {
133050
- const dataSourceState = await getDataSource(meta2, input, opt);
133051
- nodeState = stackState.nodes[meta2.urn] = {
133042
+ const dataSourceState = await getDataSource(meta$1, input, opt);
133043
+ nodeState = stackState.nodes[meta$1.urn] = {
133052
133044
  ...dataSourceState,
133053
133045
  drifted: undefined,
133054
133046
  ...partialNewResourceState
133055
133047
  };
133056
133048
  } else if (!compareState(nodeState.input, input) || nodeState.drifted) {
133057
- const dataSourceState = await getDataSource(meta2, input, opt);
133049
+ const dataSourceState = await getDataSource(meta$1, input, opt);
133058
133050
  Object.assign(nodeState, {
133059
133051
  ...dataSourceState,
133060
133052
  drifted: undefined,
@@ -133064,78 +133056,87 @@ var deployApp = async (app, opt) => {
133064
133056
  Object.assign(nodeState, partialNewResourceState);
133065
133057
  }
133066
133058
  if (isResource(node)) {
133067
- const meta2 = getMeta(node);
133068
- if (!nodeState)
133069
- if (meta2.config?.import) {
133059
+ const meta$1 = getMeta(node);
133060
+ if (!nodeState) {
133061
+ if (meta$1.config?.import) {
133070
133062
  const importedState = await importResource(node, input, opt);
133071
- const newResourceState = await updateResource(node, appState.idempotentToken, importedState.input, importedState.output, input, opt);
133072
- nodeState = stackState.nodes[meta2.urn] = {
133073
- ...importedState,
133074
- ...newResourceState,
133075
- ...partialNewResourceState
133076
- };
133077
- } else {
133063
+ if (importedState) {
133064
+ const newResourceState = await updateResource(node, appState.idempotentToken, importedState.input, importedState.output, input, opt);
133065
+ nodeState = stackState.nodes[meta$1.urn] = {
133066
+ ...importedState,
133067
+ ...newResourceState,
133068
+ ...partialNewResourceState
133069
+ };
133070
+ }
133071
+ }
133072
+ if (!nodeState) {
133078
133073
  const newResourceState = await createResource(node, appState.idempotentToken, input, opt);
133079
- nodeState = stackState.nodes[meta2.urn] = {
133074
+ nodeState = stackState.nodes[meta$1.urn] = {
133080
133075
  ...newResourceState,
133081
133076
  ...partialNewResourceState
133082
133077
  };
133083
133078
  }
133084
- else {
133079
+ } else {
133085
133080
  const inputChanged = !compareState(nodeState.input, input);
133086
133081
  const hasDrift = !!nodeState.drifted;
133087
133082
  if (!inputChanged && !hasDrift)
133088
133083
  Object.assign(nodeState, partialNewResourceState);
133089
133084
  else {
133090
133085
  let newResourceState;
133091
- const ignoreReplace = forcedUpdateDependents.has(meta2.urn);
133092
- if (!ignoreReplace && requiresReplacement(nodeState.input, input, meta2.config?.replaceOnChanges ?? []))
133093
- if (meta2.config?.createBeforeReplace) {
133094
- meta2.resolve(input);
133086
+ const ignoreReplace = forcedUpdateDependents.has(meta$1.urn);
133087
+ if (!ignoreReplace && requiresReplacement(nodeState.input, input, meta$1.config?.replaceOnChanges ?? []))
133088
+ if (meta$1.config?.createBeforeReplace) {
133089
+ meta$1.resolve(input);
133095
133090
  try {
133096
133091
  for (const [dependentUrn, dependentNode] of nodeByUrn.entries()) {
133097
133092
  if (!isResource(dependentNode))
133098
133093
  continue;
133099
133094
  const dependentMeta = getMeta(dependentNode);
133100
- if (!dependentMeta.dependencies.has(meta2.urn))
133095
+ if (!dependentMeta.dependencies.has(meta$1.urn))
133101
133096
  continue;
133102
133097
  const dependentStackState = stackStates.get(dependentMeta.stack.urn);
133103
133098
  const dependentState = dependentStackState?.nodes[dependentUrn];
133104
133099
  if (!dependentStackState || !dependentState)
133105
133100
  continue;
133106
- const dependencyPaths = findDependencyPaths(dependentMeta.input, meta2.urn);
133101
+ const dependencyPaths = findDependencyPaths(dependentMeta.input, meta$1.urn);
133107
133102
  if (dependencyPaths.length === 0)
133108
133103
  continue;
133109
133104
  const dependentProvider = findProvider(opt.providers, dependentMeta.provider);
133110
133105
  if (dependentProvider.planResourceChange) {
133111
133106
  const dependentProposedInput = await resolveInputs(dependentMeta.input, (path) => getAtPath(dependentState.input, path));
133112
- if ((await dependentProvider.planResourceChange({
133113
- type: dependentMeta.type,
133114
- priorState: dependentState.output,
133115
- proposedState: dependentProposedInput
133116
- })).requiresReplacement) {
133107
+ let dependentRequiresReplacement;
133108
+ try {
133109
+ dependentRequiresReplacement = !!(await dependentProvider.planResourceChange({
133110
+ type: dependentMeta.type,
133111
+ priorState: dependentState.output,
133112
+ proposedState: dependentProposedInput
133113
+ })).requiresReplacement;
133114
+ } catch {
133115
+ dependentRequiresReplacement = true;
133116
+ }
133117
+ if (dependentRequiresReplacement) {
133117
133118
  if (!allowsDependentReplace(dependentMeta.config?.replaceOnChanges, dependencyPaths))
133118
- throw ResourceError.wrap(dependentMeta.urn, dependentMeta.type, "update", /* @__PURE__ */ new Error(`Replacing ${meta2.urn} requires ${dependentMeta.urn} to set replaceOnChanges for its dependency fields.`));
133119
+ throw ResourceError.wrap(dependentMeta.urn, dependentMeta.type, "update", /* @__PURE__ */ new Error(`Replacing ${meta$1.urn} requires ${dependentMeta.urn} to set replaceOnChanges for its dependency fields.`));
133119
133120
  }
133120
133121
  }
133121
133122
  }
133122
133123
  } finally {
133123
- meta2.resolve(nodeState.output);
133124
+ meta$1.resolve(nodeState.output);
133124
133125
  }
133125
133126
  const priorState = { ...nodeState };
133126
133127
  newResourceState = await createResource(node, appState.idempotentToken, input, opt);
133127
133128
  if (newResourceState.output)
133128
- meta2.resolve(newResourceState.output);
133129
- if (!meta2.config?.retainOnDelete) {
133129
+ meta$1.resolve(newResourceState.output);
133130
+ if (!meta$1.config?.retainOnDelete) {
133130
133131
  appState.pendingDeletes ??= {};
133131
- appState.pendingDeletes[meta2.urn] = priorState;
133132
+ appState.pendingDeletes[meta$1.urn] = priorState;
133132
133133
  }
133133
133134
  } else {
133134
133135
  for (const [dependentUrn, dependentNode] of nodeByUrn.entries()) {
133135
133136
  if (!isResource(dependentNode))
133136
133137
  continue;
133137
133138
  const dependentMeta = getMeta(dependentNode);
133138
- if (!dependentMeta.dependencies.has(meta2.urn))
133139
+ if (!dependentMeta.dependencies.has(meta$1.urn))
133139
133140
  continue;
133140
133141
  if (plannedDependents.has(dependentUrn))
133141
133142
  continue;
@@ -133143,10 +133144,10 @@ var deployApp = async (app, opt) => {
133143
133144
  const dependentState = dependentStackState?.nodes[dependentUrn];
133144
133145
  if (!dependentStackState || !dependentState)
133145
133146
  continue;
133146
- const dependencyPaths = findDependencyPaths(dependentMeta.input, meta2.urn);
133147
+ const dependencyPaths = findDependencyPaths(dependentMeta.input, meta$1.urn);
133147
133148
  if (dependencyPaths.length === 0)
133148
133149
  continue;
133149
- const detachedInput = stripDependencyInputs(dependentState.input, dependentMeta.input, meta2.urn);
133150
+ const detachedInput = stripDependencyInputs(dependentState.input, dependentMeta.input, meta$1.urn);
133150
133151
  if (compareState(dependentState.input, detachedInput))
133151
133152
  continue;
133152
133153
  plannedDependents.add(dependentUrn);
@@ -133164,7 +133165,7 @@ var deployApp = async (app, opt) => {
133164
133165
  }
133165
133166
  if (dependentRequiresReplacement) {
133166
133167
  if (!allowsDependentReplace(dependentMeta.config?.replaceOnChanges, dependencyPaths))
133167
- throw ResourceError.wrap(dependentMeta.urn, dependentMeta.type, "update", /* @__PURE__ */ new Error(`Replacing ${meta2.urn} requires ${dependentMeta.urn} to set replaceOnChanges for its dependency fields.`));
133168
+ throw ResourceError.wrap(dependentMeta.urn, dependentMeta.type, "update", /* @__PURE__ */ new Error(`Replacing ${meta$1.urn} requires ${dependentMeta.urn} to set replaceOnChanges for its dependency fields.`));
133168
133169
  await deleteResource(appState.idempotentToken, dependentUrn, dependentState, opt);
133169
133170
  delete dependentStackState.nodes[dependentUrn];
133170
133171
  } else {
@@ -133178,12 +133179,12 @@ var deployApp = async (app, opt) => {
133178
133179
  }
133179
133180
  newResourceState = await replaceResource(node, appState.idempotentToken, nodeState.input, nodeState.output, input, opt);
133180
133181
  if (newResourceState.output)
133181
- meta2.resolve(newResourceState.output);
133182
+ meta$1.resolve(newResourceState.output);
133182
133183
  }
133183
133184
  else {
133184
133185
  newResourceState = await updateResource(node, appState.idempotentToken, nodeState.input, nodeState.output, input, opt);
133185
133186
  if (ignoreReplace)
133186
- forcedUpdateDependents.delete(meta2.urn);
133187
+ forcedUpdateDependents.delete(meta$1.urn);
133187
133188
  }
133188
133189
  Object.assign(nodeState, {
133189
133190
  input,
@@ -133432,7 +133433,6 @@ var status = async (app, opt) => {
133432
133433
  return stacks;
133433
133434
  };
133434
133435
  var WorkSpace = class {
133435
- props;
133436
133436
  constructor(props) {
133437
133437
  this.props = props;
133438
133438
  }
@@ -133527,7 +133527,6 @@ var isConditionalCheckFailed = (error3) => {
133527
133527
  return error3 instanceof Error && error3.name === "ConditionalCheckFailedException";
133528
133528
  };
133529
133529
  var DynamoLockBackend = class {
133530
- props;
133531
133530
  client;
133532
133531
  constructor(props) {
133533
133532
  this.props = props;
@@ -133611,7 +133610,6 @@ var DynamoLockBackend = class {
133611
133610
  }
133612
133611
  };
133613
133612
  var S3StateBackend = class {
133614
- props;
133615
133613
  client;
133616
133614
  constructor(props) {
133617
133615
  this.props = props;
@@ -133649,16 +133647,16 @@ var S3StateBackend = class {
133649
133647
  }
133650
133648
  };
133651
133649
  var file = (path, encoding = "utf8") => {
133652
- return new Future(async (resolve2, reject) => {
133650
+ return new Future(async (resolve$1, reject) => {
133653
133651
  try {
133654
- resolve2(await readFile4(path, { encoding }));
133652
+ resolve$1(await readFile4(path, { encoding }));
133655
133653
  } catch (error3) {
133656
133654
  reject(error3);
133657
133655
  }
133658
133656
  });
133659
133657
  };
133660
133658
  var hash = (path, algo = "sha256") => {
133661
- return file(path).pipe((file2) => createHash4(algo).update(file2).digest("hex"));
133659
+ return file(path).pipe((file$1) => createHash4(algo).update(file$1).digest("hex"));
133662
133660
  };
133663
133661
  globalThis.$resolve = resolve;
133664
133662
  globalThis.$combine = combine;
@@ -133669,7 +133667,7 @@ var createCustomResourceClass = (providerId, resourceType) => {
133669
133667
  return new Proxy(class {
133670
133668
  }, { construct(_3, [parent, id, input, config]) {
133671
133669
  const meta = createMeta("resource", `custom:${providerId}`, parent, resourceType, id, input, config);
133672
- const node = new Proxy({}, { get(_4, key) {
133670
+ const node = new Proxy({}, { get(_$1, key) {
133673
133671
  if (key === nodeMetaSymbol)
133674
133672
  return meta;
133675
133673
  if (key === "urn")
@@ -133684,68 +133682,67 @@ var createCustomResourceClass = (providerId, resourceType) => {
133684
133682
  };
133685
133683
  var createCustomProvider = (providerId, resourceProviders) => {
133686
133684
  const version2 = 1;
133687
- const hasRefreshResource = Object.values(resourceProviders).some((provider2) => !!provider2.refreshResource);
133685
+ const hasRefreshResource = Object.values(resourceProviders).some((provider$1) => !!provider$1.refreshResource);
133688
133686
  const getProvider = (type) => {
133689
- const provider2 = resourceProviders[type];
133690
- if (!provider2)
133687
+ const provider$1 = resourceProviders[type];
133688
+ if (!provider$1)
133691
133689
  throw new Error(`The "${providerId}" provider doesn't support the "${type}" resource type.`);
133692
- return provider2;
133690
+ return provider$1;
133693
133691
  };
133694
133692
  const provider = {
133695
133693
  ownResource(id) {
133696
133694
  return id === `custom:${providerId}`;
133697
133695
  },
133698
133696
  async getResource({ type, ...props }) {
133699
- const provider2 = getProvider(type);
133700
- if (!provider2.getResource)
133697
+ const provider$1 = getProvider(type);
133698
+ if (!provider$1.getResource)
133701
133699
  return {
133702
133700
  version: version2,
133703
133701
  state: props.state
133704
133702
  };
133705
133703
  return {
133706
133704
  version: version2,
133707
- state: await provider2.getResource(props)
133705
+ state: await provider$1.getResource(props)
133708
133706
  };
133709
133707
  },
133710
133708
  async createResource({ type, ...props }) {
133711
- const provider2 = getProvider(type);
133712
- if (!provider2.createResource)
133709
+ const provider$1 = getProvider(type);
133710
+ if (!provider$1.createResource)
133713
133711
  return {
133714
133712
  version: version2,
133715
133713
  state: props.state
133716
133714
  };
133717
133715
  return {
133718
133716
  version: version2,
133719
- state: await provider2.createResource(props)
133717
+ state: await provider$1.createResource(props)
133720
133718
  };
133721
133719
  },
133722
133720
  async updateResource({ type, ...props }) {
133723
- const provider2 = getProvider(type);
133724
- if (!provider2.updateResource)
133721
+ const provider$1 = getProvider(type);
133722
+ if (!provider$1.updateResource)
133725
133723
  return {
133726
133724
  version: version2,
133727
133725
  state: props.proposedState
133728
133726
  };
133729
133727
  return {
133730
133728
  version: version2,
133731
- state: await provider2.updateResource(props)
133729
+ state: await provider$1.updateResource(props)
133732
133730
  };
133733
133731
  },
133734
133732
  async deleteResource({ type, ...props }) {
133735
133733
  await getProvider(type).deleteResource?.(props);
133736
133734
  },
133737
133735
  async planResourceChange({ type, ...props }) {
133738
- const provider2 = getProvider(type);
133739
- if (!provider2.planResourceChange)
133736
+ const provider$1 = getProvider(type);
133737
+ if (!provider$1.planResourceChange)
133740
133738
  return {
133741
133739
  version: version2,
133742
133740
  state: props.proposedState,
133743
133741
  requiresReplacement: false
133744
133742
  };
133745
- const result = await provider2.planResourceChange(props);
133746
133743
  return {
133747
133744
  version: version2,
133748
- ...result
133745
+ ...await provider$1.planResourceChange(props)
133749
133746
  };
133750
133747
  },
133751
133748
  async getData({ type, ...props }) {
@@ -141105,7 +141102,7 @@ if (!nativeAccelerationDisabled) {
141105
141102
  } catch (error3) {}
141106
141103
  }
141107
141104
 
141108
- // ../../node_modules/.pnpm/@terraforge+terraform@0.0.35_@terraforge+core@0.0.43_aws-crt@1.30.0_debug@4.4.3_support_5cbec650153056d375307c2d151398c3/node_modules/@terraforge/terraform/dist/index.mjs
141105
+ // ../../node_modules/.pnpm/@terraforge+terraform@0.0.35_@terraforge+core@0.0.44_aws-crt@1.30.0_debug@4.4.3_support_4501f5c353e25a801cf638e931a8dd2d/node_modules/@terraforge/terraform/dist/index.mjs
141109
141106
  var import_grpc_js = __toESM(require_src4(), 1);
141110
141107
  var import_proto_loader = __toESM(require_src3(), 1);
141111
141108
  var import_jszip = __toESM(require_lib3(), 1);
@@ -143616,7 +143613,7 @@ var createTerraformProxy = (props) => {
143616
143613
  });
143617
143614
  };
143618
143615
 
143619
- // ../../node_modules/.pnpm/@terraforge+aws@6.53.0_@terraforge+core@0.0.43_aws-crt@1.30.0_debug@4.4.3_supports-colo_8ae6ada9f1b5b5808a0d42265f99939f/node_modules/@terraforge/aws/dist/index.js
143616
+ // ../../node_modules/.pnpm/@terraforge+aws@6.53.0_@terraforge+core@0.0.44_aws-crt@1.30.0_debug@4.4.3_supports-colo_7835ee9c943a9b106f7a0c962824b2e8/node_modules/@terraforge/aws/dist/index.js
143620
143617
  var aws2 = createTerraformProxy({
143621
143618
  namespace: "aws",
143622
143619
  provider: { org: "hashicorp", type: "aws", version: "6.53.0" }
@@ -155610,7 +155607,11 @@ var createDnsValidatedCertificate = (group4, id, props) => {
155610
155607
  validationMethod: "DNS",
155611
155608
  keyAlgorithm: "RSA_2048",
155612
155609
  subjectAlternativeNames: props.subjectAlternativeNames
155613
- }, props.provider ? { provider: props.provider } : undefined);
155610
+ }, {
155611
+ ...props.provider ? { provider: props.provider } : {},
155612
+ replaceOnChanges: ["domainName", "subjectAlternativeNames"],
155613
+ createBeforeReplace: true
155614
+ });
155614
155615
  const option = (index) => {
155615
155616
  return certificate.domainValidationOptions.pipe((options) => {
155616
155617
  return options[index];
@@ -155623,6 +155624,8 @@ var createDnsValidatedCertificate = (group4, id, props) => {
155623
155624
  ttl: toSeconds2(minutes5(5)),
155624
155625
  records: [option(0).pipe((r4) => r4.resourceRecordValue)],
155625
155626
  allowOverwrite: true
155627
+ }, {
155628
+ replaceOnChanges: ["name", "type", "zoneId", "records"]
155626
155629
  });
155627
155630
  const record2 = new aws2.route53.Record(group4, `${props.recordIdPrefix}-2`, {
155628
155631
  zoneId: props.zoneId,
@@ -155631,14 +155634,18 @@ var createDnsValidatedCertificate = (group4, id, props) => {
155631
155634
  ttl: toSeconds2(minutes5(5)),
155632
155635
  records: [option(1).pipe((r4) => r4.resourceRecordValue)],
155633
155636
  allowOverwrite: true
155637
+ }, {
155638
+ replaceOnChanges: ["name", "type", "zoneId", "records"]
155634
155639
  });
155635
155640
  const validation = new aws2.acm.CertificateValidation(group4, id, {
155636
155641
  certificateArn: certificate.arn,
155637
155642
  validationRecordFqdns: [record1.fqdn, record2.fqdn]
155638
- }, props.provider || props.dependsOn ? {
155643
+ }, {
155639
155644
  ...props.dependsOn ? { dependsOn: props.dependsOn } : {},
155640
- ...props.provider ? { provider: props.provider } : {}
155641
- } : undefined);
155645
+ ...props.provider ? { provider: props.provider } : {},
155646
+ replaceOnChanges: ["certificateArn", "validationRecordFqdns"],
155647
+ createBeforeReplace: true
155648
+ });
155642
155649
  return validation;
155643
155650
  };
155644
155651
  var getDomainNameById = (config, id) => {
@@ -155679,9 +155686,14 @@ var domainFeature = defineFeature({
155679
155686
  const zone = new aws2.route53.Zone(ctx.zones, "zone", {
155680
155687
  name: props.domain,
155681
155688
  forceDestroy: true
155689
+ }, {
155690
+ replaceOnChanges: ["name"],
155691
+ createBeforeReplace: true
155682
155692
  });
155683
155693
  const nsCheck = new NsCheck(group5, "check", {
155684
155694
  zoneId: zone.id
155695
+ }, {
155696
+ replaceOnChanges: ["zoneId"]
155685
155697
  });
155686
155698
  ctx.registerDomainZone(zone);
155687
155699
  ctx.shared.add("domain", `zone-id`, id, zone.id);
@@ -155708,7 +155720,9 @@ var domainFeature = defineFeature({
155708
155720
  const identity = new aws2.ses.DomainIdentity(group5, "mail", {
155709
155721
  domain: props.domain
155710
155722
  }, {
155711
- import: ctx.import ? props.domain : undefined
155723
+ import: ctx.import ? props.domain : undefined,
155724
+ replaceOnChanges: ["domain"],
155725
+ createBeforeReplace: true
155712
155726
  });
155713
155727
  const verificationRecord = new aws2.route53.Record(group5, `verification`, {
155714
155728
  zoneId: zone.id,
@@ -155716,11 +155730,15 @@ var domainFeature = defineFeature({
155716
155730
  type: "TXT",
155717
155731
  ttl: toSeconds3(minutes6(5)),
155718
155732
  records: [identity.verificationToken]
155733
+ }, {
155734
+ replaceOnChanges: ["name", "type", "zoneId", "records"]
155719
155735
  });
155720
155736
  const dkim = new aws2.ses.DomainDkim(group5, "dkim", {
155721
155737
  domain: props.domain
155722
155738
  }, {
155723
- import: ctx.import ? props.domain : undefined
155739
+ import: ctx.import ? props.domain : undefined,
155740
+ replaceOnChanges: ["domain"],
155741
+ createBeforeReplace: true
155724
155742
  });
155725
155743
  for (let i3 = 0;i3 < 3; i3++) {
155726
155744
  new aws2.route53.Record(group5, `dkim-${i3}`, {
@@ -155729,6 +155747,8 @@ var domainFeature = defineFeature({
155729
155747
  name: dkim.dkimTokens.pipe((t2) => `${t2.at(i3)}._domainkey`),
155730
155748
  ttl: toSeconds3(minutes6(5)),
155731
155749
  records: [dkim.dkimTokens.pipe((t2) => `${t2.at(i3)}.dkim.amazonses.com`)]
155750
+ }, {
155751
+ replaceOnChanges: ["name", "type", "zoneId", "records"]
155732
155752
  });
155733
155753
  }
155734
155754
  const mailFrom = new aws2.ses.DomainMailFrom(group5, "mail-from", {
@@ -155736,7 +155756,9 @@ var domainFeature = defineFeature({
155736
155756
  mailFromDomain: `mail.${props.domain}`,
155737
155757
  behaviorOnMxFailure: "UseDefaultValue"
155738
155758
  }, {
155739
- import: ctx.import ? props.domain : undefined
155759
+ import: ctx.import ? props.domain : undefined,
155760
+ replaceOnChanges: ["domain"],
155761
+ createBeforeReplace: true
155740
155762
  });
155741
155763
  new aws2.route53.Record(group5, `MX`, {
155742
155764
  zoneId: zone.id,
@@ -155744,6 +155766,8 @@ var domainFeature = defineFeature({
155744
155766
  type: "MX",
155745
155767
  ttl: toSeconds3(minutes6(5)),
155746
155768
  records: [`10 feedback-smtp.${ctx.appConfig.region}.amazonses.com`]
155769
+ }, {
155770
+ replaceOnChanges: ["name", "type", "zoneId"]
155747
155771
  });
155748
155772
  new aws2.route53.Record(group5, `SPF`, {
155749
155773
  zoneId: zone.id,
@@ -155751,6 +155775,8 @@ var domainFeature = defineFeature({
155751
155775
  type: "TXT",
155752
155776
  ttl: toSeconds3(minutes6(5)),
155753
155777
  records: ["v=spf1 include:amazonses.com -all"]
155778
+ }, {
155779
+ replaceOnChanges: ["name", "type", "zoneId"]
155754
155780
  });
155755
155781
  new aws2.route53.Record(group5, `DMARC`, {
155756
155782
  zoneId: zone.id,
@@ -155758,8 +155784,13 @@ var domainFeature = defineFeature({
155758
155784
  type: "TXT",
155759
155785
  ttl: toSeconds3(minutes6(5)),
155760
155786
  records: ["v=DMARC1; p=none;"]
155787
+ }, {
155788
+ replaceOnChanges: ["name", "type", "zoneId"]
155789
+ });
155790
+ new aws2.ses.DomainIdentityVerification(group5, "mail", { domain: props.domain }, {
155791
+ dependsOn: [identity, verificationRecord, nsCheck],
155792
+ replaceOnChanges: ["domain"]
155761
155793
  });
155762
- new aws2.ses.DomainIdentityVerification(group5, "mail", { domain: props.domain }, { dependsOn: [identity, verificationRecord, nsCheck] });
155763
155794
  for (const record of props.dns ?? []) {
155764
155795
  const name = record.name ?? props.domain;
155765
155796
  new aws2.route53.Record(group5, `${name}-${record.type}`, {
@@ -155768,6 +155799,8 @@ var domainFeature = defineFeature({
155768
155799
  ttl: toSeconds3(record.ttl),
155769
155800
  type: record.type,
155770
155801
  records: record.records
155802
+ }, {
155803
+ replaceOnChanges: ["name", "type", "zoneId"]
155771
155804
  });
155772
155805
  }
155773
155806
  }
@@ -158400,11 +158433,16 @@ var restFeature = defineFeature({
158400
158433
  endpointType: "REGIONAL",
158401
158434
  securityPolicy: "TLS_1_2"
158402
158435
  }
158436
+ }, {
158437
+ replaceOnChanges: ["domainName", "domainNameConfiguration"],
158438
+ createBeforeReplace: true
158403
158439
  });
158404
158440
  const mapping = new aws2.apigatewayv2.ApiMapping(group4, "mapping", {
158405
158441
  apiId: api.id,
158406
158442
  domainName: domain.domainName,
158407
158443
  stage: stage.name
158444
+ }, {
158445
+ replaceOnChanges: ["domainName"]
158408
158446
  });
158409
158447
  new aws2.route53.Record(group4, "record", {
158410
158448
  zoneId,
@@ -158416,7 +158454,8 @@ var restFeature = defineFeature({
158416
158454
  evaluateTargetHealth: false
158417
158455
  }
158418
158456
  }, {
158419
- dependsOn: [mapping]
158457
+ dependsOn: [mapping],
158458
+ replaceOnChanges: ["name", "type", "zoneId", "alias"]
158420
158459
  });
158421
158460
  ctx.bind(`REST_${constantCase(id)}_ENDPOINT`, domainName);
158422
158461
  } else {
@@ -162855,6 +162894,8 @@ var routerFeature = defineFeature({
162855
162894
  zoneId: "Z2FDTNDATAQYW2",
162856
162895
  evaluateTargetHealth: false
162857
162896
  }
162897
+ }, {
162898
+ replaceOnChanges: ["name", "type", "zoneId", "alias"]
162858
162899
  });
162859
162900
  new aws2.route53.Record(group4, `${recordId}-ipv6`, {
162860
162901
  zoneId,
@@ -162865,6 +162906,8 @@ var routerFeature = defineFeature({
162865
162906
  zoneId: "Z2FDTNDATAQYW2",
162866
162907
  evaluateTargetHealth: false
162867
162908
  }
162909
+ }, {
162910
+ replaceOnChanges: ["name", "type", "zoneId", "alias"]
162868
162911
  });
162869
162912
  }
162870
162913
  ctx.bind(`ROUTER_${constantCase(id)}_ENDPOINT`, domainName);
@@ -164250,16 +164293,148 @@ var del9 = (program3) => {
164250
164293
  import { LambdaClient as LambdaClient4 } from "@aws-sdk/client-lambda";
164251
164294
  import { DynamoDBClient as DynamoDBClient4 } from "@awsless/dynamodb";
164252
164295
 
164296
+ // src/test/environment.ts
164297
+ import { mkdir as mkdir7, writeFile as writeFile10 } from "fs/promises";
164298
+ import { join as join47 } from "path";
164299
+
164300
+ // src/test/manifest.ts
164301
+ import { isAbsolute as isAbsolute5, join as join46 } from "path";
164302
+ var absolute = (file2) => {
164303
+ return isAbsolute5(file2) ? file2 : join46(directories.root, file2);
164304
+ };
164305
+ var createTestManifest = (appConfig, stackConfigs) => {
164306
+ const manifest = {
164307
+ app: appConfig.name,
164308
+ region: appConfig.region,
164309
+ configs: appConfig.test.configs,
164310
+ tables: [],
164311
+ tableKeys: [],
164312
+ streams: [],
164313
+ searches: [],
164314
+ functions: [],
164315
+ tasks: [],
164316
+ queues: [],
164317
+ topics: appConfig.topics ?? [],
164318
+ pubsub: Object.keys(appConfig.pubsub ?? {}),
164319
+ caches: [],
164320
+ alerts: Object.keys(appConfig.alerts ?? {}),
164321
+ jobs: [],
164322
+ instances: []
164323
+ };
164324
+ for (const stack of stackConfigs) {
164325
+ for (const [id, props] of Object.entries(stack.tables ?? {})) {
164326
+ const name = formatLocalResourceName({
164327
+ appName: appConfig.name,
164328
+ stackName: stack.name,
164329
+ resourceType: "table",
164330
+ resourceName: id
164331
+ });
164332
+ manifest.tables.push(createTableInput(name, props));
164333
+ manifest.tableKeys.push({ stack: stack.name, id, keys: formatTableKeys(props) });
164334
+ if (props.stream) {
164335
+ manifest.streams.push({
164336
+ stack: stack.name,
164337
+ id,
164338
+ file: absolute(props.stream.consumer.code.file),
164339
+ hash: props.hash,
164340
+ sort: props.sort
164341
+ });
164342
+ }
164343
+ }
164344
+ for (const [id, props] of Object.entries(stack.searchs ?? {})) {
164345
+ manifest.searches.push({
164346
+ stack: stack.name,
164347
+ id,
164348
+ mappings: resolveSearchMappings(props),
164349
+ settings: props.settings
164350
+ });
164351
+ }
164352
+ for (const [id, props] of Object.entries(stack.functions ?? {})) {
164353
+ manifest.functions.push({ stack: stack.name, id, file: absolute(props.code.file) });
164354
+ }
164355
+ for (const [id, props] of Object.entries(stack.tasks ?? {})) {
164356
+ manifest.tasks.push({ stack: stack.name, id, file: absolute(props.consumer.code.file) });
164357
+ }
164358
+ for (const [id, props] of Object.entries(stack.queues ?? {})) {
164359
+ manifest.queues.push({
164360
+ stack: stack.name,
164361
+ id,
164362
+ file: props.consumer ? absolute(props.consumer.code.file) : undefined
164363
+ });
164364
+ }
164365
+ for (const id of Object.keys(stack.caches ?? {})) {
164366
+ manifest.caches.push({ stack: stack.name, id });
164367
+ }
164368
+ for (const id of Object.keys(stack.jobs ?? {})) {
164369
+ manifest.jobs.push({ stack: stack.name, id });
164370
+ }
164371
+ for (const id of Object.keys(stack.instances ?? {})) {
164372
+ manifest.instances.push({ stack: stack.name, id });
164373
+ }
164374
+ }
164375
+ return manifest;
164376
+ };
164377
+
164378
+ // src/test/environment.ts
164379
+ var waitForSearch2 = async (port, timeoutMs) => {
164380
+ const deadline = Date.now() + timeoutMs;
164381
+ while (Date.now() < deadline) {
164382
+ try {
164383
+ const res = await fetch(`http://localhost:${port}`);
164384
+ if (res.ok) {
164385
+ return;
164386
+ }
164387
+ } catch (_4) {}
164388
+ await new Promise((resolve5) => setTimeout(resolve5, 500));
164389
+ }
164390
+ throw new Error("The local OpenSearch server never became ready.");
164391
+ };
164392
+ var withTestEnvironment = async (appConfig, stackConfigs, run) => {
164393
+ const manifest = createTestManifest(appConfig, stackConfigs);
164394
+ const manifestFile = join47(directories.output, "test", "manifest.json");
164395
+ let redis;
164396
+ let killSearch;
164397
+ manifest.servers = {};
164398
+ try {
164399
+ if (manifest.searches.length > 0) {
164400
+ const { download: download2, launch: launch2, VERSION_3_5_0_MIN: VERSION_3_5_0_MIN2 } = await Promise.resolve().then(() => (init_dist2(), exports_dist));
164401
+ const port = await findFreePort();
164402
+ const path6 = await download2(VERSION_3_5_0_MIN2);
164403
+ killSearch = await launch2({
164404
+ path: path6,
164405
+ port,
164406
+ host: "localhost",
164407
+ version: VERSION_3_5_0_MIN2,
164408
+ debug: false
164409
+ });
164410
+ await waitForSearch2(port, 60000);
164411
+ manifest.servers.search = { domain: `localhost:${port}` };
164412
+ }
164413
+ if (manifest.caches.length > 0) {
164414
+ redis = new RedisServer;
164415
+ await redis.start(undefined, undefined, ["--databases", "256"]);
164416
+ await redis.ping();
164417
+ manifest.servers.redis = { host: "127.0.0.1", port: await redis.getPort() };
164418
+ }
164419
+ await mkdir7(join47(directories.output, "test"), { recursive: true });
164420
+ await writeFile10(manifestFile, JSON.stringify(manifest));
164421
+ return await run({ manifest, manifestFile });
164422
+ } finally {
164423
+ await redis?.kill();
164424
+ await killSearch?.();
164425
+ }
164426
+ };
164427
+
164253
164428
  // src/cli/ui/complex/run-tests.ts
164254
164429
  var import_wildstring2 = __toESM(require_wildstring(), 1);
164255
- import { mkdir as mkdir7, readFile as readFile19, writeFile as writeFile10 } from "fs/promises";
164256
- import { join as join47 } from "path";
164430
+ import { mkdir as mkdir8, readFile as readFile19, writeFile as writeFile11 } from "fs/promises";
164431
+ import { join as join49 } from "path";
164257
164432
  import { parse as parse7, stringify as stringify4 } from "@awsless/json";
164258
164433
  import { generateFileHash as generateFileHash5, generateFolderHash, loadWorkspace as loadWorkspace2 } from "@awsless/ts-file-cache";
164259
164434
  import { createHash as createHash21 } from "crypto";
164260
164435
 
164261
164436
  // src/test/start.ts
164262
- import { dirname as dirname21, join as join46 } from "path";
164437
+ import { dirname as dirname21, join as join48 } from "path";
164263
164438
  import { fileURLToPath as fileURLToPath15 } from "url";
164264
164439
  import { configDefaults } from "vitest/config";
164265
164440
  import { startVitest } from "vitest/node";
@@ -164335,7 +164510,7 @@ var startTest = async (props) => {
164335
164510
  reporters: [new NullReporter],
164336
164511
  env: props.env,
164337
164512
  setupFiles: [
164338
- join46(__dirname4, "test-global-setup.js")
164513
+ join48(__dirname4, "test-global-setup.js")
164339
164514
  ]
164340
164515
  }, {
164341
164516
  logLevel: "silent",
@@ -164388,7 +164563,8 @@ var startTest = async (props) => {
164388
164563
  location: stack ? { line: stack.line, column: stack.column } : test.location,
164389
164564
  message: error3.message,
164390
164565
  diff: error3.diff,
164391
- type: error3.name
164566
+ type: error3.name,
164567
+ stack: error3.stack
164392
164568
  });
164393
164569
  }
164394
164570
  }
@@ -164397,7 +164573,8 @@ var startTest = async (props) => {
164397
164573
  errors3.push({
164398
164574
  type: error3.name,
164399
164575
  message: error3.message,
164400
- location: stack ? { line: stack.line, column: stack.column } : undefined
164576
+ location: stack ? { line: stack.line, column: stack.column } : undefined,
164577
+ stack: error3.stack
164401
164578
  });
164402
164579
  }
164403
164580
  }
@@ -164461,6 +164638,10 @@ var formatFileName = (test, error3) => {
164461
164638
  return name.join("");
164462
164639
  };
164463
164640
  var logTestError = (index, event, test, error3) => {
164641
+ if (error3.stack) {
164642
+ debug(`Test error in ${test.file} \u203A ${test.name}: ${error3.message}
164643
+ ${error3.stack}`);
164644
+ }
164464
164645
  const [message4, ...comment] = error3.message.split("//");
164465
164646
  const errorMessage = [
164466
164647
  color2.error.bold(error3.type + ":"),
@@ -164490,8 +164671,8 @@ var logTestErrors = (event) => {
164490
164671
  }
164491
164672
  };
164492
164673
  var runTest = async (stack, dir, filters, workspace, opts) => {
164493
- await mkdir7(directories.test, { recursive: true });
164494
- const file2 = join47(directories.test, `${stack}.json`);
164674
+ await mkdir8(directories.test, { recursive: true });
164675
+ const file2 = join49(directories.test, `${stack}.json`);
164495
164676
  const fingerprint = await generateFolderHash(workspace, dir) + (opts.fingerprint ?? "");
164496
164677
  if (!process.env.NO_CACHE) {
164497
164678
  const exists4 = await fileExist(file2);
@@ -164522,7 +164703,11 @@ var runTest = async (stack, dir, filters, workspace, opts) => {
164522
164703
  env: opts.env
164523
164704
  });
164524
164705
  if (result2.errors.length > 0) {
164525
- throw result2.errors.map((error3) => new ExpectedError(error3.message));
164706
+ for (const error3 of result2.errors) {
164707
+ debug(`Module error in ${stack} tests: ${error3.message}
164708
+ ${error3.stack ?? "(no stack captured)"}`);
164709
+ }
164710
+ throw result2.errors.map((error3) => new ExpectedError(error3.type && error3.type !== "Error" ? `${error3.type}: ${error3.message}` : error3.message));
164526
164711
  }
164527
164712
  ctx.updateSuccessMessage(formatResult({
164528
164713
  stack,
@@ -164536,7 +164721,7 @@ var runTest = async (stack, dir, filters, workspace, opts) => {
164536
164721
  logTestLogs(result);
164537
164722
  }
164538
164723
  logTestErrors(result);
164539
- await writeFile10(file2, stringify4({
164724
+ await writeFile11(file2, stringify4({
164540
164725
  ...result,
164541
164726
  fingerprint
164542
164727
  }));
@@ -164808,14 +164993,18 @@ var deploy = (program3) => {
164808
164993
  }
164809
164994
  }
164810
164995
  if (!options.skipTests) {
164811
- const passed = await runTests(tests, [], [], {
164812
- showLogs: false,
164813
- env: {
164814
- APP: appConfig.name,
164815
- APP_ID: appId,
164816
- AWS_REGION: appConfig.region,
164817
- AWS_ACCOUNT_ID: accountId
164818
- }
164996
+ const passed = await withTestEnvironment(appConfig, stackConfigs, ({ manifest, manifestFile }) => {
164997
+ return runTests(tests, [], [], {
164998
+ showLogs: false,
164999
+ manifest,
165000
+ env: {
165001
+ APP: appConfig.name,
165002
+ APP_ID: appId,
165003
+ AWS_REGION: appConfig.region,
165004
+ AWS_ACCOUNT_ID: accountId,
165005
+ AWSLESS_TEST_MANIFEST: manifestFile
165006
+ }
165007
+ });
164819
165008
  });
164820
165009
  if (!passed) {
164821
165010
  throw new ExpectedError("Tests failed.");
@@ -165371,12 +165560,12 @@ var auth = (program3) => {
165371
165560
 
165372
165561
  // src/cli/command/bind.ts
165373
165562
  import { readFile as readFile20 } from "fs/promises";
165374
- import { join as join48 } from "path";
165563
+ import { join as join50 } from "path";
165375
165564
  var bind = (program3) => {
165376
165565
  program3.command("bind").argument("[command...]", "The command to execute").option("--config <string...>", "List of config values that will be accessable", (v3) => v3.split(",")).option("--local", "Bind against the running local dev environment instead of the deployed app").description(`Bind your site environment variables to a command`).action(async (commands5 = [], opts) => {
165377
165566
  await layout("bind", async ({ appConfig, stackConfigs }) => {
165378
165567
  if (opts.local) {
165379
- const file2 = join48(directories.output, "local", "env.json");
165568
+ const file2 = join50(directories.output, "local", "env.json");
165380
165569
  let env5;
165381
165570
  try {
165382
165571
  env5 = JSON.parse(await readFile20(file2, "utf8"));
@@ -166172,18 +166361,18 @@ var watchConfig = async (options, resolve5, reject) => {
166172
166361
 
166173
166362
  // src/dev/index.ts
166174
166363
  import { loadWorkspace as loadWorkspace3 } from "@awsless/ts-file-cache";
166175
- import { mkdir as mkdir10, rm as rm12, writeFile as writeFile14 } from "fs/promises";
166176
- import { join as join55 } from "path";
166364
+ import { mkdir as mkdir11, rm as rm12, writeFile as writeFile15 } from "fs/promises";
166365
+ import { join as join57 } from "path";
166177
166366
 
166178
166367
  // src/dev/context.ts
166179
166368
  import { DynamoDBServer } from "@awsless/dynamodb-server";
166180
- import { join as join50 } from "path";
166369
+ import { join as join52 } from "path";
166181
166370
 
166182
166371
  // src/dev/servers/s3.ts
166183
166372
  import { createHash as createHash22 } from "crypto";
166184
- import { mkdir as mkdir8, readdir as readdir8, readFile as readFile21, rm as rm10, stat as stat7, writeFile as writeFile11 } from "fs/promises";
166373
+ import { mkdir as mkdir9, readdir as readdir8, readFile as readFile21, rm as rm10, stat as stat7, writeFile as writeFile12 } from "fs/promises";
166185
166374
  import { createServer as createServer7 } from "http";
166186
- import { dirname as dirname22, isAbsolute as isAbsolute5, join as join49, relative as relative10, sep as sep4 } from "path";
166375
+ import { dirname as dirname22, isAbsolute as isAbsolute6, join as join51, relative as relative10, sep as sep4 } from "path";
166187
166376
  var escapeXml = (value) => {
166188
166377
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
166189
166378
  };
@@ -166248,11 +166437,11 @@ var createS3Server = (props) => {
166248
166437
  res.end(xmlError("InvalidRequest", "Missing bucket name"));
166249
166438
  return;
166250
166439
  }
166251
- const bucketDir = join49(props.root, bucket);
166252
- const file2 = join49(bucketDir, ...keyParts);
166440
+ const bucketDir = join51(props.root, bucket);
166441
+ const file2 = join51(bucketDir, ...keyParts);
166253
166442
  const escapes = (base, path6) => {
166254
166443
  const rel = relative10(base, path6);
166255
- return rel.startsWith("..") || isAbsolute5(rel);
166444
+ return rel.startsWith("..") || isAbsolute6(rel);
166256
166445
  };
166257
166446
  if (escapes(props.root, bucketDir) || escapes(bucketDir, file2)) {
166258
166447
  res.writeHead(400, { "content-type": "application/xml" });
@@ -166270,7 +166459,7 @@ var createS3Server = (props) => {
166270
166459
  return;
166271
166460
  }
166272
166461
  for (const entry of entries2) {
166273
- const path6 = join49(dir, entry.name);
166462
+ const path6 = join51(dir, entry.name);
166274
166463
  if (entry.isDirectory()) {
166275
166464
  await walk2(path6);
166276
166465
  } else {
@@ -166296,8 +166485,8 @@ var createS3Server = (props) => {
166296
166485
  if (typeof encoding === "string" && encoding.includes("aws-chunked") || typeof sha === "string" && sha.startsWith("STREAMING")) {
166297
166486
  body = decodeAwsChunked(body);
166298
166487
  }
166299
- await mkdir8(dirname22(file2), { recursive: true });
166300
- await writeFile11(file2, body);
166488
+ await mkdir9(dirname22(file2), { recursive: true });
166489
+ await writeFile12(file2, body);
166301
166490
  const eTag = createHash22("md5").update(body).digest("hex");
166302
166491
  res.writeHead(200, { etag: `"${eTag}"` });
166303
166492
  res.end();
@@ -166738,7 +166927,7 @@ var createDevContext = (props) => {
166738
166927
  const value = await props.pool.keep("store", null, async () => {
166739
166928
  const rules = [];
166740
166929
  const server = createS3Server({
166741
- root: join50(directories.output, "local", "store"),
166930
+ root: join52(directories.output, "local", "store"),
166742
166931
  region: props.appConfig.region,
166743
166932
  rules
166744
166933
  });
@@ -166838,9 +167027,9 @@ var createDevContext = (props) => {
166838
167027
 
166839
167028
  // src/dev/seed.ts
166840
167029
  import { spawn as spawn6 } from "child_process";
166841
- import { isAbsolute as isAbsolute6, join as join51 } from "path";
167030
+ import { isAbsolute as isAbsolute7, join as join53 } from "path";
166842
167031
  var createSeedRunner = (props) => {
166843
- const file2 = props.seed && (isAbsolute6(props.seed) ? props.seed : join51(directories.root, props.seed));
167032
+ const file2 = props.seed && (isAbsolute7(props.seed) ? props.seed : join53(directories.root, props.seed));
166844
167033
  let running;
166845
167034
  const run = () => {
166846
167035
  running ??= (async () => {
@@ -166889,15 +167078,15 @@ var import_ioredis5 = __toESM(require_built3(), 1);
166889
167078
  import { DynamoDBClient as DynamoDBClient5 } from "@aws-sdk/client-dynamodb";
166890
167079
  import { DynamoDBDocumentClient, ScanCommand as ScanCommand2 } from "@aws-sdk/lib-dynamodb";
166891
167080
  import { randomUUID as randomUUID8 } from "crypto";
166892
- import { readdir as readdir9, readFile as readFile22, stat as stat8, writeFile as writeFile13 } from "fs/promises";
167081
+ import { readdir as readdir9, readFile as readFile22, stat as stat8, writeFile as writeFile14 } from "fs/promises";
166893
167082
  import { createServer as createServer9 } from "http";
166894
- import { join as join53, relative as relative11, sep as sep5 } from "path";
167083
+ import { join as join55, relative as relative11, sep as sep5 } from "path";
166895
167084
 
166896
167085
  // src/dev/worker.ts
166897
167086
  import { spawn as spawn7 } from "child_process";
166898
- import { writeFile as writeFile12 } from "fs/promises";
167087
+ import { writeFile as writeFile13 } from "fs/promises";
166899
167088
  import { availableParallelism } from "os";
166900
- import { join as join52 } from "path";
167089
+ import { join as join54 } from "path";
166901
167090
  class WorkerError extends Error {
166902
167091
  name;
166903
167092
  constructor(name, message4, stack) {
@@ -167014,7 +167203,7 @@ var createBundleWorker = (props) => {
167014
167203
  throw new Error("The bundle worker never became ready.");
167015
167204
  };
167016
167205
  const startWorker = async () => {
167017
- const entry = join52(props.buildDir, "worker.mjs");
167206
+ const entry = join54(props.buildDir, "worker.mjs");
167018
167207
  const port = await findFreePort();
167019
167208
  const child = spawn7("node", ["--enable-source-maps", entry], {
167020
167209
  cwd: props.buildDir,
@@ -167073,7 +167262,7 @@ var createBundleWorker = (props) => {
167073
167262
  return worker;
167074
167263
  };
167075
167264
  const doStart = async () => {
167076
- await writeFile12(join52(props.buildDir, "worker.mjs"), WORKER_ENTRY);
167265
+ await writeFile13(join54(props.buildDir, "worker.mjs"), WORKER_ENTRY);
167077
167266
  const results = await Promise.allSettled(Array.from({ length: concurrency }, () => startWorker()));
167078
167267
  const started = results.filter((result) => result.status === "fulfilled").map((result) => result.value);
167079
167268
  const failed = results.find((result) => result.status === "rejected");
@@ -167472,6 +167661,8 @@ const ICONS = {
167472
167661
  route: svg('<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>'),
167473
167662
  site: svg('<rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/>'),
167474
167663
  seed: svg('<path d="M12 22V8"/><path d="M12 8C12 5 9 2 5 2c0 4 3 6 7 6z"/><path d="M12 12c0-3 3-6 7-6 0 4-3 6-7 6z"/>'),
167664
+ auth: svg('<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>'),
167665
+ worker: svg('<polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/>'),
167475
167666
  }
167476
167667
 
167477
167668
  const icon = kind => {
@@ -168737,7 +168928,7 @@ var createDashboardServer = (props) => {
168737
168928
  return;
168738
168929
  }
168739
168930
  for (const entry of entries2) {
168740
- const path6 = join53(dir, entry.name);
168931
+ const path6 = join55(dir, entry.name);
168741
168932
  if (entry.isDirectory()) {
168742
168933
  await walk2(path6);
168743
168934
  } else {
@@ -168802,7 +168993,7 @@ var createDashboardServer = (props) => {
168802
168993
  if (url.pathname === "/api/config") {
168803
168994
  if (req.method === "PUT") {
168804
168995
  const values2 = JSON.parse((await readBody(req)).toString() || "{}");
168805
- await writeFile13(props.configFile, JSON.stringify(values2, null, "\t") + `
168996
+ await writeFile14(props.configFile, JSON.stringify(values2, null, "\t") + `
168806
168997
  `);
168807
168998
  return { status: 200, body: JSON.stringify({ ok: true }) };
168808
168999
  }
@@ -169048,17 +169239,17 @@ var createLambdaServer = (props) => {
169048
169239
  };
169049
169240
 
169050
169241
  // src/dev/sdk.ts
169051
- import { readdir as readdir10, readFile as readFile23, mkdir as mkdir9, rm as rm11, stat as stat9, symlink } from "fs/promises";
169242
+ import { readdir as readdir10, readFile as readFile23, mkdir as mkdir10, rm as rm11, stat as stat9, symlink } from "fs/promises";
169052
169243
  import { createRequire } from "module";
169053
- import { dirname as dirname23, join as join54 } from "path";
169244
+ import { dirname as dirname23, join as join56 } from "path";
169054
169245
  var linkSdkPackages = async (buildDir, onWarn) => {
169055
- const filesDir = join54(buildDir, "files");
169246
+ const filesDir = join56(buildDir, "files");
169056
169247
  const packages = new Set;
169057
169248
  for (const file2 of await readdir10(filesDir)) {
169058
169249
  if (!file2.endsWith(".mjs")) {
169059
169250
  continue;
169060
169251
  }
169061
- const code = await readFile23(join54(filesDir, file2), "utf8");
169252
+ const code = await readFile23(join56(filesDir, file2), "utf8");
169062
169253
  for (const match3 of code.matchAll(/(?:from\s*|import\()\s*["'](@aws-sdk\/[a-z0-9-]+|sharp)["']/g)) {
169063
169254
  packages.add(match3[1]);
169064
169255
  }
@@ -169066,25 +169257,25 @@ var linkSdkPackages = async (buildDir, onWarn) => {
169066
169257
  const ownRequire = createRequire(import.meta.url);
169067
169258
  const isProjectDep = async (name) => {
169068
169259
  try {
169069
- await stat9(join54(directories.root, "node_modules", name, "package.json"));
169260
+ await stat9(join56(directories.root, "node_modules", name, "package.json"));
169070
169261
  return true;
169071
169262
  } catch (_4) {
169072
169263
  return false;
169073
169264
  }
169074
169265
  };
169075
169266
  const resolveFromStore = async (name) => {
169076
- const store = join54(directories.root, "node_modules", ".pnpm");
169267
+ const store = join56(directories.root, "node_modules", ".pnpm");
169077
169268
  const prefix = name.replaceAll("/", "+") + "@";
169078
169269
  try {
169079
169270
  const entries2 = (await readdir10(store)).filter((entry) => entry.startsWith(prefix));
169080
169271
  const best = entries2.sort((a4, b6) => a4.slice(prefix.length).localeCompare(b6.slice(prefix.length), undefined, { numeric: true })).at(-1);
169081
- return best ? join54(store, best, "node_modules", name) : undefined;
169272
+ return best ? join56(store, best, "node_modules", name) : undefined;
169082
169273
  } catch (_4) {
169083
169274
  return;
169084
169275
  }
169085
169276
  };
169086
169277
  for (const name of packages) {
169087
- const target2 = join54(buildDir, "node_modules", name);
169278
+ const target2 = join56(buildDir, "node_modules", name);
169088
169279
  try {
169089
169280
  if (await isProjectDep(name)) {
169090
169281
  await rm11(target2, { recursive: true, force: true });
@@ -169100,10 +169291,10 @@ var linkSdkPackages = async (buildDir, onWarn) => {
169100
169291
  continue;
169101
169292
  }
169102
169293
  }
169103
- await mkdir9(dirname23(target2), { recursive: true });
169294
+ await mkdir10(dirname23(target2), { recursive: true });
169104
169295
  await rm11(target2, { recursive: true, force: true });
169105
169296
  await symlink(source, target2, "dir");
169106
- await stat9(join54(target2, "package.json"));
169297
+ await stat9(join56(target2, "package.json"));
169107
169298
  debug(`Sdk link ${name}: ${source}`);
169108
169299
  } catch (error3) {
169109
169300
  onWarn?.(`Linking the "${name}" sdk package failed: ${error3 instanceof Error ? error3.message : String(error3)}`);
@@ -169127,7 +169318,7 @@ var startDev = async (props) => {
169127
169318
  dev: true
169128
169319
  });
169129
169320
  ready2();
169130
- await mkdir10(join55(directories.output, "local"), { recursive: true });
169321
+ await mkdir11(join57(directories.output, "local"), { recursive: true });
169131
169322
  const routerPorts = {};
169132
169323
  Object.keys(appConfig.router ?? {}).forEach((id, index) => {
169133
169324
  routerPorts[id] = props.port + 1 + index;
@@ -169182,7 +169373,7 @@ var startDev = async (props) => {
169182
169373
  for (const [id, port] of Object.entries(routerPorts)) {
169183
169374
  env5[`ROUTER_${constantCase(id)}_ENDPOINT`] = `localhost:${port}`;
169184
169375
  }
169185
- await writeFile14(join55(directories.output, "local", "env.json"), JSON.stringify(env5, null, "\t") + `
169376
+ await writeFile15(join57(directories.output, "local", "env.json"), JSON.stringify(env5, null, "\t") + `
169186
169377
  `);
169187
169378
  return { env: env5, lambda: lambda2 };
169188
169379
  });
@@ -169197,7 +169388,7 @@ var startDev = async (props) => {
169197
169388
  }
169198
169389
  debug(`Build ${builder.type}:${builder.name}`, meta?.cached ? "cached" : String(meta?.buildTime));
169199
169390
  }
169200
- await writeFile14(getBuildPath("bundle", bundleName, "files/awsless-env.mjs"), `export default {}
169391
+ await writeFile15(getBuildPath("bundle", bundleName, "files/awsless-env.mjs"), `export default {}
169201
169392
  `);
169202
169393
  await linkSdkPackages(buildDir, log);
169203
169394
  return changed;
@@ -169324,8 +169515,8 @@ var startDev = async (props) => {
169324
169515
  resources: dev.resources,
169325
169516
  routes: dev.routes,
169326
169517
  env: env4,
169327
- storeRoot: join55(directories.output, "local", "store"),
169328
- configFile: join55(directories.output, "local", "config.json"),
169518
+ storeRoot: join57(directories.output, "local", "store"),
169519
+ configFile: join57(directories.output, "local", "config.json"),
169329
169520
  getEmails: () => props.pool.peek("shim:ses-email")?.server.list() ?? [],
169330
169521
  configPulled: Object.keys(props.pool.peek("config:pull") ?? {}),
169331
169522
  auth: createAuthAdmin({
@@ -169367,7 +169558,7 @@ var startDev = async (props) => {
169367
169558
  routerPorts,
169368
169559
  async stop() {
169369
169560
  stopping = true;
169370
- await rm12(join55(directories.output, "local", "env.json"), { force: true });
169561
+ await rm12(join57(directories.output, "local", "env.json"), { force: true });
169371
169562
  clearTimeout(rebuildTimer);
169372
169563
  await watcher.close();
169373
169564
  await restartWatcher?.close();
@@ -169432,8 +169623,8 @@ var createServerPool = () => {
169432
169623
  };
169433
169624
 
169434
169625
  // src/type-gen/generate.ts
169435
- import { mkdir as mkdir11, writeFile as writeFile15 } from "fs/promises";
169436
- import { dirname as dirname24, join as join56, relative as relative12 } from "path";
169626
+ import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
169627
+ import { dirname as dirname24, join as join58, relative as relative12 } from "path";
169437
169628
  var generateTypes = async (props) => {
169438
169629
  const files = [];
169439
169630
  await Promise.all(features.map((feature) => {
@@ -169441,13 +169632,13 @@ var generateTypes = async (props) => {
169441
169632
  ...props,
169442
169633
  async write(file2, data, include = false) {
169443
169634
  const code = data?.toString("utf8");
169444
- const path6 = join56(directories.types, file2);
169635
+ const path6 = join58(directories.types, file2);
169445
169636
  if (code) {
169446
169637
  if (include) {
169447
169638
  files.push(relative12(directories.root, path6));
169448
169639
  }
169449
- await mkdir11(dirname24(path6), { recursive: true });
169450
- await writeFile15(path6, code);
169640
+ await mkdir12(dirname24(path6), { recursive: true });
169641
+ await writeFile16(path6, code);
169451
169642
  }
169452
169643
  }
169453
169644
  });
@@ -169455,7 +169646,7 @@ var generateTypes = async (props) => {
169455
169646
  if (files.length) {
169456
169647
  const code = files.map((file2) => `/// <reference path='${file2}' />`).join(`
169457
169648
  `);
169458
- await writeFile15(join56(directories.root, `awsless.d.ts`), code);
169649
+ await writeFile16(join58(directories.root, `awsless.d.ts`), code);
169459
169650
  }
169460
169651
  };
169461
169652
 
@@ -185107,101 +185298,6 @@ var state = (program3) => {
185107
185298
  };
185108
185299
 
185109
185300
  // src/cli/command/test.ts
185110
- import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
185111
- import { join as join58 } from "path";
185112
-
185113
- // src/test/manifest.ts
185114
- import { isAbsolute as isAbsolute7, join as join57 } from "path";
185115
- var absolute = (file2) => {
185116
- return isAbsolute7(file2) ? file2 : join57(directories.root, file2);
185117
- };
185118
- var createTestManifest = (appConfig, stackConfigs) => {
185119
- const manifest = {
185120
- app: appConfig.name,
185121
- region: appConfig.region,
185122
- configs: appConfig.test.configs,
185123
- tables: [],
185124
- tableKeys: [],
185125
- streams: [],
185126
- searches: [],
185127
- functions: [],
185128
- tasks: [],
185129
- queues: [],
185130
- topics: appConfig.topics ?? [],
185131
- pubsub: Object.keys(appConfig.pubsub ?? {}),
185132
- caches: [],
185133
- alerts: Object.keys(appConfig.alerts ?? {}),
185134
- jobs: [],
185135
- instances: []
185136
- };
185137
- for (const stack of stackConfigs) {
185138
- for (const [id, props] of Object.entries(stack.tables ?? {})) {
185139
- const name = formatLocalResourceName({
185140
- appName: appConfig.name,
185141
- stackName: stack.name,
185142
- resourceType: "table",
185143
- resourceName: id
185144
- });
185145
- manifest.tables.push(createTableInput(name, props));
185146
- manifest.tableKeys.push({ stack: stack.name, id, keys: formatTableKeys(props) });
185147
- if (props.stream) {
185148
- manifest.streams.push({
185149
- stack: stack.name,
185150
- id,
185151
- file: absolute(props.stream.consumer.code.file),
185152
- hash: props.hash,
185153
- sort: props.sort
185154
- });
185155
- }
185156
- }
185157
- for (const [id, props] of Object.entries(stack.searchs ?? {})) {
185158
- manifest.searches.push({
185159
- stack: stack.name,
185160
- id,
185161
- mappings: resolveSearchMappings(props),
185162
- settings: props.settings
185163
- });
185164
- }
185165
- for (const [id, props] of Object.entries(stack.functions ?? {})) {
185166
- manifest.functions.push({ stack: stack.name, id, file: absolute(props.code.file) });
185167
- }
185168
- for (const [id, props] of Object.entries(stack.tasks ?? {})) {
185169
- manifest.tasks.push({ stack: stack.name, id, file: absolute(props.consumer.code.file) });
185170
- }
185171
- for (const [id, props] of Object.entries(stack.queues ?? {})) {
185172
- manifest.queues.push({
185173
- stack: stack.name,
185174
- id,
185175
- file: props.consumer ? absolute(props.consumer.code.file) : undefined
185176
- });
185177
- }
185178
- for (const id of Object.keys(stack.caches ?? {})) {
185179
- manifest.caches.push({ stack: stack.name, id });
185180
- }
185181
- for (const id of Object.keys(stack.jobs ?? {})) {
185182
- manifest.jobs.push({ stack: stack.name, id });
185183
- }
185184
- for (const id of Object.keys(stack.instances ?? {})) {
185185
- manifest.instances.push({ stack: stack.name, id });
185186
- }
185187
- }
185188
- return manifest;
185189
- };
185190
-
185191
- // src/cli/command/test.ts
185192
- var waitForSearch2 = async (port, timeoutMs) => {
185193
- const deadline = Date.now() + timeoutMs;
185194
- while (Date.now() < deadline) {
185195
- try {
185196
- const res = await fetch(`http://localhost:${port}`);
185197
- if (res.ok) {
185198
- return;
185199
- }
185200
- } catch (_4) {}
185201
- await new Promise((resolve5) => setTimeout(resolve5, 500));
185202
- }
185203
- throw new Error("The local OpenSearch server never became ready.");
185204
- };
185205
185301
  var test2 = (program3) => {
185206
185302
  program3.command("test").argument("[stacks...]", "Optionally filter stacks to test").option("-f --filters <string...>", "Optionally filter test files").description("Test your app").action(async (stacks, options) => {
185207
185303
  await layout(`test ${stacks ?? ""}`, async (props) => {
@@ -185210,36 +185306,8 @@ var test2 = (program3) => {
185210
185306
  if (tests.length === 0) {
185211
185307
  return "No tests found.";
185212
185308
  }
185213
- const manifest = createTestManifest(props.appConfig, props.stackConfigs);
185214
- const manifestFile = join58(directories.output, "test", "manifest.json");
185215
- let redis;
185216
- let killSearch;
185217
- manifest.servers = {};
185218
- let passed = false;
185219
- try {
185220
- if (manifest.searches.length > 0) {
185221
- const { download: download2, launch: launch2, VERSION_3_5_0_MIN: VERSION_3_5_0_MIN2 } = await Promise.resolve().then(() => (init_dist2(), exports_dist));
185222
- const port = await findFreePort();
185223
- const path6 = await download2(VERSION_3_5_0_MIN2);
185224
- killSearch = await launch2({
185225
- path: path6,
185226
- port,
185227
- host: "localhost",
185228
- version: VERSION_3_5_0_MIN2,
185229
- debug: false
185230
- });
185231
- await waitForSearch2(port, 60000);
185232
- manifest.servers.search = { domain: `localhost:${port}` };
185233
- }
185234
- if (manifest.caches.length > 0) {
185235
- redis = new RedisServer;
185236
- await redis.start(undefined, undefined, ["--databases", "256"]);
185237
- await redis.ping();
185238
- manifest.servers.redis = { host: "127.0.0.1", port: await redis.getPort() };
185239
- }
185240
- await mkdir12(join58(directories.output, "test"), { recursive: true });
185241
- await writeFile16(manifestFile, JSON.stringify(manifest));
185242
- passed = await runTests(tests, stacks, options?.filters, {
185309
+ const passed = await withTestEnvironment(props.appConfig, props.stackConfigs, ({ manifest, manifestFile }) => {
185310
+ return runTests(tests, stacks, options?.filters, {
185243
185311
  showLogs: true,
185244
185312
  manifest,
185245
185313
  env: {
@@ -185250,10 +185318,7 @@ var test2 = (program3) => {
185250
185318
  AWSLESS_TEST_MANIFEST: manifestFile
185251
185319
  }
185252
185320
  });
185253
- } finally {
185254
- await redis?.kill();
185255
- await killSearch?.();
185256
- }
185321
+ });
185257
185322
  if (!passed) {
185258
185323
  throw new ExpectedError("Tests failed.");
185259
185324
  }