@awsless/cli 0.1.3 → 0.1.4

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 +370 -318
  2. package/package.json +14 -14
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,17 @@ 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
+ });
155642
155648
  return validation;
155643
155649
  };
155644
155650
  var getDomainNameById = (config, id) => {
@@ -155679,9 +155685,14 @@ var domainFeature = defineFeature({
155679
155685
  const zone = new aws2.route53.Zone(ctx.zones, "zone", {
155680
155686
  name: props.domain,
155681
155687
  forceDestroy: true
155688
+ }, {
155689
+ replaceOnChanges: ["name"],
155690
+ createBeforeReplace: true
155682
155691
  });
155683
155692
  const nsCheck = new NsCheck(group5, "check", {
155684
155693
  zoneId: zone.id
155694
+ }, {
155695
+ replaceOnChanges: ["zoneId"]
155685
155696
  });
155686
155697
  ctx.registerDomainZone(zone);
155687
155698
  ctx.shared.add("domain", `zone-id`, id, zone.id);
@@ -155708,7 +155719,9 @@ var domainFeature = defineFeature({
155708
155719
  const identity = new aws2.ses.DomainIdentity(group5, "mail", {
155709
155720
  domain: props.domain
155710
155721
  }, {
155711
- import: ctx.import ? props.domain : undefined
155722
+ import: ctx.import ? props.domain : undefined,
155723
+ replaceOnChanges: ["domain"],
155724
+ createBeforeReplace: true
155712
155725
  });
155713
155726
  const verificationRecord = new aws2.route53.Record(group5, `verification`, {
155714
155727
  zoneId: zone.id,
@@ -155716,11 +155729,15 @@ var domainFeature = defineFeature({
155716
155729
  type: "TXT",
155717
155730
  ttl: toSeconds3(minutes6(5)),
155718
155731
  records: [identity.verificationToken]
155732
+ }, {
155733
+ replaceOnChanges: ["name", "type", "zoneId", "records"]
155719
155734
  });
155720
155735
  const dkim = new aws2.ses.DomainDkim(group5, "dkim", {
155721
155736
  domain: props.domain
155722
155737
  }, {
155723
- import: ctx.import ? props.domain : undefined
155738
+ import: ctx.import ? props.domain : undefined,
155739
+ replaceOnChanges: ["domain"],
155740
+ createBeforeReplace: true
155724
155741
  });
155725
155742
  for (let i3 = 0;i3 < 3; i3++) {
155726
155743
  new aws2.route53.Record(group5, `dkim-${i3}`, {
@@ -155729,6 +155746,8 @@ var domainFeature = defineFeature({
155729
155746
  name: dkim.dkimTokens.pipe((t2) => `${t2.at(i3)}._domainkey`),
155730
155747
  ttl: toSeconds3(minutes6(5)),
155731
155748
  records: [dkim.dkimTokens.pipe((t2) => `${t2.at(i3)}.dkim.amazonses.com`)]
155749
+ }, {
155750
+ replaceOnChanges: ["name", "type", "zoneId", "records"]
155732
155751
  });
155733
155752
  }
155734
155753
  const mailFrom = new aws2.ses.DomainMailFrom(group5, "mail-from", {
@@ -155736,7 +155755,9 @@ var domainFeature = defineFeature({
155736
155755
  mailFromDomain: `mail.${props.domain}`,
155737
155756
  behaviorOnMxFailure: "UseDefaultValue"
155738
155757
  }, {
155739
- import: ctx.import ? props.domain : undefined
155758
+ import: ctx.import ? props.domain : undefined,
155759
+ replaceOnChanges: ["domain"],
155760
+ createBeforeReplace: true
155740
155761
  });
155741
155762
  new aws2.route53.Record(group5, `MX`, {
155742
155763
  zoneId: zone.id,
@@ -155744,6 +155765,8 @@ var domainFeature = defineFeature({
155744
155765
  type: "MX",
155745
155766
  ttl: toSeconds3(minutes6(5)),
155746
155767
  records: [`10 feedback-smtp.${ctx.appConfig.region}.amazonses.com`]
155768
+ }, {
155769
+ replaceOnChanges: ["name", "type", "zoneId"]
155747
155770
  });
155748
155771
  new aws2.route53.Record(group5, `SPF`, {
155749
155772
  zoneId: zone.id,
@@ -155751,6 +155774,8 @@ var domainFeature = defineFeature({
155751
155774
  type: "TXT",
155752
155775
  ttl: toSeconds3(minutes6(5)),
155753
155776
  records: ["v=spf1 include:amazonses.com -all"]
155777
+ }, {
155778
+ replaceOnChanges: ["name", "type", "zoneId"]
155754
155779
  });
155755
155780
  new aws2.route53.Record(group5, `DMARC`, {
155756
155781
  zoneId: zone.id,
@@ -155758,8 +155783,13 @@ var domainFeature = defineFeature({
155758
155783
  type: "TXT",
155759
155784
  ttl: toSeconds3(minutes6(5)),
155760
155785
  records: ["v=DMARC1; p=none;"]
155786
+ }, {
155787
+ replaceOnChanges: ["name", "type", "zoneId"]
155788
+ });
155789
+ new aws2.ses.DomainIdentityVerification(group5, "mail", { domain: props.domain }, {
155790
+ dependsOn: [identity, verificationRecord, nsCheck],
155791
+ replaceOnChanges: ["domain"]
155761
155792
  });
155762
- new aws2.ses.DomainIdentityVerification(group5, "mail", { domain: props.domain }, { dependsOn: [identity, verificationRecord, nsCheck] });
155763
155793
  for (const record of props.dns ?? []) {
155764
155794
  const name = record.name ?? props.domain;
155765
155795
  new aws2.route53.Record(group5, `${name}-${record.type}`, {
@@ -155768,6 +155798,8 @@ var domainFeature = defineFeature({
155768
155798
  ttl: toSeconds3(record.ttl),
155769
155799
  type: record.type,
155770
155800
  records: record.records
155801
+ }, {
155802
+ replaceOnChanges: ["name", "type", "zoneId"]
155771
155803
  });
155772
155804
  }
155773
155805
  }
@@ -158400,11 +158432,16 @@ var restFeature = defineFeature({
158400
158432
  endpointType: "REGIONAL",
158401
158433
  securityPolicy: "TLS_1_2"
158402
158434
  }
158435
+ }, {
158436
+ replaceOnChanges: ["domainName", "domainNameConfiguration"],
158437
+ createBeforeReplace: true
158403
158438
  });
158404
158439
  const mapping = new aws2.apigatewayv2.ApiMapping(group4, "mapping", {
158405
158440
  apiId: api.id,
158406
158441
  domainName: domain.domainName,
158407
158442
  stage: stage.name
158443
+ }, {
158444
+ replaceOnChanges: ["domainName"]
158408
158445
  });
158409
158446
  new aws2.route53.Record(group4, "record", {
158410
158447
  zoneId,
@@ -158416,7 +158453,8 @@ var restFeature = defineFeature({
158416
158453
  evaluateTargetHealth: false
158417
158454
  }
158418
158455
  }, {
158419
- dependsOn: [mapping]
158456
+ dependsOn: [mapping],
158457
+ replaceOnChanges: ["name", "type", "zoneId", "alias"]
158420
158458
  });
158421
158459
  ctx.bind(`REST_${constantCase(id)}_ENDPOINT`, domainName);
158422
158460
  } else {
@@ -162855,6 +162893,8 @@ var routerFeature = defineFeature({
162855
162893
  zoneId: "Z2FDTNDATAQYW2",
162856
162894
  evaluateTargetHealth: false
162857
162895
  }
162896
+ }, {
162897
+ replaceOnChanges: ["name", "type", "zoneId", "alias"]
162858
162898
  });
162859
162899
  new aws2.route53.Record(group4, `${recordId}-ipv6`, {
162860
162900
  zoneId,
@@ -162865,6 +162905,8 @@ var routerFeature = defineFeature({
162865
162905
  zoneId: "Z2FDTNDATAQYW2",
162866
162906
  evaluateTargetHealth: false
162867
162907
  }
162908
+ }, {
162909
+ replaceOnChanges: ["name", "type", "zoneId", "alias"]
162868
162910
  });
162869
162911
  }
162870
162912
  ctx.bind(`ROUTER_${constantCase(id)}_ENDPOINT`, domainName);
@@ -164250,16 +164292,148 @@ var del9 = (program3) => {
164250
164292
  import { LambdaClient as LambdaClient4 } from "@aws-sdk/client-lambda";
164251
164293
  import { DynamoDBClient as DynamoDBClient4 } from "@awsless/dynamodb";
164252
164294
 
164295
+ // src/test/environment.ts
164296
+ import { mkdir as mkdir7, writeFile as writeFile10 } from "fs/promises";
164297
+ import { join as join47 } from "path";
164298
+
164299
+ // src/test/manifest.ts
164300
+ import { isAbsolute as isAbsolute5, join as join46 } from "path";
164301
+ var absolute = (file2) => {
164302
+ return isAbsolute5(file2) ? file2 : join46(directories.root, file2);
164303
+ };
164304
+ var createTestManifest = (appConfig, stackConfigs) => {
164305
+ const manifest = {
164306
+ app: appConfig.name,
164307
+ region: appConfig.region,
164308
+ configs: appConfig.test.configs,
164309
+ tables: [],
164310
+ tableKeys: [],
164311
+ streams: [],
164312
+ searches: [],
164313
+ functions: [],
164314
+ tasks: [],
164315
+ queues: [],
164316
+ topics: appConfig.topics ?? [],
164317
+ pubsub: Object.keys(appConfig.pubsub ?? {}),
164318
+ caches: [],
164319
+ alerts: Object.keys(appConfig.alerts ?? {}),
164320
+ jobs: [],
164321
+ instances: []
164322
+ };
164323
+ for (const stack of stackConfigs) {
164324
+ for (const [id, props] of Object.entries(stack.tables ?? {})) {
164325
+ const name = formatLocalResourceName({
164326
+ appName: appConfig.name,
164327
+ stackName: stack.name,
164328
+ resourceType: "table",
164329
+ resourceName: id
164330
+ });
164331
+ manifest.tables.push(createTableInput(name, props));
164332
+ manifest.tableKeys.push({ stack: stack.name, id, keys: formatTableKeys(props) });
164333
+ if (props.stream) {
164334
+ manifest.streams.push({
164335
+ stack: stack.name,
164336
+ id,
164337
+ file: absolute(props.stream.consumer.code.file),
164338
+ hash: props.hash,
164339
+ sort: props.sort
164340
+ });
164341
+ }
164342
+ }
164343
+ for (const [id, props] of Object.entries(stack.searchs ?? {})) {
164344
+ manifest.searches.push({
164345
+ stack: stack.name,
164346
+ id,
164347
+ mappings: resolveSearchMappings(props),
164348
+ settings: props.settings
164349
+ });
164350
+ }
164351
+ for (const [id, props] of Object.entries(stack.functions ?? {})) {
164352
+ manifest.functions.push({ stack: stack.name, id, file: absolute(props.code.file) });
164353
+ }
164354
+ for (const [id, props] of Object.entries(stack.tasks ?? {})) {
164355
+ manifest.tasks.push({ stack: stack.name, id, file: absolute(props.consumer.code.file) });
164356
+ }
164357
+ for (const [id, props] of Object.entries(stack.queues ?? {})) {
164358
+ manifest.queues.push({
164359
+ stack: stack.name,
164360
+ id,
164361
+ file: props.consumer ? absolute(props.consumer.code.file) : undefined
164362
+ });
164363
+ }
164364
+ for (const id of Object.keys(stack.caches ?? {})) {
164365
+ manifest.caches.push({ stack: stack.name, id });
164366
+ }
164367
+ for (const id of Object.keys(stack.jobs ?? {})) {
164368
+ manifest.jobs.push({ stack: stack.name, id });
164369
+ }
164370
+ for (const id of Object.keys(stack.instances ?? {})) {
164371
+ manifest.instances.push({ stack: stack.name, id });
164372
+ }
164373
+ }
164374
+ return manifest;
164375
+ };
164376
+
164377
+ // src/test/environment.ts
164378
+ var waitForSearch2 = async (port, timeoutMs) => {
164379
+ const deadline = Date.now() + timeoutMs;
164380
+ while (Date.now() < deadline) {
164381
+ try {
164382
+ const res = await fetch(`http://localhost:${port}`);
164383
+ if (res.ok) {
164384
+ return;
164385
+ }
164386
+ } catch (_4) {}
164387
+ await new Promise((resolve5) => setTimeout(resolve5, 500));
164388
+ }
164389
+ throw new Error("The local OpenSearch server never became ready.");
164390
+ };
164391
+ var withTestEnvironment = async (appConfig, stackConfigs, run) => {
164392
+ const manifest = createTestManifest(appConfig, stackConfigs);
164393
+ const manifestFile = join47(directories.output, "test", "manifest.json");
164394
+ let redis;
164395
+ let killSearch;
164396
+ manifest.servers = {};
164397
+ try {
164398
+ if (manifest.searches.length > 0) {
164399
+ const { download: download2, launch: launch2, VERSION_3_5_0_MIN: VERSION_3_5_0_MIN2 } = await Promise.resolve().then(() => (init_dist2(), exports_dist));
164400
+ const port = await findFreePort();
164401
+ const path6 = await download2(VERSION_3_5_0_MIN2);
164402
+ killSearch = await launch2({
164403
+ path: path6,
164404
+ port,
164405
+ host: "localhost",
164406
+ version: VERSION_3_5_0_MIN2,
164407
+ debug: false
164408
+ });
164409
+ await waitForSearch2(port, 60000);
164410
+ manifest.servers.search = { domain: `localhost:${port}` };
164411
+ }
164412
+ if (manifest.caches.length > 0) {
164413
+ redis = new RedisServer;
164414
+ await redis.start(undefined, undefined, ["--databases", "256"]);
164415
+ await redis.ping();
164416
+ manifest.servers.redis = { host: "127.0.0.1", port: await redis.getPort() };
164417
+ }
164418
+ await mkdir7(join47(directories.output, "test"), { recursive: true });
164419
+ await writeFile10(manifestFile, JSON.stringify(manifest));
164420
+ return await run({ manifest, manifestFile });
164421
+ } finally {
164422
+ await redis?.kill();
164423
+ await killSearch?.();
164424
+ }
164425
+ };
164426
+
164253
164427
  // src/cli/ui/complex/run-tests.ts
164254
164428
  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";
164429
+ import { mkdir as mkdir8, readFile as readFile19, writeFile as writeFile11 } from "fs/promises";
164430
+ import { join as join49 } from "path";
164257
164431
  import { parse as parse7, stringify as stringify4 } from "@awsless/json";
164258
164432
  import { generateFileHash as generateFileHash5, generateFolderHash, loadWorkspace as loadWorkspace2 } from "@awsless/ts-file-cache";
164259
164433
  import { createHash as createHash21 } from "crypto";
164260
164434
 
164261
164435
  // src/test/start.ts
164262
- import { dirname as dirname21, join as join46 } from "path";
164436
+ import { dirname as dirname21, join as join48 } from "path";
164263
164437
  import { fileURLToPath as fileURLToPath15 } from "url";
164264
164438
  import { configDefaults } from "vitest/config";
164265
164439
  import { startVitest } from "vitest/node";
@@ -164335,7 +164509,7 @@ var startTest = async (props) => {
164335
164509
  reporters: [new NullReporter],
164336
164510
  env: props.env,
164337
164511
  setupFiles: [
164338
- join46(__dirname4, "test-global-setup.js")
164512
+ join48(__dirname4, "test-global-setup.js")
164339
164513
  ]
164340
164514
  }, {
164341
164515
  logLevel: "silent",
@@ -164490,8 +164664,8 @@ var logTestErrors = (event) => {
164490
164664
  }
164491
164665
  };
164492
164666
  var runTest = async (stack, dir, filters, workspace, opts) => {
164493
- await mkdir7(directories.test, { recursive: true });
164494
- const file2 = join47(directories.test, `${stack}.json`);
164667
+ await mkdir8(directories.test, { recursive: true });
164668
+ const file2 = join49(directories.test, `${stack}.json`);
164495
164669
  const fingerprint = await generateFolderHash(workspace, dir) + (opts.fingerprint ?? "");
164496
164670
  if (!process.env.NO_CACHE) {
164497
164671
  const exists4 = await fileExist(file2);
@@ -164522,7 +164696,7 @@ var runTest = async (stack, dir, filters, workspace, opts) => {
164522
164696
  env: opts.env
164523
164697
  });
164524
164698
  if (result2.errors.length > 0) {
164525
- throw result2.errors.map((error3) => new ExpectedError(error3.message));
164699
+ throw result2.errors.map((error3) => new ExpectedError(error3.type && error3.type !== "Error" ? `${error3.type}: ${error3.message}` : error3.message));
164526
164700
  }
164527
164701
  ctx.updateSuccessMessage(formatResult({
164528
164702
  stack,
@@ -164536,7 +164710,7 @@ var runTest = async (stack, dir, filters, workspace, opts) => {
164536
164710
  logTestLogs(result);
164537
164711
  }
164538
164712
  logTestErrors(result);
164539
- await writeFile10(file2, stringify4({
164713
+ await writeFile11(file2, stringify4({
164540
164714
  ...result,
164541
164715
  fingerprint
164542
164716
  }));
@@ -164808,14 +164982,18 @@ var deploy = (program3) => {
164808
164982
  }
164809
164983
  }
164810
164984
  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
- }
164985
+ const passed = await withTestEnvironment(appConfig, stackConfigs, ({ manifest, manifestFile }) => {
164986
+ return runTests(tests, [], [], {
164987
+ showLogs: false,
164988
+ manifest,
164989
+ env: {
164990
+ APP: appConfig.name,
164991
+ APP_ID: appId,
164992
+ AWS_REGION: appConfig.region,
164993
+ AWS_ACCOUNT_ID: accountId,
164994
+ AWSLESS_TEST_MANIFEST: manifestFile
164995
+ }
164996
+ });
164819
164997
  });
164820
164998
  if (!passed) {
164821
164999
  throw new ExpectedError("Tests failed.");
@@ -165371,12 +165549,12 @@ var auth = (program3) => {
165371
165549
 
165372
165550
  // src/cli/command/bind.ts
165373
165551
  import { readFile as readFile20 } from "fs/promises";
165374
- import { join as join48 } from "path";
165552
+ import { join as join50 } from "path";
165375
165553
  var bind = (program3) => {
165376
165554
  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
165555
  await layout("bind", async ({ appConfig, stackConfigs }) => {
165378
165556
  if (opts.local) {
165379
- const file2 = join48(directories.output, "local", "env.json");
165557
+ const file2 = join50(directories.output, "local", "env.json");
165380
165558
  let env5;
165381
165559
  try {
165382
165560
  env5 = JSON.parse(await readFile20(file2, "utf8"));
@@ -166172,18 +166350,18 @@ var watchConfig = async (options, resolve5, reject) => {
166172
166350
 
166173
166351
  // src/dev/index.ts
166174
166352
  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";
166353
+ import { mkdir as mkdir11, rm as rm12, writeFile as writeFile15 } from "fs/promises";
166354
+ import { join as join57 } from "path";
166177
166355
 
166178
166356
  // src/dev/context.ts
166179
166357
  import { DynamoDBServer } from "@awsless/dynamodb-server";
166180
- import { join as join50 } from "path";
166358
+ import { join as join52 } from "path";
166181
166359
 
166182
166360
  // src/dev/servers/s3.ts
166183
166361
  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";
166362
+ import { mkdir as mkdir9, readdir as readdir8, readFile as readFile21, rm as rm10, stat as stat7, writeFile as writeFile12 } from "fs/promises";
166185
166363
  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";
166364
+ import { dirname as dirname22, isAbsolute as isAbsolute6, join as join51, relative as relative10, sep as sep4 } from "path";
166187
166365
  var escapeXml = (value) => {
166188
166366
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
166189
166367
  };
@@ -166248,11 +166426,11 @@ var createS3Server = (props) => {
166248
166426
  res.end(xmlError("InvalidRequest", "Missing bucket name"));
166249
166427
  return;
166250
166428
  }
166251
- const bucketDir = join49(props.root, bucket);
166252
- const file2 = join49(bucketDir, ...keyParts);
166429
+ const bucketDir = join51(props.root, bucket);
166430
+ const file2 = join51(bucketDir, ...keyParts);
166253
166431
  const escapes = (base, path6) => {
166254
166432
  const rel = relative10(base, path6);
166255
- return rel.startsWith("..") || isAbsolute5(rel);
166433
+ return rel.startsWith("..") || isAbsolute6(rel);
166256
166434
  };
166257
166435
  if (escapes(props.root, bucketDir) || escapes(bucketDir, file2)) {
166258
166436
  res.writeHead(400, { "content-type": "application/xml" });
@@ -166270,7 +166448,7 @@ var createS3Server = (props) => {
166270
166448
  return;
166271
166449
  }
166272
166450
  for (const entry of entries2) {
166273
- const path6 = join49(dir, entry.name);
166451
+ const path6 = join51(dir, entry.name);
166274
166452
  if (entry.isDirectory()) {
166275
166453
  await walk2(path6);
166276
166454
  } else {
@@ -166296,8 +166474,8 @@ var createS3Server = (props) => {
166296
166474
  if (typeof encoding === "string" && encoding.includes("aws-chunked") || typeof sha === "string" && sha.startsWith("STREAMING")) {
166297
166475
  body = decodeAwsChunked(body);
166298
166476
  }
166299
- await mkdir8(dirname22(file2), { recursive: true });
166300
- await writeFile11(file2, body);
166477
+ await mkdir9(dirname22(file2), { recursive: true });
166478
+ await writeFile12(file2, body);
166301
166479
  const eTag = createHash22("md5").update(body).digest("hex");
166302
166480
  res.writeHead(200, { etag: `"${eTag}"` });
166303
166481
  res.end();
@@ -166738,7 +166916,7 @@ var createDevContext = (props) => {
166738
166916
  const value = await props.pool.keep("store", null, async () => {
166739
166917
  const rules = [];
166740
166918
  const server = createS3Server({
166741
- root: join50(directories.output, "local", "store"),
166919
+ root: join52(directories.output, "local", "store"),
166742
166920
  region: props.appConfig.region,
166743
166921
  rules
166744
166922
  });
@@ -166838,9 +167016,9 @@ var createDevContext = (props) => {
166838
167016
 
166839
167017
  // src/dev/seed.ts
166840
167018
  import { spawn as spawn6 } from "child_process";
166841
- import { isAbsolute as isAbsolute6, join as join51 } from "path";
167019
+ import { isAbsolute as isAbsolute7, join as join53 } from "path";
166842
167020
  var createSeedRunner = (props) => {
166843
- const file2 = props.seed && (isAbsolute6(props.seed) ? props.seed : join51(directories.root, props.seed));
167021
+ const file2 = props.seed && (isAbsolute7(props.seed) ? props.seed : join53(directories.root, props.seed));
166844
167022
  let running;
166845
167023
  const run = () => {
166846
167024
  running ??= (async () => {
@@ -166889,15 +167067,15 @@ var import_ioredis5 = __toESM(require_built3(), 1);
166889
167067
  import { DynamoDBClient as DynamoDBClient5 } from "@aws-sdk/client-dynamodb";
166890
167068
  import { DynamoDBDocumentClient, ScanCommand as ScanCommand2 } from "@aws-sdk/lib-dynamodb";
166891
167069
  import { randomUUID as randomUUID8 } from "crypto";
166892
- import { readdir as readdir9, readFile as readFile22, stat as stat8, writeFile as writeFile13 } from "fs/promises";
167070
+ import { readdir as readdir9, readFile as readFile22, stat as stat8, writeFile as writeFile14 } from "fs/promises";
166893
167071
  import { createServer as createServer9 } from "http";
166894
- import { join as join53, relative as relative11, sep as sep5 } from "path";
167072
+ import { join as join55, relative as relative11, sep as sep5 } from "path";
166895
167073
 
166896
167074
  // src/dev/worker.ts
166897
167075
  import { spawn as spawn7 } from "child_process";
166898
- import { writeFile as writeFile12 } from "fs/promises";
167076
+ import { writeFile as writeFile13 } from "fs/promises";
166899
167077
  import { availableParallelism } from "os";
166900
- import { join as join52 } from "path";
167078
+ import { join as join54 } from "path";
166901
167079
  class WorkerError extends Error {
166902
167080
  name;
166903
167081
  constructor(name, message4, stack) {
@@ -167014,7 +167192,7 @@ var createBundleWorker = (props) => {
167014
167192
  throw new Error("The bundle worker never became ready.");
167015
167193
  };
167016
167194
  const startWorker = async () => {
167017
- const entry = join52(props.buildDir, "worker.mjs");
167195
+ const entry = join54(props.buildDir, "worker.mjs");
167018
167196
  const port = await findFreePort();
167019
167197
  const child = spawn7("node", ["--enable-source-maps", entry], {
167020
167198
  cwd: props.buildDir,
@@ -167073,7 +167251,7 @@ var createBundleWorker = (props) => {
167073
167251
  return worker;
167074
167252
  };
167075
167253
  const doStart = async () => {
167076
- await writeFile12(join52(props.buildDir, "worker.mjs"), WORKER_ENTRY);
167254
+ await writeFile13(join54(props.buildDir, "worker.mjs"), WORKER_ENTRY);
167077
167255
  const results = await Promise.allSettled(Array.from({ length: concurrency }, () => startWorker()));
167078
167256
  const started = results.filter((result) => result.status === "fulfilled").map((result) => result.value);
167079
167257
  const failed = results.find((result) => result.status === "rejected");
@@ -168737,7 +168915,7 @@ var createDashboardServer = (props) => {
168737
168915
  return;
168738
168916
  }
168739
168917
  for (const entry of entries2) {
168740
- const path6 = join53(dir, entry.name);
168918
+ const path6 = join55(dir, entry.name);
168741
168919
  if (entry.isDirectory()) {
168742
168920
  await walk2(path6);
168743
168921
  } else {
@@ -168802,7 +168980,7 @@ var createDashboardServer = (props) => {
168802
168980
  if (url.pathname === "/api/config") {
168803
168981
  if (req.method === "PUT") {
168804
168982
  const values2 = JSON.parse((await readBody(req)).toString() || "{}");
168805
- await writeFile13(props.configFile, JSON.stringify(values2, null, "\t") + `
168983
+ await writeFile14(props.configFile, JSON.stringify(values2, null, "\t") + `
168806
168984
  `);
168807
168985
  return { status: 200, body: JSON.stringify({ ok: true }) };
168808
168986
  }
@@ -169048,17 +169226,17 @@ var createLambdaServer = (props) => {
169048
169226
  };
169049
169227
 
169050
169228
  // 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";
169229
+ import { readdir as readdir10, readFile as readFile23, mkdir as mkdir10, rm as rm11, stat as stat9, symlink } from "fs/promises";
169052
169230
  import { createRequire } from "module";
169053
- import { dirname as dirname23, join as join54 } from "path";
169231
+ import { dirname as dirname23, join as join56 } from "path";
169054
169232
  var linkSdkPackages = async (buildDir, onWarn) => {
169055
- const filesDir = join54(buildDir, "files");
169233
+ const filesDir = join56(buildDir, "files");
169056
169234
  const packages = new Set;
169057
169235
  for (const file2 of await readdir10(filesDir)) {
169058
169236
  if (!file2.endsWith(".mjs")) {
169059
169237
  continue;
169060
169238
  }
169061
- const code = await readFile23(join54(filesDir, file2), "utf8");
169239
+ const code = await readFile23(join56(filesDir, file2), "utf8");
169062
169240
  for (const match3 of code.matchAll(/(?:from\s*|import\()\s*["'](@aws-sdk\/[a-z0-9-]+|sharp)["']/g)) {
169063
169241
  packages.add(match3[1]);
169064
169242
  }
@@ -169066,25 +169244,25 @@ var linkSdkPackages = async (buildDir, onWarn) => {
169066
169244
  const ownRequire = createRequire(import.meta.url);
169067
169245
  const isProjectDep = async (name) => {
169068
169246
  try {
169069
- await stat9(join54(directories.root, "node_modules", name, "package.json"));
169247
+ await stat9(join56(directories.root, "node_modules", name, "package.json"));
169070
169248
  return true;
169071
169249
  } catch (_4) {
169072
169250
  return false;
169073
169251
  }
169074
169252
  };
169075
169253
  const resolveFromStore = async (name) => {
169076
- const store = join54(directories.root, "node_modules", ".pnpm");
169254
+ const store = join56(directories.root, "node_modules", ".pnpm");
169077
169255
  const prefix = name.replaceAll("/", "+") + "@";
169078
169256
  try {
169079
169257
  const entries2 = (await readdir10(store)).filter((entry) => entry.startsWith(prefix));
169080
169258
  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;
169259
+ return best ? join56(store, best, "node_modules", name) : undefined;
169082
169260
  } catch (_4) {
169083
169261
  return;
169084
169262
  }
169085
169263
  };
169086
169264
  for (const name of packages) {
169087
- const target2 = join54(buildDir, "node_modules", name);
169265
+ const target2 = join56(buildDir, "node_modules", name);
169088
169266
  try {
169089
169267
  if (await isProjectDep(name)) {
169090
169268
  await rm11(target2, { recursive: true, force: true });
@@ -169100,10 +169278,10 @@ var linkSdkPackages = async (buildDir, onWarn) => {
169100
169278
  continue;
169101
169279
  }
169102
169280
  }
169103
- await mkdir9(dirname23(target2), { recursive: true });
169281
+ await mkdir10(dirname23(target2), { recursive: true });
169104
169282
  await rm11(target2, { recursive: true, force: true });
169105
169283
  await symlink(source, target2, "dir");
169106
- await stat9(join54(target2, "package.json"));
169284
+ await stat9(join56(target2, "package.json"));
169107
169285
  debug(`Sdk link ${name}: ${source}`);
169108
169286
  } catch (error3) {
169109
169287
  onWarn?.(`Linking the "${name}" sdk package failed: ${error3 instanceof Error ? error3.message : String(error3)}`);
@@ -169127,7 +169305,7 @@ var startDev = async (props) => {
169127
169305
  dev: true
169128
169306
  });
169129
169307
  ready2();
169130
- await mkdir10(join55(directories.output, "local"), { recursive: true });
169308
+ await mkdir11(join57(directories.output, "local"), { recursive: true });
169131
169309
  const routerPorts = {};
169132
169310
  Object.keys(appConfig.router ?? {}).forEach((id, index) => {
169133
169311
  routerPorts[id] = props.port + 1 + index;
@@ -169182,7 +169360,7 @@ var startDev = async (props) => {
169182
169360
  for (const [id, port] of Object.entries(routerPorts)) {
169183
169361
  env5[`ROUTER_${constantCase(id)}_ENDPOINT`] = `localhost:${port}`;
169184
169362
  }
169185
- await writeFile14(join55(directories.output, "local", "env.json"), JSON.stringify(env5, null, "\t") + `
169363
+ await writeFile15(join57(directories.output, "local", "env.json"), JSON.stringify(env5, null, "\t") + `
169186
169364
  `);
169187
169365
  return { env: env5, lambda: lambda2 };
169188
169366
  });
@@ -169197,7 +169375,7 @@ var startDev = async (props) => {
169197
169375
  }
169198
169376
  debug(`Build ${builder.type}:${builder.name}`, meta?.cached ? "cached" : String(meta?.buildTime));
169199
169377
  }
169200
- await writeFile14(getBuildPath("bundle", bundleName, "files/awsless-env.mjs"), `export default {}
169378
+ await writeFile15(getBuildPath("bundle", bundleName, "files/awsless-env.mjs"), `export default {}
169201
169379
  `);
169202
169380
  await linkSdkPackages(buildDir, log);
169203
169381
  return changed;
@@ -169324,8 +169502,8 @@ var startDev = async (props) => {
169324
169502
  resources: dev.resources,
169325
169503
  routes: dev.routes,
169326
169504
  env: env4,
169327
- storeRoot: join55(directories.output, "local", "store"),
169328
- configFile: join55(directories.output, "local", "config.json"),
169505
+ storeRoot: join57(directories.output, "local", "store"),
169506
+ configFile: join57(directories.output, "local", "config.json"),
169329
169507
  getEmails: () => props.pool.peek("shim:ses-email")?.server.list() ?? [],
169330
169508
  configPulled: Object.keys(props.pool.peek("config:pull") ?? {}),
169331
169509
  auth: createAuthAdmin({
@@ -169367,7 +169545,7 @@ var startDev = async (props) => {
169367
169545
  routerPorts,
169368
169546
  async stop() {
169369
169547
  stopping = true;
169370
- await rm12(join55(directories.output, "local", "env.json"), { force: true });
169548
+ await rm12(join57(directories.output, "local", "env.json"), { force: true });
169371
169549
  clearTimeout(rebuildTimer);
169372
169550
  await watcher.close();
169373
169551
  await restartWatcher?.close();
@@ -169432,8 +169610,8 @@ var createServerPool = () => {
169432
169610
  };
169433
169611
 
169434
169612
  // 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";
169613
+ import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
169614
+ import { dirname as dirname24, join as join58, relative as relative12 } from "path";
169437
169615
  var generateTypes = async (props) => {
169438
169616
  const files = [];
169439
169617
  await Promise.all(features.map((feature) => {
@@ -169441,13 +169619,13 @@ var generateTypes = async (props) => {
169441
169619
  ...props,
169442
169620
  async write(file2, data, include = false) {
169443
169621
  const code = data?.toString("utf8");
169444
- const path6 = join56(directories.types, file2);
169622
+ const path6 = join58(directories.types, file2);
169445
169623
  if (code) {
169446
169624
  if (include) {
169447
169625
  files.push(relative12(directories.root, path6));
169448
169626
  }
169449
- await mkdir11(dirname24(path6), { recursive: true });
169450
- await writeFile15(path6, code);
169627
+ await mkdir12(dirname24(path6), { recursive: true });
169628
+ await writeFile16(path6, code);
169451
169629
  }
169452
169630
  }
169453
169631
  });
@@ -169455,7 +169633,7 @@ var generateTypes = async (props) => {
169455
169633
  if (files.length) {
169456
169634
  const code = files.map((file2) => `/// <reference path='${file2}' />`).join(`
169457
169635
  `);
169458
- await writeFile15(join56(directories.root, `awsless.d.ts`), code);
169636
+ await writeFile16(join58(directories.root, `awsless.d.ts`), code);
169459
169637
  }
169460
169638
  };
169461
169639
 
@@ -185107,101 +185285,6 @@ var state = (program3) => {
185107
185285
  };
185108
185286
 
185109
185287
  // 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
185288
  var test2 = (program3) => {
185206
185289
  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
185290
  await layout(`test ${stacks ?? ""}`, async (props) => {
@@ -185210,36 +185293,8 @@ var test2 = (program3) => {
185210
185293
  if (tests.length === 0) {
185211
185294
  return "No tests found.";
185212
185295
  }
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, {
185296
+ const passed = await withTestEnvironment(props.appConfig, props.stackConfigs, ({ manifest, manifestFile }) => {
185297
+ return runTests(tests, stacks, options?.filters, {
185243
185298
  showLogs: true,
185244
185299
  manifest,
185245
185300
  env: {
@@ -185250,10 +185305,7 @@ var test2 = (program3) => {
185250
185305
  AWSLESS_TEST_MANIFEST: manifestFile
185251
185306
  }
185252
185307
  });
185253
- } finally {
185254
- await redis?.kill();
185255
- await killSearch?.();
185256
- }
185308
+ });
185257
185309
  if (!passed) {
185258
185310
  throw new ExpectedError("Tests failed.");
185259
185311
  }