@crvouga/mockingbird-service-sqs 3.7.0 → 3.9.0

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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,19 @@
1
1
  # Changelog — @crvouga/mockingbird-service-sqs
2
2
 
3
- ## 3.7.0 (2026-10-19)
3
+ ## 3.9.0 (2026-10-21)
4
+
5
+ ### Features
6
+
7
+ - add manual response controls ([4599960](https://github.com/crvouga/mockingbird/commit/45999603e8b860c633181367afc7baa906ba486b))
8
+
9
+ ## 3.8.0 (2026-10-20)
10
+
11
+ ### Features
12
+
13
+ - raise the serve and fleet body limit to the S3 maximum ([86b9e2b](https://github.com/crvouga/mockingbird/commit/86b9e2b80bcaaaef57f52edbac50b27da0b42f33))
14
+ - long polling, unknown-operation errors and batch/list/delete operation coverage ([2743ce1](https://github.com/crvouga/mockingbird/commit/2743ce1b97ab0c389ad950fb0848558d87711cb8))
15
+
16
+ ## 3.7.0 (2026-10-18)
4
17
 
5
18
  ### Features
6
19
 
package/README.md CHANGED
@@ -44,7 +44,29 @@ console.log(Messages?.[0]?.Body) // {"job":"resize"}
44
44
  await server.close()
45
45
  ```
46
46
 
47
- Supported operations are CreateQueue, GetQueueUrl, GetQueueAttributes, SendMessage, SendMessageBatch, ReceiveMessage, DeleteMessage, ChangeMessageVisibility, and PurgeQueue. Receive honors maximum messages, visibility timeout, system attribute selection, and message attribute selection. The injected shared clock controls visibility expiry and redrive without sleeps.
47
+ Supported operations are CreateQueue, ListQueues, GetQueueUrl, DeleteQueue, SetQueueAttributes, GetQueueAttributes, TagQueue, UntagQueue, ListQueueTags, ListDeadLetterSourceQueues, SendMessage, SendMessageBatch, ReceiveMessage, DeleteMessage, DeleteMessageBatch, ChangeMessageVisibility, ChangeMessageVisibilityBatch, and PurgeQueue. Receive honors maximum messages, visibility timeout, wait time, system attribute selection, and message attribute selection. The injected shared clock controls visibility expiry and redrive without sleeps.
48
+
49
+ Batches answer per entry: `DeleteMessageBatch` and `ChangeMessageVisibilityBatch` list each entry in `Successful` or `Failed` (a stale handle fails as `ReceiptHandleIsInvalid` and the rest still succeed). `ListQueues` filters by `QueueNamePrefix` and pages with `MaxResults` and `NextToken`. `DeleteQueue` drops the queue and its messages. `SetQueueAttributes` validates and replaces the given attributes, and later receives use them.
50
+
51
+ ### Long polling
52
+
53
+ An empty `ReceiveMessage` is held for `WaitTimeSeconds` (0 to 20), or the queue's `ReceiveMessageWaitTimeSeconds` when the call omits it; `WaitTimeSeconds: 0` never waits. The wait is measured on the emulator clock, so it stays deterministic:
54
+
55
+ - A message sent during the wait (`SendMessage`, a batch, `POST /__admin/messages`) or made visible (`ChangeMessageVisibility` to 0, an expiring delay or visibility timeout) releases the held request, which answers with it and `ApproximateReceiveCount` 1.
56
+ - On a live clock (a served stack) the wait is real. On a frozen clock it lasts until a test advances the clock by the wait time (`clock.advance(3000)` or `POST /__admin/clock`), then answers with no `Messages`.
57
+ - With virtual time on (`virtualTime: true`, see Admin controls) the wait is spent on the namespace clock at once, without sleeping.
58
+ - A client that disconnects while held stops the wait before anything is received for it, so no message is left hidden. A queue deleted during the wait answers `AWS.SimpleQueueService.NonExistentQueue`.
59
+ - `createServer({ longPoll: false })` (or `createRuntime`) keeps the old instant answer for suites that rely on it.
60
+
61
+ A held request polls the clock every 25 ms of real time while it waits, so an idle consumer costs little but is not free.
62
+
63
+ Evidence: [short and long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) and the [ReceiveMessage reference](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html), implemented from the documentation (not observed against live SQS). `WaitTimeSeconds` above 20 is `InvalidParameterValue`, as documented.
64
+
65
+ ### Unknown operations
66
+
67
+ An `X-Amz-Target` the emulator does not answer is refused before any queue is looked up, as `400 UnknownOperationException` (`{"__type":"UnknownOperationException","message":"Unknown operation Nope"}`), never as a missing queue. The SQS operations that exist but are not modelled (`AddPermission`, `RemovePermission`, `StartMessageMoveTask`, `CancelMessageMoveTask`, `ListMessageMoveTasks`) get the same type with the message `<Operation> is an Amazon SQS operation this emulator does not implement.`, so a missing operation is told apart from a missing queue.
68
+
69
+ Best guess, not oracle-verified: the [AWS JSON 1.0 protocol](https://smithy.io/2.0/aws/protocols/aws-json-1_0-protocol.html) reports an unrecognized operation as a 400 whose `__type` names the failure, and this emulator uses the `UnknownOperationException` name the other AWS emulators in this repo use. The exact `__type` live SQS sends (it may be a `com.amazon.coral.service#UnknownOperationException` form) was not observed; SDK clients strip the namespace before the `#`, so they see the same error name.
48
70
 
49
71
  ### Admin and deterministic controls
50
72
 
@@ -57,7 +79,7 @@ The shared runtime supplies reset, clock, journal, timeline, metrics, faults, an
57
79
 
58
80
  ### Deliberately not modelled
59
81
 
60
- Operations outside the surface listed above, IAM policy evaluation, server-side encryption, queue tagging, production throughput and size limits beyond the 1 MiB message limit, real long-poll wall-clock waits, AWS dashboards, and billing are not modelled.
82
+ Operations outside the surface listed above (queue permissions and message move tasks answer `UnknownOperationException`), IAM policy evaluation, server-side encryption, production throughput and size limits beyond the 1 MiB message limit, AWS dashboards, and billing are not modelled. Queue-missing errors use the legacy `AWS.SimpleQueueService.NonExistentQueue` code, not the `QueueDoesNotExist` name newer SDKs map it to; `GetQueueUrl` for a deleted queue fails with it.
61
83
 
62
84
  ## API
63
85
 
@@ -9,7 +9,7 @@ import {
9
9
  parseFaultHeader,
10
10
  resolveAdminPrefix,
11
11
  restoreClock
12
- } from "./chunk-DPNMBVYR.js";
12
+ } from "./chunk-GWRTPEQW.js";
13
13
 
14
14
  // ../../adapters/node/dist/cli.js
15
15
  import { readFile as readFile5 } from "node:fs/promises";
@@ -3057,7 +3057,7 @@ async function preflightFleet(config, options) {
3057
3057
  break;
3058
3058
  }
3059
3059
  }
3060
- targets.set(name, { ...target, packageVersion: packageVersion ?? "3.7.0" });
3060
+ targets.set(name, { ...target, packageVersion: packageVersion ?? "3.9.0" });
3061
3061
  } catch (error) {
3062
3062
  throw new Error(`service ${name}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
3063
3063
  }
@@ -3283,7 +3283,11 @@ var serve = async (api, options = {}) => {
3283
3283
  // ../../adapters/node/dist/listen.js
3284
3284
  var listen = async (api, options = {}) => {
3285
3285
  const host = options.host ?? "127.0.0.1";
3286
- const server = await serve(api, { port: options.port ?? 0, host });
3286
+ const server = await serve(api, {
3287
+ port: options.port ?? 0,
3288
+ host,
3289
+ ...options.maxBodyBytes !== void 0 ? { maxBodyBytes: options.maxBodyBytes } : {}
3290
+ });
3287
3291
  const address = server.address();
3288
3292
  const port = typeof address === "object" && address !== null ? address.port : options.port ?? 0;
3289
3293
  const shown = host.includes(":") ? `[${host}]` : host;
@@ -3482,7 +3486,8 @@ var httpChild = async (target, entry, options, admission, generation, privateAcc
3482
3486
  try {
3483
3487
  server = await listen(api, {
3484
3488
  port: entry.port ?? target.defaultPort,
3485
- host: entry.host ?? "127.0.0.1"
3489
+ host: entry.host ?? "127.0.0.1",
3490
+ ...target.maxBodyBytes !== void 0 ? { maxBodyBytes: target.maxBodyBytes } : {}
3486
3491
  });
3487
3492
  target.listening?.(server);
3488
3493
  } catch (error) {
@@ -4873,7 +4878,11 @@ var start = async (target, values, config) => {
4873
4878
  });
4874
4879
  if (config.idBase !== void 0)
4875
4880
  runtime.setIdBase?.(config.idBase);
4876
- const listening = await listen(runtime, { port: config.port, host: config.host });
4881
+ const listening = await listen(runtime, {
4882
+ port: config.port,
4883
+ host: config.host,
4884
+ ...target.maxBodyBytes !== void 0 ? { maxBodyBytes: target.maxBodyBytes } : {}
4885
+ });
4877
4886
  target.listening?.(listening);
4878
4887
  console.log(`${target.name} emulator listening on ${listening.url}`);
4879
4888
  console.log(`${target.name} health: GET ${listening.url}${adminPrefix}/health`);
@@ -5003,4 +5012,4 @@ export {
5003
5012
  createServer2 as createServer,
5004
5013
  serveTarget
5005
5014
  };
5006
- //# sourceMappingURL=chunk-WATYUP5R.js.map
5015
+ //# sourceMappingURL=chunk-GMJLAKCG.js.map