@awsless/cli 0.0.46-local.51 → 0.0.46-local.53

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 +651 -274
  2. package/package.json +13 -13
package/dist/bin.js CHANGED
@@ -103012,7 +103012,7 @@ import { fromEnv as fromEnv3 } from "@aws-sdk/credential-providers";
103012
103012
  import { Client as Client4 } from "@opensearch-project/opensearch";
103013
103013
  import { AwsSigv4Signer as AwsSigv4Signer2 } from "@opensearch-project/opensearch/aws";
103014
103014
  import { Agent } from "https";
103015
- import { createHash as createHash16 } from "crypto";
103015
+ import { createHash as createHash15 } from "crypto";
103016
103016
  import { mkdir as mkdir6, rename as rename4, rm as rm8, stat as stat5 } from "fs/promises";
103017
103017
  import { join as join27, resolve as resolve3 } from "path";
103018
103018
  import { spawn as spawn3 } from "child_process";
@@ -103084,7 +103084,7 @@ var import_decompress, import_sleep_await, mock, searchClient = (options = {}, s
103084
103084
  throw new Error(`Downloading the OpenSearch checksum failed with status ${checksumResponse.status}: ${url}.sha512`);
103085
103085
  }
103086
103086
  const checksum = (await checksumResponse.text()).split(/\s+/)[0];
103087
- const digest = createHash16("sha512").update(buffer).digest("hex");
103087
+ const digest = createHash15("sha512").update(buffer).digest("hex");
103088
103088
  if (digest !== checksum) {
103089
103089
  throw new Error(`The OpenSearch archive doesn't match its published sha512 checksum: ${url}`);
103090
103090
  }
@@ -103753,7 +103753,7 @@ var require_find_exec = __commonJS((exports, module) => {
103753
103753
  var require_play_sound = __commonJS((exports, module) => {
103754
103754
  var fs5 = __require("fs");
103755
103755
  var findExec = require_find_exec();
103756
- var spawn5 = __require("child_process").spawn;
103756
+ var spawn6 = __require("child_process").spawn;
103757
103757
  var players = [
103758
103758
  "mplayer",
103759
103759
  "afplay",
@@ -103783,7 +103783,7 @@ var require_play_sound = __commonJS((exports, module) => {
103783
103783
  return next(new Error("Couldn't find a suitable audio player"));
103784
103784
  }
103785
103785
  var args = Array.isArray(options[this.player]) ? options[this.player].concat(what) : [what];
103786
- var process5 = spawn5(this.player, args, options);
103786
+ var process5 = spawn6(this.player, args, options);
103787
103787
  if (!process5) {
103788
103788
  next(new Error("Unable to spawn process with " + this.player));
103789
103789
  return null;
@@ -107776,9 +107776,9 @@ var require_nodefs_handler = __commonJS((exports, module) => {
107776
107776
  if (this.fsw.closed) {
107777
107777
  return;
107778
107778
  }
107779
- const dirname21 = sysPath.dirname(file2);
107779
+ const dirname22 = sysPath.dirname(file2);
107780
107780
  const basename4 = sysPath.basename(file2);
107781
- const parent = this.fsw._getWatchedDir(dirname21);
107781
+ const parent = this.fsw._getWatchedDir(dirname22);
107782
107782
  let prevStats = stats2;
107783
107783
  if (parent.has(basename4))
107784
107784
  return;
@@ -107803,7 +107803,7 @@ var require_nodefs_handler = __commonJS((exports, module) => {
107803
107803
  prevStats = newStats2;
107804
107804
  }
107805
107805
  } catch (error3) {
107806
- this.fsw._remove(dirname21, basename4);
107806
+ this.fsw._remove(dirname22, basename4);
107807
107807
  }
107808
107808
  } else if (parent.has(basename4)) {
107809
107809
  const at2 = newStats.atimeMs;
@@ -154977,11 +154977,13 @@ import { createServer as createServer2 } from "http";
154977
154977
 
154978
154978
  // src/dev/util.ts
154979
154979
  import { createServer } from "net";
154980
- var stopChild = async (child) => {
154980
+ var stopChild = async (child, gracePeriod = 5000) => {
154981
154981
  if (child && child.exitCode === null && child.signalCode === null) {
154982
154982
  const exited = new Promise((resolve3) => child.once("exit", () => resolve3()));
154983
154983
  child.kill();
154984
+ const timer = setTimeout(() => child.kill("SIGKILL"), gracePeriod);
154984
154985
  await exited;
154986
+ clearTimeout(timer);
154985
154987
  }
154986
154988
  };
154987
154989
  var trackConnections = (server) => {
@@ -157746,182 +157748,6 @@ var pubsubFeature = defineFeature({
157746
157748
  var import_deepmerge3 = __toESM(require_cjs2(), 1);
157747
157749
  import { relative as relative4 } from "path";
157748
157750
  import { minutes as minutes7, seconds as seconds5, toSeconds as toSeconds6 } from "@awsless/duration";
157749
-
157750
- // src/dev/servers/sqs.ts
157751
- import { createHash as createHash15, randomUUID as randomUUID5 } from "crypto";
157752
- import { createServer as createServer5 } from "http";
157753
- var md5 = (value) => createHash15("md5").update(value).digest("hex");
157754
- var md5OfAttributes = (attributes) => {
157755
- const parts = [];
157756
- const push = (value) => {
157757
- const data = Buffer.from(value, "utf8");
157758
- const size2 = Buffer.alloc(4);
157759
- size2.writeUInt32BE(data.length);
157760
- parts.push(size2, data);
157761
- };
157762
- for (const name of Object.keys(attributes).sort()) {
157763
- const attribute = attributes[name];
157764
- push(name);
157765
- push(attribute.DataType ?? "String");
157766
- if (typeof attribute.BinaryValue === "string") {
157767
- const data = Buffer.from(attribute.BinaryValue, "base64");
157768
- const size2 = Buffer.alloc(4);
157769
- size2.writeUInt32BE(data.length);
157770
- parts.push(Buffer.from([2]), size2, data);
157771
- } else {
157772
- const data = Buffer.from(attribute.StringValue ?? "", "utf8");
157773
- const size2 = Buffer.alloc(4);
157774
- size2.writeUInt32BE(data.length);
157775
- parts.push(Buffer.from([1]), size2, data);
157776
- }
157777
- }
157778
- return md5(Buffer.concat(parts));
157779
- };
157780
- var formatEventAttributes = (attributes) => {
157781
- const list2 = {};
157782
- for (const [name, attribute] of Object.entries(attributes)) {
157783
- list2[name] = {
157784
- dataType: attribute.DataType ?? "String",
157785
- stringValue: attribute.StringValue,
157786
- binaryValue: attribute.BinaryValue
157787
- };
157788
- }
157789
- return list2;
157790
- };
157791
- var createSqsServer = (props) => {
157792
- let server;
157793
- let closeServer;
157794
- let dispatch;
157795
- let reportFailure;
157796
- const queueFromUrl = (url) => {
157797
- const name = url?.split("/").filter(Boolean).at(-1);
157798
- return name && props.queues.has(name) ? name : undefined;
157799
- };
157800
- const deliver = (queue, input, messageId) => {
157801
- const now = Date.now();
157802
- const event = {
157803
- Records: [
157804
- {
157805
- messageId,
157806
- receiptHandle: randomUUID5(),
157807
- body: input.MessageBody,
157808
- attributes: {
157809
- ApproximateReceiveCount: "1",
157810
- SentTimestamp: String(now),
157811
- SenderId: "local",
157812
- ApproximateFirstReceiveTimestamp: String(now)
157813
- },
157814
- messageAttributes: formatEventAttributes(input.MessageAttributes ?? {}),
157815
- md5OfBody: md5(input.MessageBody ?? ""),
157816
- eventSource: "aws:sqs",
157817
- eventSourceARN: `arn:aws:sqs:${props.region}:${props.accountId}:${queue}`,
157818
- awsRegion: props.region
157819
- }
157820
- ]
157821
- };
157822
- const send = () => {
157823
- dispatch?.(event).catch((error3) => {
157824
- let body = input.MessageBody;
157825
- try {
157826
- body = JSON.parse(input.MessageBody ?? "");
157827
- } catch (_3) {}
157828
- reportFailure?.({
157829
- kind: "queue",
157830
- routeKey: props.queues.get(queue),
157831
- event: body,
157832
- error: error3,
157833
- queue: { name: queue }
157834
- });
157835
- });
157836
- };
157837
- if (input.DelaySeconds) {
157838
- setTimeout(send, input.DelaySeconds * 1000);
157839
- } else {
157840
- setImmediate(send);
157841
- }
157842
- };
157843
- const sendResult = (input, messageId) => {
157844
- return {
157845
- MessageId: messageId,
157846
- MD5OfMessageBody: md5(input.MessageBody ?? ""),
157847
- ...input.MessageAttributes && Object.keys(input.MessageAttributes).length > 0 ? { MD5OfMessageAttributes: md5OfAttributes(input.MessageAttributes) } : {}
157848
- };
157849
- };
157850
- const actions = {
157851
- GetQueueUrl(input) {
157852
- return {
157853
- QueueUrl: `http://sqs.local/${props.accountId}/${input.QueueName}`
157854
- };
157855
- },
157856
- SendMessage(input) {
157857
- const queue = queueFromUrl(input.QueueUrl);
157858
- if (!queue) {
157859
- throw new Error(`Unknown local queue: ${input.QueueUrl}`);
157860
- }
157861
- const messageId = randomUUID5();
157862
- deliver(queue, input, messageId);
157863
- return sendResult(input, messageId);
157864
- },
157865
- SendMessageBatch(input) {
157866
- const queue = queueFromUrl(input.QueueUrl);
157867
- if (!queue) {
157868
- throw new Error(`Unknown local queue: ${input.QueueUrl}`);
157869
- }
157870
- return {
157871
- Successful: (input.Entries ?? []).map((entry) => {
157872
- const messageId = randomUUID5();
157873
- deliver(queue, entry, messageId);
157874
- return {
157875
- Id: entry.Id,
157876
- ...sendResult(entry, messageId)
157877
- };
157878
- }),
157879
- Failed: []
157880
- };
157881
- }
157882
- };
157883
- return {
157884
- connect(dispatchFn, reportFailureFn) {
157885
- dispatch = dispatchFn;
157886
- reportFailure = reportFailureFn;
157887
- },
157888
- async listen(port = 0) {
157889
- server = createServer5((req, res) => {
157890
- const chunks = [];
157891
- req.on("data", (chunk3) => chunks.push(chunk3));
157892
- req.on("end", () => {
157893
- const target2 = String(req.headers["x-amz-target"] ?? "");
157894
- const action = actions[target2.split(".").at(-1) ?? ""];
157895
- try {
157896
- if (!action) {
157897
- throw new Error(`The local dev sqs emulator does not support: ${target2}`);
157898
- }
157899
- const result = action(JSON.parse(Buffer.concat(chunks).toString() || "{}"));
157900
- res.writeHead(200, { "content-type": "application/x-amz-json-1.0" });
157901
- res.end(JSON.stringify(result));
157902
- } catch (error3) {
157903
- res.writeHead(400, { "content-type": "application/x-amz-json-1.0" });
157904
- res.end(JSON.stringify({
157905
- __type: "InvalidAction",
157906
- message: error3 instanceof Error ? error3.message : String(error3)
157907
- }));
157908
- }
157909
- });
157910
- });
157911
- await new Promise((resolve3, reject) => {
157912
- server.once("error", reject);
157913
- closeServer = trackConnections(server);
157914
- server.listen(port, "127.0.0.1", () => resolve3());
157915
- });
157916
- return server.address().port;
157917
- },
157918
- stop() {
157919
- return closeServer?.() ?? Promise.resolve();
157920
- }
157921
- };
157922
- };
157923
-
157924
- // src/feature/queue/index.ts
157925
157751
  var typeGenCode5 = `
157926
157752
  import {
157927
157753
  SendMessageOptions,
@@ -157958,7 +157784,7 @@ var queueFeature = defineFeature({
157958
157784
  if (queues.length === 0) {
157959
157785
  return;
157960
157786
  }
157961
- const queueRoutes = new Map;
157787
+ const { port, queues: registry } = await ctx.useSqs();
157962
157788
  const named = queues.map(({ stackName, id }) => {
157963
157789
  const name = `${formatLocalResourceName({
157964
157790
  appName: ctx.appConfig.name,
@@ -157966,19 +157792,9 @@ var queueFeature = defineFeature({
157966
157792
  resourceType: "queue",
157967
157793
  resourceName: id
157968
157794
  })}.fifo`;
157969
- queueRoutes.set(name, formatRouteKey(stackName, "queue", id));
157795
+ registry.set(name, formatRouteKey(stackName, "queue", id));
157970
157796
  return { stackName, id, name };
157971
157797
  });
157972
- const { server, port } = await ctx.keep("shim:sqs", queueRoutes, async () => {
157973
- const server2 = createSqsServer({
157974
- region: ctx.appConfig.region,
157975
- accountId: "000000000000",
157976
- queues: queueRoutes
157977
- });
157978
- const port2 = await server2.listen();
157979
- return { value: { server: server2, port: port2 }, stop: () => server2.stop() };
157980
- });
157981
- ctx.addEnv("AWS_ENDPOINT_URL_SQS", `http://127.0.0.1:${port}`);
157982
157798
  for (const { stackName, id, name } of named) {
157983
157799
  ctx.addEnv(`QUEUE_${constantCase(stackName)}_${constantCase(id)}_URL`, `http://127.0.0.1:${port}/000000000000/${name}`);
157984
157800
  ctx.registerResource({
@@ -157989,12 +157805,6 @@ var queueFeature = defineFeature({
157989
157805
  detail: name
157990
157806
  });
157991
157807
  }
157992
- ctx.registerServer({
157993
- name: "sqs",
157994
- start({ dispatch, reportFailure }) {
157995
- server.connect(dispatch, reportFailure);
157996
- }
157997
- });
157998
157808
  },
157999
157809
  async onTypeGen(ctx) {
158000
157810
  const gen = new TypeFile("awsless");
@@ -158081,7 +157891,7 @@ var queueFeature = defineFeature({
158081
157891
  });
158082
157892
 
158083
157893
  // src/dev/servers/rest.ts
158084
- import { createServer as createServer6 } from "http";
157894
+ import { createServer as createServer5 } from "http";
158085
157895
 
158086
157896
  // src/dev/router.ts
158087
157897
  var compileRoutes = (routes) => {
@@ -158448,7 +158258,7 @@ var createRestServer = (props) => {
158448
158258
  dispatch = dispatchFn;
158449
158259
  },
158450
158260
  async listen(port = 0) {
158451
- server = createServer6((req, res) => {
158261
+ server = createServer5((req, res) => {
158452
158262
  handle(req, res).catch((error3) => {
158453
158263
  res.writeHead(500, { "content-type": "text/plain" });
158454
158264
  res.end(error3 instanceof Error ? `${error3.name}: ${error3.message}` : String(error3));
@@ -158982,7 +158792,7 @@ var searchFeature = defineFeature({
158982
158792
  });
158983
158793
 
158984
158794
  // src/feature/site/index.ts
158985
- import { createHash as createHash17 } from "crypto";
158795
+ import { createHash as createHash16 } from "crypto";
158986
158796
  import { dirname as dirname17, join as join35 } from "path";
158987
158797
 
158988
158798
  // src/util/cache.ts
@@ -159339,7 +159149,7 @@ ${(errors3.trim() || output.trim()).slice(-2000)}`);
159339
159149
  }).sort();
159340
159150
  const hashes = files.map((file2) => $hash(join35(staticDir, file2)));
159341
159151
  const version2 = $combine(...hashes).pipe((hashes2) => {
159342
- const hash2 = createHash17("sha1");
159152
+ const hash2 = createHash16("sha1");
159343
159153
  for (const [index, file2] of files.entries()) {
159344
159154
  hash2.update(file2);
159345
159155
  hash2.update(hashes2[index]);
@@ -159944,7 +159754,7 @@ var tableFeature = defineFeature({
159944
159754
  import { relative as relative6 } from "path";
159945
159755
 
159946
159756
  // src/dev/servers/scheduler.ts
159947
- import { createServer as createServer7 } from "http";
159757
+ import { createServer as createServer6 } from "http";
159948
159758
  var createSchedulerServer = () => {
159949
159759
  let server;
159950
159760
  let closeServer;
@@ -159956,7 +159766,7 @@ var createSchedulerServer = () => {
159956
159766
  reportFailure = reportFailureFn;
159957
159767
  },
159958
159768
  async listen(port = 0) {
159959
- server = createServer7((req, res) => {
159769
+ server = createServer6((req, res) => {
159960
159770
  const chunks = [];
159961
159771
  req.on("data", (chunk3) => chunks.push(chunk3));
159962
159772
  req.on("end", () => {
@@ -160593,7 +160403,7 @@ var layerFeature = defineFeature({
160593
160403
  // src/feature/image/index.ts
160594
160404
  import { toDays as toDays9 } from "@awsless/duration";
160595
160405
  import { formatRouteEnvName as formatRouteEnvName3 } from "awsless";
160596
- import { createHash as createHash18 } from "crypto";
160406
+ import { createHash as createHash17 } from "crypto";
160597
160407
  import { readFile as readFile17 } from "fs/promises";
160598
160408
  import { dirname as dirname18, join as join40 } from "path";
160599
160409
  import { fileURLToPath as fileURLToPath13 } from "url";
@@ -160677,7 +160487,7 @@ var imageFeature = defineFeature({
160677
160487
  });
160678
160488
  ctx.registerBuild("image", layerId, async (build2) => {
160679
160489
  const file2 = await readFile17(path6);
160680
- const fingerprint = createHash18("sha1").update(file2).digest("hex");
160490
+ const fingerprint = createHash17("sha1").update(file2).digest("hex");
160681
160491
  return build2(fingerprint, async (write2) => {
160682
160492
  await Promise.all([
160683
160493
  write2("HASH", fingerprint),
@@ -160958,10 +160768,10 @@ import { toDays as toDays11, toSeconds as toSeconds10 } from "@awsless/duration"
160958
160768
  import { stringify as stringify2 } from "@awsless/json";
160959
160769
  import { generateFileHash as generateFileHash3 } from "@awsless/ts-file-cache";
160960
160770
  var import_deepmerge4 = __toESM(require_cjs2(), 1);
160961
- import { createHash as createHash20 } from "crypto";
160771
+ import { createHash as createHash19 } from "crypto";
160962
160772
 
160963
160773
  // src/feature/job/build/executable.ts
160964
- import { createHash as createHash19 } from "crypto";
160774
+ import { createHash as createHash18 } from "crypto";
160965
160775
  import { readFile as readFile18, writeFile as writeFile9 } from "fs/promises";
160966
160776
  import { join as join43, resolve as resolve4 } from "path";
160967
160777
  var buildJobExecutable = async (input, outputPath, architecture) => {
@@ -161019,7 +160829,7 @@ ${result.logs?.map((log) => log.message).join(`
161019
160829
  }
161020
160830
  const file2 = await readFile18(filePath);
161021
160831
  return {
161022
- hash: createHash19("sha1").update(file2).update(target2).digest("hex"),
160832
+ hash: createHash18("sha1").update(file2).update(target2).digest("hex"),
161023
160833
  file: file2
161024
160834
  };
161025
160835
  };
@@ -161282,7 +161092,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
161282
161092
  variables.AWS_ACCOUNT_ID = ctx.accountId;
161283
161093
  variables.STACK = ctx.stackConfig.name;
161284
161094
  variables.CODE_HASH = code.sourceHash;
161285
- variables.JOB_CONFIG_HASH = createHash20("sha1").update(stringify2(props)).digest("hex");
161095
+ variables.JOB_CONFIG_HASH = createHash19("sha1").update(stringify2(props)).digest("hex");
161286
161096
  if (props.environment) {
161287
161097
  for (const [key, value] of Object.entries(props.environment)) {
161288
161098
  variables[key] = value;
@@ -161474,13 +161284,124 @@ var jobFeature = defineFeature({
161474
161284
  // src/feature/instance/index.ts
161475
161285
  import { days as days11, seconds as seconds6, toSeconds as toSeconds12 } from "@awsless/duration";
161476
161286
 
161287
+ // src/feature/instance/dev.ts
161288
+ import { spawn as spawn5 } from "child_process";
161289
+ var import_deepmerge6 = __toESM(require_cjs2(), 1);
161290
+ import { dirname as dirname20, join as join44 } from "path";
161291
+ var instanceOnDev = async (ctx) => {
161292
+ const instances = ctx.stackConfigs.flatMap((stackConfig) => {
161293
+ return Object.entries(stackConfig.instances ?? {}).map(([id, props]) => ({ stackConfig, id, props }));
161294
+ });
161295
+ if (instances.length === 0) {
161296
+ return;
161297
+ }
161298
+ const { port, queues } = await ctx.useSqs();
161299
+ for (const { stackConfig, id, props } of instances) {
161300
+ const name = formatLocalResourceName({
161301
+ appName: ctx.appConfig.name,
161302
+ stackName: stackConfig.name,
161303
+ resourceType: "instance",
161304
+ resourceName: id
161305
+ });
161306
+ queues.set(name, undefined);
161307
+ const queueUrl = `http://127.0.0.1:${port}/000000000000/${name}`;
161308
+ ctx.addEnv(`INSTANCE_${constantCase(stackConfig.name)}_${constantCase(id)}_URL`, queueUrl);
161309
+ const channel = `instance:${stackConfig.name}:${id}`;
161310
+ const healthPort = await findFreePort();
161311
+ const merged = import_deepmerge6.default(ctx.appConfig.instance ?? {}, props);
161312
+ const file2 = merged.code.file;
161313
+ const cwd2 = join44(directories.root, dirname20(stackConfig.file));
161314
+ let child;
161315
+ let stopping = false;
161316
+ let restarting = false;
161317
+ let boot;
161318
+ const restart = async (reason) => {
161319
+ if (!boot || restarting) {
161320
+ return;
161321
+ }
161322
+ restarting = true;
161323
+ ctx.emitEvent(channel, { date: Date.now(), line: reason });
161324
+ try {
161325
+ if (child) {
161326
+ stopping = true;
161327
+ await stopChild(child);
161328
+ stopping = false;
161329
+ }
161330
+ boot();
161331
+ } finally {
161332
+ restarting = false;
161333
+ }
161334
+ };
161335
+ ctx.registerServer({
161336
+ name: `instance ${id}`,
161337
+ async start({ env: env4 }) {
161338
+ const tail = [];
161339
+ boot = () => {
161340
+ child = spawn5("bun", [file2], {
161341
+ cwd: cwd2,
161342
+ stdio: ["ignore", "pipe", "pipe"],
161343
+ env: {
161344
+ ...process.env,
161345
+ ...env4,
161346
+ ...merged.environment ?? {},
161347
+ STACK: stackConfig.name,
161348
+ PORT: String(healthPort),
161349
+ PATH: binPath(cwd2)
161350
+ }
161351
+ });
161352
+ const capture = (chunk3) => {
161353
+ for (const raw of chunk3.toString().split(`
161354
+ `)) {
161355
+ const line = stripAnsi2(raw);
161356
+ if (line.trim() === "") {
161357
+ continue;
161358
+ }
161359
+ tail.push(line);
161360
+ ctx.emitEvent(channel, { date: Date.now(), line });
161361
+ }
161362
+ while (tail.length > 20) {
161363
+ tail.shift();
161364
+ }
161365
+ };
161366
+ child.stdout?.on("data", capture);
161367
+ child.stderr?.on("data", capture);
161368
+ child.on("exit", (code) => {
161369
+ if (!stopping && code !== null && code !== 0) {
161370
+ logs_exports.error(`The instance "${id}" exited with code ${code}:
161371
+ ${tail.join(`
161372
+ `)}`);
161373
+ ctx.emitEvent(channel, { date: Date.now(), line: `Exited with code ${code}`, error: true });
161374
+ }
161375
+ });
161376
+ };
161377
+ boot();
161378
+ },
161379
+ async stop() {
161380
+ stopping = true;
161381
+ if (child) {
161382
+ await stopChild(child);
161383
+ }
161384
+ }
161385
+ });
161386
+ ctx.registerResource({
161387
+ kind: "instance",
161388
+ stack: stackConfig.name,
161389
+ id,
161390
+ detail: `http://localhost:${healthPort}`,
161391
+ queueUrl,
161392
+ channel,
161393
+ restart: () => restart("Restarting...")
161394
+ });
161395
+ }
161396
+ };
161397
+
161477
161398
  // src/feature/instance/util.ts
161478
161399
  import { toDays as toDays12, toSeconds as toSeconds11 } from "@awsless/duration";
161479
161400
  import { stringify as stringify3 } from "@awsless/json";
161480
161401
  import { generateFileHash as generateFileHash4 } from "@awsless/ts-file-cache";
161481
- var import_deepmerge6 = __toESM(require_cjs2(), 1);
161482
- import { createHash as createHash21 } from "crypto";
161483
- import { join as join44 } from "path";
161402
+ var import_deepmerge7 = __toESM(require_cjs2(), 1);
161403
+ import { createHash as createHash20 } from "crypto";
161404
+ import { join as join45 } from "path";
161484
161405
  var createFargateTask = (parentGroup, ctx, ns, id, local) => {
161485
161406
  const group4 = new Group(parentGroup, "instance", ns);
161486
161407
  const name = formatLocalResourceName({
@@ -161490,7 +161411,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
161490
161411
  resourceName: id
161491
161412
  });
161492
161413
  const shortName = shortId(`${ctx.app.name}:${ctx.stack.name}:${ns}:${id}:${ctx.appId}`);
161493
- const props = import_deepmerge6.default(ctx.appConfig.instance, local);
161414
+ const props = import_deepmerge7.default(ctx.appConfig.instance, local);
161494
161415
  const image = props.image || (props.architecture === "arm64" ? "public.ecr.aws/aws-cli/aws-cli:arm64" : "public.ecr.aws/aws-cli/aws-cli:amd64");
161495
161416
  ctx.registerBuild("instance", name, async (build2, { workspace }) => {
161496
161417
  const fingerprint = await generateFileHash4(workspace, local.code.file);
@@ -161682,7 +161603,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
161682
161603
  healthCheck: props.healthCheck ? {
161683
161604
  command: [
161684
161605
  "CMD-SHELL",
161685
- `curl -f http://${join44("localhost", props.healthCheck.path)} || exit 1`
161606
+ `curl -f http://${join45("localhost", props.healthCheck.path)} || exit 1`
161686
161607
  ],
161687
161608
  interval: toSeconds11(props.healthCheck.interval),
161688
161609
  retries: props.healthCheck.retries,
@@ -161769,7 +161690,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
161769
161690
  variables.AWS_ACCOUNT_ID = ctx.accountId;
161770
161691
  variables.STACK = ctx.stackConfig.name;
161771
161692
  variables.CODE_HASH = code.sourceHash;
161772
- variables.INSTANCE_CONFIG_HASH = createHash21("sha1").update(stringify3(props)).digest("hex");
161693
+ variables.INSTANCE_CONFIG_HASH = createHash20("sha1").update(stringify3(props)).digest("hex");
161773
161694
  if (props.environment) {
161774
161695
  for (const [key, value] of Object.entries(props.environment)) {
161775
161696
  variables[key] = value;
@@ -161804,6 +161725,7 @@ type TestMockEntry = MockBuilder & MockObject
161804
161725
  `;
161805
161726
  var instanceFeature = defineFeature({
161806
161727
  name: "instance",
161728
+ onDev: instanceOnDev,
161807
161729
  async onTypeGen(ctx) {
161808
161730
  const gen = new TypeFile("awsless");
161809
161731
  const resources = new TypeObject(1);
@@ -164264,12 +164186,12 @@ import { DynamoDBClient as DynamoDBClient4 } from "@awsless/dynamodb";
164264
164186
  // src/cli/ui/complex/run-tests.ts
164265
164187
  var import_wildstring2 = __toESM(require_wildstring(), 1);
164266
164188
  import { mkdir as mkdir7, readFile as readFile19, writeFile as writeFile10 } from "fs/promises";
164267
- import { join as join46 } from "path";
164189
+ import { join as join47 } from "path";
164268
164190
  import { parse as parse7, stringify as stringify4 } from "@awsless/json";
164269
164191
  import { generateFolderHash, loadWorkspace as loadWorkspace2 } from "@awsless/ts-file-cache";
164270
164192
 
164271
164193
  // src/test/start.ts
164272
- import { dirname as dirname20, join as join45 } from "path";
164194
+ import { dirname as dirname21, join as join46 } from "path";
164273
164195
  import { fileURLToPath as fileURLToPath15 } from "url";
164274
164196
  import { configDefaults } from "vitest/config";
164275
164197
  import { startVitest } from "vitest/node";
@@ -164323,7 +164245,7 @@ ${statements.join(`
164323
164245
  class NullReporter {
164324
164246
  }
164325
164247
  var startTest = async (props) => {
164326
- const __dirname4 = dirname20(fileURLToPath15(import.meta.url));
164248
+ const __dirname4 = dirname21(fileURLToPath15(import.meta.url));
164327
164249
  const startTime = process.hrtime.bigint();
164328
164250
  process.noDeprecation = true;
164329
164251
  const nodeEnv = process.env["NODE_ENV"];
@@ -164345,7 +164267,7 @@ var startTest = async (props) => {
164345
164267
  reporters: [new NullReporter],
164346
164268
  env: props.env,
164347
164269
  setupFiles: [
164348
- join45(__dirname4, "test-global-setup.js")
164270
+ join46(__dirname4, "test-global-setup.js")
164349
164271
  ]
164350
164272
  }, {
164351
164273
  logLevel: "silent",
@@ -164501,7 +164423,7 @@ var logTestErrors = (event) => {
164501
164423
  };
164502
164424
  var runTest = async (stack, dir, filters, workspace, opts) => {
164503
164425
  await mkdir7(directories.test, { recursive: true });
164504
- const file2 = join46(directories.test, `${stack}.json`);
164426
+ const file2 = join47(directories.test, `${stack}.json`);
164505
164427
  const fingerprint = await generateFolderHash(workspace, dir);
164506
164428
  if (!process.env.NO_CACHE) {
164507
164429
  const exists4 = await fileExist(file2);
@@ -165411,12 +165333,12 @@ var auth = (program3) => {
165411
165333
 
165412
165334
  // src/cli/command/bind.ts
165413
165335
  import { readFile as readFile20 } from "fs/promises";
165414
- import { join as join47 } from "path";
165336
+ import { join as join48 } from "path";
165415
165337
  var bind = (program3) => {
165416
165338
  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) => {
165417
165339
  await layout("bind", async ({ appConfig, stackConfigs }) => {
165418
165340
  if (opts.local) {
165419
- const file2 = join47(directories.output, "local", "env.json");
165341
+ const file2 = join48(directories.output, "local", "env.json");
165420
165342
  let env5;
165421
165343
  try {
165422
165344
  env5 = JSON.parse(await readFile20(file2, "utf8"));
@@ -166210,17 +166132,17 @@ var watchConfig = async (options, resolve5, reject) => {
166210
166132
  // src/dev/index.ts
166211
166133
  import { loadWorkspace as loadWorkspace3 } from "@awsless/ts-file-cache";
166212
166134
  import { mkdir as mkdir10, rm as rm12, writeFile as writeFile14 } from "fs/promises";
166213
- import { join as join54 } from "path";
166135
+ import { join as join55 } from "path";
166214
166136
 
166215
166137
  // src/dev/context.ts
166216
166138
  import { DynamoDBServer } from "@awsless/dynamodb-server";
166217
- import { join as join49 } from "path";
166139
+ import { join as join50 } from "path";
166218
166140
 
166219
166141
  // src/dev/servers/s3.ts
166220
- import { createHash as createHash22 } from "crypto";
166221
- import { createServer as createServer8 } from "http";
166142
+ import { createHash as createHash21 } from "crypto";
166143
+ import { createServer as createServer7 } from "http";
166222
166144
  import { mkdir as mkdir8, readdir as readdir8, readFile as readFile21, rm as rm10, stat as stat7, writeFile as writeFile11 } from "fs/promises";
166223
- import { dirname as dirname21, join as join48, relative as relative9, sep as sep4 } from "path";
166145
+ import { dirname as dirname22, join as join49, relative as relative9, sep as sep4 } from "path";
166224
166146
  var readBody2 = (req) => {
166225
166147
  return new Promise((resolve5, reject) => {
166226
166148
  const chunks = [];
@@ -166290,8 +166212,8 @@ var createS3Server = (props) => {
166290
166212
  res.end(xmlError("InvalidRequest", "Missing bucket name"));
166291
166213
  return;
166292
166214
  }
166293
- const bucketDir = join48(props.root, bucket);
166294
- const file2 = join48(bucketDir, ...keyParts);
166215
+ const bucketDir = join49(props.root, bucket);
166216
+ const file2 = join49(bucketDir, ...keyParts);
166295
166217
  if (relative9(bucketDir, file2).startsWith("..")) {
166296
166218
  res.writeHead(400, { "content-type": "application/xml" });
166297
166219
  res.end(xmlError("InvalidRequest", "Invalid object key"));
@@ -166308,7 +166230,7 @@ var createS3Server = (props) => {
166308
166230
  return;
166309
166231
  }
166310
166232
  for (const entry of entries2) {
166311
- const path6 = join48(dir, entry.name);
166233
+ const path6 = join49(dir, entry.name);
166312
166234
  if (entry.isDirectory()) {
166313
166235
  await walk2(path6);
166314
166236
  } else {
@@ -166334,9 +166256,9 @@ var createS3Server = (props) => {
166334
166256
  if (typeof encoding === "string" && encoding.includes("aws-chunked") || typeof sha === "string" && sha.startsWith("STREAMING")) {
166335
166257
  body = decodeAwsChunked(body);
166336
166258
  }
166337
- await mkdir8(dirname21(file2), { recursive: true });
166259
+ await mkdir8(dirname22(file2), { recursive: true });
166338
166260
  await writeFile11(file2, body);
166339
- const eTag = createHash22("md5").update(body).digest("hex");
166261
+ const eTag = createHash21("md5").update(body).digest("hex");
166340
166262
  res.writeHead(200, { etag: `"${eTag}"` });
166341
166263
  res.end();
166342
166264
  notify("ObjectCreated:Put", bucket, key, body.length, eTag);
@@ -166353,7 +166275,7 @@ var createS3Server = (props) => {
166353
166275
  }
166354
166276
  res.writeHead(200, {
166355
166277
  "content-length": body.length,
166356
- etag: `"${createHash22("md5").update(body).digest("hex")}"`
166278
+ etag: `"${createHash21("md5").update(body).digest("hex")}"`
166357
166279
  });
166358
166280
  res.end(req.method === "HEAD" ? undefined : body);
166359
166281
  return;
@@ -166374,7 +166296,7 @@ var createS3Server = (props) => {
166374
166296
  reportFailure = reportFailureFn;
166375
166297
  },
166376
166298
  async listen(port = 0) {
166377
- server = createServer8((req, res) => {
166299
+ server = createServer7((req, res) => {
166378
166300
  handle(req, res).catch((error3) => {
166379
166301
  res.writeHead(500, { "content-type": "application/xml" });
166380
166302
  res.end(xmlError("InternalError", error3 instanceof Error ? error3.message : String(error3)));
@@ -166393,6 +166315,323 @@ var createS3Server = (props) => {
166393
166315
  };
166394
166316
  };
166395
166317
 
166318
+ // src/dev/servers/sqs.ts
166319
+ import { createHash as createHash22, randomUUID as randomUUID5 } from "crypto";
166320
+ import { createServer as createServer8 } from "http";
166321
+ var md5 = (value) => createHash22("md5").update(value).digest("hex");
166322
+ var md5OfAttributes = (attributes) => {
166323
+ const parts = [];
166324
+ const push = (value) => {
166325
+ const data = Buffer.from(value, "utf8");
166326
+ const size2 = Buffer.alloc(4);
166327
+ size2.writeUInt32BE(data.length);
166328
+ parts.push(size2, data);
166329
+ };
166330
+ for (const name of Object.keys(attributes).sort()) {
166331
+ const attribute = attributes[name];
166332
+ push(name);
166333
+ push(attribute.DataType ?? "String");
166334
+ if (typeof attribute.BinaryValue === "string") {
166335
+ const data = Buffer.from(attribute.BinaryValue, "base64");
166336
+ const size2 = Buffer.alloc(4);
166337
+ size2.writeUInt32BE(data.length);
166338
+ parts.push(Buffer.from([2]), size2, data);
166339
+ } else {
166340
+ const data = Buffer.from(attribute.StringValue ?? "", "utf8");
166341
+ const size2 = Buffer.alloc(4);
166342
+ size2.writeUInt32BE(data.length);
166343
+ parts.push(Buffer.from([1]), size2, data);
166344
+ }
166345
+ }
166346
+ return md5(Buffer.concat(parts));
166347
+ };
166348
+ var formatEventAttributes = (attributes) => {
166349
+ const list3 = {};
166350
+ for (const [name, attribute] of Object.entries(attributes)) {
166351
+ list3[name] = {
166352
+ dataType: attribute.DataType ?? "String",
166353
+ stringValue: attribute.StringValue,
166354
+ binaryValue: attribute.BinaryValue
166355
+ };
166356
+ }
166357
+ return list3;
166358
+ };
166359
+ var createSqsServer = (props) => {
166360
+ let server;
166361
+ let closeServer;
166362
+ let dispatch;
166363
+ let reportFailure;
166364
+ let boundPort = 0;
166365
+ const stores = new Map;
166366
+ const queueFromUrl = (url) => {
166367
+ const name = url?.split("/").filter(Boolean).at(-1);
166368
+ return name && props.queues.has(name) ? name : undefined;
166369
+ };
166370
+ const storeOf = (queue) => {
166371
+ if (!stores.has(queue)) {
166372
+ stores.set(queue, []);
166373
+ }
166374
+ return stores.get(queue);
166375
+ };
166376
+ const deliver = (queue, input, messageId) => {
166377
+ const now = Date.now();
166378
+ if (props.queues.get(queue) === undefined) {
166379
+ storeOf(queue).push({
166380
+ id: messageId,
166381
+ body: input.MessageBody ?? "",
166382
+ attributes: input.MessageAttributes ?? {},
166383
+ sentAt: now,
166384
+ receiveCount: 0,
166385
+ visibleAt: now + (input.DelaySeconds ?? 0) * 1000
166386
+ });
166387
+ return;
166388
+ }
166389
+ const event = {
166390
+ Records: [
166391
+ {
166392
+ messageId,
166393
+ receiptHandle: randomUUID5(),
166394
+ body: input.MessageBody,
166395
+ attributes: {
166396
+ ApproximateReceiveCount: "1",
166397
+ SentTimestamp: String(now),
166398
+ SenderId: "local",
166399
+ ApproximateFirstReceiveTimestamp: String(now)
166400
+ },
166401
+ messageAttributes: formatEventAttributes(input.MessageAttributes ?? {}),
166402
+ md5OfBody: md5(input.MessageBody ?? ""),
166403
+ eventSource: "aws:sqs",
166404
+ eventSourceARN: `arn:aws:sqs:${props.region}:${props.accountId}:${queue}`,
166405
+ awsRegion: props.region
166406
+ }
166407
+ ]
166408
+ };
166409
+ const send = () => {
166410
+ dispatch?.(event).catch((error3) => {
166411
+ let body = input.MessageBody;
166412
+ try {
166413
+ body = JSON.parse(input.MessageBody ?? "");
166414
+ } catch (_4) {}
166415
+ reportFailure?.({
166416
+ kind: "queue",
166417
+ routeKey: props.queues.get(queue),
166418
+ event: body,
166419
+ error: error3,
166420
+ queue: { name: queue }
166421
+ });
166422
+ });
166423
+ };
166424
+ if (input.DelaySeconds) {
166425
+ setTimeout(send, input.DelaySeconds * 1000);
166426
+ } else {
166427
+ setImmediate(send);
166428
+ }
166429
+ };
166430
+ const sendResult = (input, messageId) => {
166431
+ return {
166432
+ MessageId: messageId,
166433
+ MD5OfMessageBody: md5(input.MessageBody ?? ""),
166434
+ ...input.MessageAttributes && Object.keys(input.MessageAttributes).length > 0 ? { MD5OfMessageAttributes: md5OfAttributes(input.MessageAttributes) } : {}
166435
+ };
166436
+ };
166437
+ const queueUrl = (name) => {
166438
+ return `http://127.0.0.1:${boundPort}/${props.accountId}/${name}`;
166439
+ };
166440
+ const findByReceipt = (queue, receipt) => {
166441
+ return storeOf(queue).find((message4) => message4.receipt === receipt);
166442
+ };
166443
+ const actions = {
166444
+ GetQueueUrl(input) {
166445
+ if (!input.QueueName || !props.queues.has(input.QueueName)) {
166446
+ throw new Error(`Unknown local queue: ${input.QueueName}`);
166447
+ }
166448
+ return {
166449
+ QueueUrl: queueUrl(input.QueueName)
166450
+ };
166451
+ },
166452
+ SendMessage(input) {
166453
+ const queue = queueFromUrl(input.QueueUrl);
166454
+ if (!queue) {
166455
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166456
+ }
166457
+ const messageId = randomUUID5();
166458
+ deliver(queue, input, messageId);
166459
+ return sendResult(input, messageId);
166460
+ },
166461
+ SendMessageBatch(input) {
166462
+ const queue = queueFromUrl(input.QueueUrl);
166463
+ if (!queue) {
166464
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166465
+ }
166466
+ return {
166467
+ Successful: (input.Entries ?? []).map((entry) => {
166468
+ const messageId = randomUUID5();
166469
+ deliver(queue, entry, messageId);
166470
+ return {
166471
+ Id: entry.Id,
166472
+ ...sendResult(entry, messageId)
166473
+ };
166474
+ }),
166475
+ Failed: []
166476
+ };
166477
+ },
166478
+ async ReceiveMessage(input, signal) {
166479
+ const queue = queueFromUrl(input.QueueUrl);
166480
+ if (!queue) {
166481
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166482
+ }
166483
+ const store = storeOf(queue);
166484
+ const deadline = Date.now() + (input.WaitTimeSeconds ?? 0) * 1000;
166485
+ while (true) {
166486
+ const now = Date.now();
166487
+ const visible = store.filter((message4) => message4.visibleAt <= now);
166488
+ if (visible.length > 0) {
166489
+ const batch2 = visible.slice(0, Math.max(1, input.MaxNumberOfMessages ?? 1));
166490
+ return {
166491
+ Messages: batch2.map((message4) => {
166492
+ message4.receipt = randomUUID5();
166493
+ message4.receiveCount += 1;
166494
+ message4.firstReceivedAt ??= now;
166495
+ message4.visibleAt = now + (input.VisibilityTimeout ?? 30) * 1000;
166496
+ return {
166497
+ MessageId: message4.id,
166498
+ ReceiptHandle: message4.receipt,
166499
+ Body: message4.body,
166500
+ MD5OfBody: md5(message4.body),
166501
+ Attributes: {
166502
+ ApproximateReceiveCount: String(message4.receiveCount),
166503
+ SentTimestamp: String(message4.sentAt),
166504
+ SenderId: "local",
166505
+ ApproximateFirstReceiveTimestamp: String(message4.firstReceivedAt)
166506
+ },
166507
+ ...Object.keys(message4.attributes).length > 0 ? {
166508
+ MessageAttributes: message4.attributes,
166509
+ MD5OfMessageAttributes: md5OfAttributes(message4.attributes)
166510
+ } : {}
166511
+ };
166512
+ })
166513
+ };
166514
+ }
166515
+ if (now >= deadline || signal.aborted) {
166516
+ return {};
166517
+ }
166518
+ await new Promise((resolve5) => setTimeout(resolve5, 100));
166519
+ }
166520
+ },
166521
+ DeleteMessage(input) {
166522
+ const queue = queueFromUrl(input.QueueUrl);
166523
+ if (!queue) {
166524
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166525
+ }
166526
+ const store = storeOf(queue);
166527
+ const index = store.findIndex((message4) => message4.receipt === input.ReceiptHandle);
166528
+ if (index >= 0) {
166529
+ store.splice(index, 1);
166530
+ }
166531
+ return {};
166532
+ },
166533
+ DeleteMessageBatch(input) {
166534
+ const queue = queueFromUrl(input.QueueUrl);
166535
+ if (!queue) {
166536
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166537
+ }
166538
+ const store = storeOf(queue);
166539
+ return {
166540
+ Successful: (input.Entries ?? []).map((entry) => {
166541
+ const index = store.findIndex((message4) => message4.receipt === entry.ReceiptHandle);
166542
+ if (index >= 0) {
166543
+ store.splice(index, 1);
166544
+ }
166545
+ return { Id: entry.Id };
166546
+ }),
166547
+ Failed: []
166548
+ };
166549
+ },
166550
+ ChangeMessageVisibility(input) {
166551
+ const queue = queueFromUrl(input.QueueUrl);
166552
+ if (!queue) {
166553
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166554
+ }
166555
+ const message4 = findByReceipt(queue, input.ReceiptHandle);
166556
+ if (message4) {
166557
+ message4.visibleAt = Date.now() + (input.VisibilityTimeout ?? 0) * 1000;
166558
+ }
166559
+ return {};
166560
+ },
166561
+ GetQueueAttributes(input) {
166562
+ const queue = queueFromUrl(input.QueueUrl);
166563
+ if (!queue) {
166564
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166565
+ }
166566
+ const now = Date.now();
166567
+ const store = storeOf(queue);
166568
+ return {
166569
+ Attributes: {
166570
+ QueueArn: `arn:aws:sqs:${props.region}:${props.accountId}:${queue}`,
166571
+ ApproximateNumberOfMessages: String(store.filter((m4) => m4.visibleAt <= now).length),
166572
+ ApproximateNumberOfMessagesNotVisible: String(store.filter((m4) => m4.visibleAt > now).length)
166573
+ }
166574
+ };
166575
+ },
166576
+ PurgeQueue(input) {
166577
+ const queue = queueFromUrl(input.QueueUrl);
166578
+ if (!queue) {
166579
+ throw new Error(`Unknown local queue: ${input.QueueUrl}`);
166580
+ }
166581
+ storeOf(queue).length = 0;
166582
+ return {};
166583
+ }
166584
+ };
166585
+ return {
166586
+ connect(dispatchFn, reportFailureFn) {
166587
+ dispatch = dispatchFn;
166588
+ reportFailure = reportFailureFn;
166589
+ },
166590
+ async listen(port = 0) {
166591
+ server = createServer8((req, res) => {
166592
+ const chunks = [];
166593
+ req.on("data", (chunk3) => chunks.push(chunk3));
166594
+ req.on("end", async () => {
166595
+ const target2 = String(req.headers["x-amz-target"] ?? "");
166596
+ const action = actions[target2.split(".").at(-1) ?? ""];
166597
+ const abort = new AbortController;
166598
+ res.on("close", () => abort.abort());
166599
+ try {
166600
+ if (!action) {
166601
+ throw new Error(`The local dev sqs emulator does not support: ${target2}`);
166602
+ }
166603
+ const result = await action(JSON.parse(Buffer.concat(chunks).toString() || "{}"), abort.signal);
166604
+ if (res.writableEnded || res.destroyed) {
166605
+ return;
166606
+ }
166607
+ res.writeHead(200, { "content-type": "application/x-amz-json-1.0" });
166608
+ res.end(JSON.stringify(result));
166609
+ } catch (error3) {
166610
+ if (res.writableEnded || res.destroyed) {
166611
+ return;
166612
+ }
166613
+ res.writeHead(400, { "content-type": "application/x-amz-json-1.0" });
166614
+ res.end(JSON.stringify({
166615
+ __type: "InvalidAction",
166616
+ message: error3 instanceof Error ? error3.message : String(error3)
166617
+ }));
166618
+ }
166619
+ });
166620
+ });
166621
+ await new Promise((resolve5, reject) => {
166622
+ server.once("error", reject);
166623
+ closeServer = trackConnections(server);
166624
+ server.listen(port, "127.0.0.1", () => resolve5());
166625
+ });
166626
+ boundPort = server.address().port;
166627
+ return boundPort;
166628
+ },
166629
+ stop() {
166630
+ return closeServer?.() ?? Promise.resolve();
166631
+ }
166632
+ };
166633
+ };
166634
+
166396
166635
  // src/dev/context.ts
166397
166636
  var createDevContext = (props) => {
166398
166637
  const env4 = {};
@@ -166447,7 +166686,7 @@ var createDevContext = (props) => {
166447
166686
  const value = await props.pool.keep("store", null, async () => {
166448
166687
  const rules = [];
166449
166688
  const server = createS3Server({
166450
- root: join49(directories.output, "local", "store"),
166689
+ root: join50(directories.output, "local", "store"),
166451
166690
  region: props.appConfig.region,
166452
166691
  rules
166453
166692
  });
@@ -166469,6 +166708,34 @@ var createDevContext = (props) => {
166469
166708
  })();
166470
166709
  return store;
166471
166710
  };
166711
+ let sqs;
166712
+ const useSqs = () => {
166713
+ sqs ??= (async () => {
166714
+ const value = await props.pool.keep("shim:sqs", null, async () => {
166715
+ const queues = new Map;
166716
+ const server = createSqsServer({
166717
+ region: props.appConfig.region,
166718
+ accountId: "000000000000",
166719
+ queues
166720
+ });
166721
+ const port = await server.listen();
166722
+ return {
166723
+ value: { server, port, queues },
166724
+ stop: () => server.stop()
166725
+ };
166726
+ });
166727
+ value.queues.clear();
166728
+ env4["AWS_ENDPOINT_URL_SQS"] = `http://127.0.0.1:${value.port}`;
166729
+ servers.push({
166730
+ name: "sqs",
166731
+ start({ dispatch, reportFailure }) {
166732
+ value.server.connect(dispatch, reportFailure);
166733
+ }
166734
+ });
166735
+ return { port: value.port, queues: value.queues };
166736
+ })();
166737
+ return sqs;
166738
+ };
166472
166739
  return {
166473
166740
  env: env4,
166474
166741
  routes,
@@ -166492,6 +166759,7 @@ var createDevContext = (props) => {
166492
166759
  peek: props.pool.peek,
166493
166760
  useDynamo,
166494
166761
  useStore,
166762
+ useSqs,
166495
166763
  addEnv(name, value) {
166496
166764
  if (name in env4 && env4[name] !== value) {
166497
166765
  throw new Error(`The env var "${name}" is defined multiple times with different values, while all bundled functions share the same env.`);
@@ -166517,10 +166785,10 @@ var createDevContext = (props) => {
166517
166785
  };
166518
166786
 
166519
166787
  // src/dev/seed.ts
166520
- import { spawn as spawn5 } from "child_process";
166521
- import { isAbsolute as isAbsolute4, join as join50 } from "path";
166788
+ import { spawn as spawn6 } from "child_process";
166789
+ import { isAbsolute as isAbsolute4, join as join51 } from "path";
166522
166790
  var createSeedRunner = (props) => {
166523
- const file2 = props.seed && (isAbsolute4(props.seed) ? props.seed : join50(directories.root, props.seed));
166791
+ const file2 = props.seed && (isAbsolute4(props.seed) ? props.seed : join51(directories.root, props.seed));
166524
166792
  let running;
166525
166793
  const run = () => {
166526
166794
  running ??= (async () => {
@@ -166530,7 +166798,7 @@ var createSeedRunner = (props) => {
166530
166798
  }
166531
166799
  debug(`Seeding from ${props.seed}`);
166532
166800
  await new Promise((resolve5, reject) => {
166533
- const child = spawn5("bun", [file2], {
166801
+ const child = spawn6("bun", [file2], {
166534
166802
  cwd: directories.root,
166535
166803
  stdio: ["ignore", "pipe", "pipe"],
166536
166804
  env: { ...process.env, ...props.env }
@@ -166571,13 +166839,13 @@ import { DynamoDBDocumentClient, ScanCommand as ScanCommand2 } from "@aws-sdk/li
166571
166839
  import { randomUUID as randomUUID6 } from "crypto";
166572
166840
  import { readdir as readdir9, readFile as readFile22, stat as stat8, writeFile as writeFile13 } from "fs/promises";
166573
166841
  import { createServer as createServer9 } from "http";
166574
- import { join as join52, relative as relative10, sep as sep5 } from "path";
166842
+ import { join as join53, relative as relative10, sep as sep5 } from "path";
166575
166843
 
166576
166844
  // src/dev/worker.ts
166577
- import { spawn as spawn6 } from "child_process";
166845
+ import { spawn as spawn7 } from "child_process";
166578
166846
  import { writeFile as writeFile12 } from "fs/promises";
166579
166847
  import { availableParallelism } from "os";
166580
- import { join as join51 } from "path";
166848
+ import { join as join52 } from "path";
166581
166849
  class WorkerError extends Error {
166582
166850
  name;
166583
166851
  constructor(name, message4, stack) {
@@ -166694,9 +166962,9 @@ var createBundleWorker = (props) => {
166694
166962
  throw new Error("The bundle worker never became ready.");
166695
166963
  };
166696
166964
  const startWorker = async () => {
166697
- const entry = join51(props.buildDir, "worker.mjs");
166965
+ const entry = join52(props.buildDir, "worker.mjs");
166698
166966
  const port = await findFreePort();
166699
- const child = spawn6("node", ["--enable-source-maps", entry], {
166967
+ const child = spawn7("node", ["--enable-source-maps", entry], {
166700
166968
  cwd: props.buildDir,
166701
166969
  stdio: ["ignore", "pipe", "pipe"],
166702
166970
  env: {
@@ -166748,7 +167016,7 @@ var createBundleWorker = (props) => {
166748
167016
  return worker;
166749
167017
  };
166750
167018
  const start = async () => {
166751
- await writeFile12(join51(props.buildDir, "worker.mjs"), WORKER_ENTRY);
167019
+ await writeFile12(join52(props.buildDir, "worker.mjs"), WORKER_ENTRY);
166752
167020
  workers = await Promise.all(Array.from({ length: concurrency }, () => startWorker()));
166753
167021
  };
166754
167022
  const stop = async () => {
@@ -167089,6 +167357,7 @@ const GROUPS = [
167089
167357
  ['function', 'Functions'],
167090
167358
  ['cron', 'Crons'],
167091
167359
  ['task', 'Tasks'],
167360
+ ['instance', 'Instances'],
167092
167361
  ['queue', 'Queues'],
167093
167362
  ['topic', 'Topics'],
167094
167363
  ['subscriber', 'Subscribers'],
@@ -167115,6 +167384,7 @@ const ICONS = {
167115
167384
  function: svg('<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>'),
167116
167385
  cron: svg('<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>'),
167117
167386
  task: svg('<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>'),
167387
+ instance: svg('<line x1="22" y1="12" x2="2" y2="12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/><line x1="6" y1="16" x2="6.01" y2="16"/><line x1="10" y1="16" x2="10.01" y2="16"/>'),
167118
167388
  queue: svg('<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>'),
167119
167389
  topic: svg('<line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>'),
167120
167390
  subscriber: svg('<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>'),
@@ -167274,6 +167544,74 @@ const invokePanel = (main, r) => {
167274
167544
  }
167275
167545
  }
167276
167546
 
167547
+ const instancePanel = (main, r) => {
167548
+ // A message into the instance's queue, like Instance.stack.name()
167549
+ // sends. The last payload survives reloads & panel switches.
167550
+ const storageKey = 'invoke-payload:' + r.kind + ':' + (r.stack ?? '-') + ':' + r.id
167551
+ const placeholder = '{}'
167552
+ const input = $('textarea', { value: localStorage.getItem(storageKey) ?? placeholder, spellcheck: false })
167553
+ const status = $('span', { className: 'status' })
167554
+ const result = $('pre', { className: 'result', hidden: true })
167555
+ const send = $('button', { className: 'primary', textContent: 'Send' })
167556
+ const reset = $('button', { className: 'secondary', textContent: 'Reset' })
167557
+ const restart = $('button', { className: 'secondary', textContent: 'Restart' })
167558
+
167559
+ input.oninput = () => localStorage.setItem(storageKey, input.value)
167560
+
167561
+ reset.onclick = () => {
167562
+ localStorage.removeItem(storageKey)
167563
+ input.value = placeholder
167564
+ }
167565
+
167566
+ restart.onclick = async () => {
167567
+ restart.disabled = true
167568
+ status.textContent = ''
167569
+ result.hidden = true
167570
+ try {
167571
+ await api('/api/instance/restart', {
167572
+ method: 'POST',
167573
+ body: JSON.stringify({ stack: r.stack, id: r.id }),
167574
+ })
167575
+ status.textContent = 'restarted'
167576
+ } catch (error) {
167577
+ result.className = 'result error'
167578
+ result.textContent = String(error.message ?? error)
167579
+ result.hidden = false
167580
+ }
167581
+ restart.disabled = false
167582
+ }
167583
+
167584
+ send.onclick = async () => {
167585
+ send.disabled = true
167586
+ status.textContent = ''
167587
+ result.hidden = true
167588
+ try {
167589
+ const payload = input.value.trim() ? JSON.parse(input.value) : {}
167590
+ await api('/api/instance/send', {
167591
+ method: 'POST',
167592
+ body: JSON.stringify({ stack: r.stack, id: r.id, payload }),
167593
+ })
167594
+ status.textContent = 'sent'
167595
+ } catch (error) {
167596
+ result.className = 'result error'
167597
+ result.textContent = String(error.message ?? error)
167598
+ result.hidden = false
167599
+ }
167600
+ send.disabled = false
167601
+ }
167602
+
167603
+ main.append(
167604
+ $('p', {}, $('a', { href: r.detail, target: '_blank', style: 'color: var(--accent)' }, r.detail)),
167605
+ input,
167606
+ $('div', { className: 'actions' }, [send, reset, restart, status]),
167607
+ result,
167608
+ )
167609
+
167610
+ if (r.channel) {
167611
+ cleanupPanel = attachLogFeed(main, r.channel)
167612
+ }
167613
+ }
167614
+
167277
167615
  const pubsubPanel = (main, r) => {
167278
167616
  const topic = $('input', { placeholder: 'topic', value: 'my-topic', autocomplete: 'off' })
167279
167617
  const event = $('input', { placeholder: 'event', value: 'my-event', autocomplete: 'off' })
@@ -167910,6 +168248,7 @@ const renderResource = main => {
167910
168248
  $('p', { className: 'detail' }, [r.kind, r.detail ? ' \xB7 ' + r.detail : '', r.routeKey ? ' \xB7 ' + r.routeKey : '']),
167911
168249
  )
167912
168250
 
168251
+ if (r.kind === 'instance') return instancePanel(main, r)
167913
168252
  if (r.kind === 'pubsub') return pubsubPanel(main, r)
167914
168253
  if (r.kind === 'rpc') return rpcPanel(main, r)
167915
168254
  if (r.kind === 'search') return searchPanel(main, r)
@@ -168215,6 +168554,44 @@ var createDashboardServer = (props) => {
168215
168554
  });
168216
168555
  return { status: 200, body: JSON.stringify({ result: result ?? null }) };
168217
168556
  }
168557
+ if (url.pathname === "/api/instance/send" && req.method === "POST") {
168558
+ const { stack, id, payload } = JSON.parse((await readBody3(req)).toString() || "{}");
168559
+ const resource = props.resources.find((r5) => r5.kind === "instance" && r5.stack === stack && r5.id === id);
168560
+ if (!resource?.queueUrl) {
168561
+ return { status: 400, body: JSON.stringify({ error: `Unknown instance: ${stack}/${id}` }) };
168562
+ }
168563
+ const queueName = resource.queueUrl.split("/").at(-1) ?? "";
168564
+ const res = await fetch(resource.queueUrl, {
168565
+ method: "POST",
168566
+ headers: {
168567
+ "content-type": "application/x-amz-json-1.0",
168568
+ "x-amz-target": "AmazonSQS.SendMessage"
168569
+ },
168570
+ body: JSON.stringify({
168571
+ QueueUrl: resource.queueUrl,
168572
+ MessageBody: JSON.stringify(payload ?? {}),
168573
+ MessageAttributes: {
168574
+ queue: { DataType: "String", StringValue: queueName },
168575
+ queueUrl: { DataType: "String", StringValue: resource.queueUrl },
168576
+ queueName: { DataType: "String", StringValue: queueName }
168577
+ }
168578
+ })
168579
+ });
168580
+ if (!res.ok) {
168581
+ const data = await res.json().catch(() => ({}));
168582
+ return { status: 400, body: JSON.stringify({ error: data.message ?? res.statusText }) };
168583
+ }
168584
+ return { status: 200, body: JSON.stringify({ result: "sent" }) };
168585
+ }
168586
+ if (url.pathname === "/api/instance/restart" && req.method === "POST") {
168587
+ const { stack, id } = JSON.parse((await readBody3(req)).toString() || "{}");
168588
+ const resource = props.resources.find((r5) => r5.kind === "instance" && r5.stack === stack && r5.id === id);
168589
+ if (!resource?.restart) {
168590
+ return { status: 400, body: JSON.stringify({ error: `Unknown instance: ${stack}/${id}` }) };
168591
+ }
168592
+ await resource.restart();
168593
+ return { status: 200, body: JSON.stringify({ result: "restarted" }) };
168594
+ }
168218
168595
  if (url.pathname === "/api/table") {
168219
168596
  const name = url.searchParams.get("name");
168220
168597
  try {
@@ -168278,7 +168655,7 @@ var createDashboardServer = (props) => {
168278
168655
  return;
168279
168656
  }
168280
168657
  for (const entry of entries2) {
168281
- const path6 = join52(dir, entry.name);
168658
+ const path6 = join53(dir, entry.name);
168282
168659
  if (entry.isDirectory()) {
168283
168660
  await walk2(path6);
168284
168661
  } else {
@@ -168581,28 +168958,28 @@ var createLambdaServer = (props) => {
168581
168958
  // src/dev/sdk.ts
168582
168959
  import { readdir as readdir10, readFile as readFile23, mkdir as mkdir9, rm as rm11, symlink } from "fs/promises";
168583
168960
  import { createRequire } from "module";
168584
- import { dirname as dirname22, join as join53 } from "path";
168961
+ import { dirname as dirname23, join as join54 } from "path";
168585
168962
  var linkSdkPackages = async (buildDir, onWarn) => {
168586
- const filesDir = join53(buildDir, "files");
168963
+ const filesDir = join54(buildDir, "files");
168587
168964
  const packages = new Set;
168588
168965
  for (const file2 of await readdir10(filesDir)) {
168589
168966
  if (!file2.endsWith(".mjs")) {
168590
168967
  continue;
168591
168968
  }
168592
- const code = await readFile23(join53(filesDir, file2), "utf8");
168969
+ const code = await readFile23(join54(filesDir, file2), "utf8");
168593
168970
  for (const match3 of code.matchAll(/(?:from\s*|import\()\s*["'](@aws-sdk\/[a-z0-9-]+|sharp)["']/g)) {
168594
168971
  packages.add(match3[1]);
168595
168972
  }
168596
168973
  }
168597
- const projectRequire = createRequire(join53(directories.root, "noop.js"));
168974
+ const projectRequire = createRequire(join54(directories.root, "noop.js"));
168598
168975
  const ownRequire = createRequire(import.meta.url);
168599
168976
  const resolveFromStore = async (name) => {
168600
- const store = join53(directories.root, "node_modules", ".pnpm");
168977
+ const store = join54(directories.root, "node_modules", ".pnpm");
168601
168978
  const prefix = name.replaceAll("/", "+") + "@";
168602
168979
  try {
168603
168980
  const entries2 = (await readdir10(store)).filter((entry) => entry.startsWith(prefix));
168604
168981
  const best = entries2.sort((a4, b6) => a4.slice(prefix.length).localeCompare(b6.slice(prefix.length), undefined, { numeric: true })).at(-1);
168605
- return best ? join53(store, best, "node_modules", name) : undefined;
168982
+ return best ? join54(store, best, "node_modules", name) : undefined;
168606
168983
  } catch (_4) {
168607
168984
  return;
168608
168985
  }
@@ -168615,14 +168992,14 @@ var linkSdkPackages = async (buildDir, onWarn) => {
168615
168992
  let source = await resolveFromStore(name);
168616
168993
  if (!source) {
168617
168994
  try {
168618
- source = dirname22(ownRequire.resolve(`${name}/package.json`));
168995
+ source = dirname23(ownRequire.resolve(`${name}/package.json`));
168619
168996
  } catch (_4) {
168620
168997
  onWarn?.(`The bundle imports "${name}", which is neither a project dependency nor shipped with the cli. Add it to your project dependencies.`);
168621
168998
  continue;
168622
168999
  }
168623
169000
  }
168624
- const target2 = join53(buildDir, "node_modules", name);
168625
- await mkdir9(dirname22(target2), { recursive: true });
169001
+ const target2 = join54(buildDir, "node_modules", name);
169002
+ await mkdir9(dirname23(target2), { recursive: true });
168626
169003
  await rm11(target2, { recursive: true, force: true });
168627
169004
  await symlink(source, target2, "dir");
168628
169005
  }
@@ -168645,7 +169022,7 @@ var startDev = async (props) => {
168645
169022
  dev: true
168646
169023
  });
168647
169024
  ready2();
168648
- await mkdir10(join54(directories.output, "local"), { recursive: true });
169025
+ await mkdir10(join55(directories.output, "local"), { recursive: true });
168649
169026
  const routerPorts = {};
168650
169027
  Object.keys(appConfig.router ?? {}).forEach((id, index) => {
168651
169028
  routerPorts[id] = props.port + 1 + index;
@@ -168700,7 +169077,7 @@ var startDev = async (props) => {
168700
169077
  for (const [id, port] of Object.entries(routerPorts)) {
168701
169078
  env5[`ROUTER_${constantCase(id)}_ENDPOINT`] = `localhost:${port}`;
168702
169079
  }
168703
- await writeFile14(join54(directories.output, "local", "env.json"), JSON.stringify(env5, null, "\t") + `
169080
+ await writeFile14(join55(directories.output, "local", "env.json"), JSON.stringify(env5, null, "\t") + `
168704
169081
  `);
168705
169082
  return { env: env5, lambda: lambda2 };
168706
169083
  });
@@ -168835,8 +169212,8 @@ var startDev = async (props) => {
168835
169212
  resources: dev.resources,
168836
169213
  routes: dev.routes,
168837
169214
  env: env4,
168838
- storeRoot: join54(directories.output, "local", "store"),
168839
- configFile: join54(directories.output, "local", "config.json"),
169215
+ storeRoot: join55(directories.output, "local", "store"),
169216
+ configFile: join55(directories.output, "local", "config.json"),
168840
169217
  getEmails: () => props.pool.peek("shim:ses-email")?.server.list() ?? [],
168841
169218
  configPulled: Object.keys(props.pool.peek("config:pull") ?? {}),
168842
169219
  auth: createAuthAdmin({
@@ -168871,7 +169248,7 @@ var startDev = async (props) => {
168871
169248
  dashboardPort,
168872
169249
  routerPorts,
168873
169250
  async stop() {
168874
- await rm12(join54(directories.output, "local", "env.json"), { force: true });
169251
+ await rm12(join55(directories.output, "local", "env.json"), { force: true });
168875
169252
  clearTimeout(rebuildTimer);
168876
169253
  await watcher.close();
168877
169254
  await restartWatcher?.close();
@@ -168936,7 +169313,7 @@ var createServerPool = () => {
168936
169313
 
168937
169314
  // src/type-gen/generate.ts
168938
169315
  import { mkdir as mkdir11, writeFile as writeFile15 } from "fs/promises";
168939
- import { dirname as dirname23, join as join55, relative as relative11 } from "path";
169316
+ import { dirname as dirname24, join as join56, relative as relative11 } from "path";
168940
169317
  var generateTypes = async (props) => {
168941
169318
  const files = [];
168942
169319
  await Promise.all(features.map((feature) => {
@@ -168944,12 +169321,12 @@ var generateTypes = async (props) => {
168944
169321
  ...props,
168945
169322
  async write(file2, data, include = false) {
168946
169323
  const code = data?.toString("utf8");
168947
- const path6 = join55(directories.types, file2);
169324
+ const path6 = join56(directories.types, file2);
168948
169325
  if (code) {
168949
169326
  if (include) {
168950
169327
  files.push(relative11(directories.root, path6));
168951
169328
  }
168952
- await mkdir11(dirname23(path6), { recursive: true });
169329
+ await mkdir11(dirname24(path6), { recursive: true });
168953
169330
  await writeFile15(path6, code);
168954
169331
  }
168955
169332
  }
@@ -168958,7 +169335,7 @@ var generateTypes = async (props) => {
168958
169335
  if (files.length) {
168959
169336
  const code = files.map((file2) => `/// <reference path='${file2}' />`).join(`
168960
169337
  `);
168961
- await writeFile15(join55(directories.root, `awsless.d.ts`), code);
169338
+ await writeFile15(join56(directories.root, `awsless.d.ts`), code);
168962
169339
  }
168963
169340
  };
168964
169341
 
@@ -184588,12 +184965,12 @@ var state = (program3) => {
184588
184965
 
184589
184966
  // src/cli/command/test.ts
184590
184967
  import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
184591
- import { join as join57 } from "path";
184968
+ import { join as join58 } from "path";
184592
184969
 
184593
184970
  // src/test/manifest.ts
184594
- import { isAbsolute as isAbsolute5, join as join56 } from "path";
184971
+ import { isAbsolute as isAbsolute5, join as join57 } from "path";
184595
184972
  var absolute = (file2) => {
184596
- return isAbsolute5(file2) ? file2 : join56(directories.root, file2);
184973
+ return isAbsolute5(file2) ? file2 : join57(directories.root, file2);
184597
184974
  };
184598
184975
  var createTestManifest = (appConfig, stackConfigs) => {
184599
184976
  const manifest = {
@@ -184689,7 +185066,7 @@ var test2 = (program3) => {
184689
185066
  return "No tests found.";
184690
185067
  }
184691
185068
  const manifest = createTestManifest(props.appConfig, props.stackConfigs);
184692
- const manifestFile = join57(directories.output, "test", "manifest.json");
185069
+ const manifestFile = join58(directories.output, "test", "manifest.json");
184693
185070
  let redis;
184694
185071
  let killSearch;
184695
185072
  manifest.servers = {};
@@ -184713,7 +185090,7 @@ var test2 = (program3) => {
184713
185090
  await redis.ping();
184714
185091
  manifest.servers.redis = { host: "127.0.0.1", port: await redis.getPort() };
184715
185092
  }
184716
- await mkdir12(join57(directories.output, "test"), { recursive: true });
185093
+ await mkdir12(join58(directories.output, "test"), { recursive: true });
184717
185094
  await writeFile16(manifestFile, JSON.stringify(manifest));
184718
185095
  process.env.AWSLESS_TEST_MANIFEST = manifestFile;
184719
185096
  let passed = false;