@ferricstore/ferricstore 0.13.3 → 0.13.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,7 +34,7 @@ covers every public adapter class and option.
34
34
 
35
35
  ## Compatibility
36
36
 
37
- TypeScript SDK `0.13.3` requires FerricStore server `0.11.4` or newer. With
37
+ TypeScript SDK `0.13.5` requires FerricStore server `0.11.4` or newer. With
38
38
  FerricStore 0.11.11 it negotiates compact Stream mode 34 for homogeneous auto-ID
39
39
  `XADD` pipelines and compact Pub/Sub mode 35 for homogeneous `PUBLISH`
40
40
  pipelines. Native wire protocol v1 and the generic fallback are unchanged.
@@ -62,7 +62,7 @@ const { FerricStoreClient, JsonCodec } = require("@ferricstore/ferricstore");
62
62
  docker run -p 6388:6388 \
63
63
  -e FERRICSTORE_PROTECTED_MODE=false \
64
64
  -v ferricstore_data:/data \
65
- quay.io/ferricstore/ferricstore:0.11.19@sha256:6275175c71a75f2d2a47c30c47a6561f994d8a5e31570fc8bd11a9f6ebcb6b31
65
+ quay.io/ferricstore/ferricstore:0.11.21@sha256:d297c91414ecf206671685d6e74efcec715e5f14a96c5cef09ac5d8c4664c74b
66
66
  ```
67
67
 
68
68
  ## Query durable runs
@@ -152,7 +152,7 @@ Run the complete HTTP-compatible integration surface through a real TLS
152
152
  listener with ACL authentication using:
153
153
 
154
154
  ```bash
155
- FERRICSTORE_IMAGE=quay.io/ferricstore/ferricstore:0.11.19@sha256:6275175c71a75f2d2a47c30c47a6561f994d8a5e31570fc8bd11a9f6ebcb6b31 \
155
+ FERRICSTORE_IMAGE=quay.io/ferricstore/ferricstore:0.11.21@sha256:d297c91414ecf206671685d6e74efcec715e5f14a96c5cef09ac5d8c4664c74b \
156
156
  npm run test:integration:http
157
157
  ```
158
158
 
@@ -449,10 +449,19 @@ worker-mode default. If an asynchronous completion fails after earlier writes
449
449
  succeed, `QueueCompletionError.completed` reports every successful completion
450
450
  drained by the same call, regardless of where the failed completion appeared.
451
451
 
452
- When a worker combines `blockMs` with an `AbortSignal`, native long polls are
453
- bounded by `abortPollMs` (default `1_000`) so shutdown is observed without
454
- abandoning an in-flight claim that may already have leased work. Finite server
455
- blocking time is added to the transport timeout rather than consuming it.
452
+ Worker `blockMs` values must be safe non-negative integers from `0` through
453
+ `4_294_967_295`; invalid values fail before a blocking claim is dispatched. When
454
+ a worker combines `blockMs` with an `AbortSignal`, native long polls are bounded
455
+ by `abortPollMs` (default `1_000`) so shutdown is observed without abandoning an
456
+ in-flight claim that may already have leased work. Finite server blocking time
457
+ is added to the transport timeout rather than consuming it. Raw
458
+ `FLOW.CLAIM_DUE` `BLOCK` and `BLOCK_MS` arguments use the same validation before
459
+ native or HTTP preparation.
460
+ For malformed raw commands, recognized option/value pairs are skipped before an
461
+ unsupported tail is scanned for `BLOCK`/`BLOCK_MS`; every subsequent marker is
462
+ treated as an option and its successor is validated. This intentionally fails
463
+ closed when arbitrary malformed tail data happens to equal `BLOCK`. Explicit
464
+ `COMMAND_EXEC` wrappers and custom executors remain opaque escape hatches.
456
465
 
457
466
  Unpartitioned `enqueueMany` calls group items in linear time, preserve caller
458
467
  result order, keep chunks for the same auto-partition sequential, and dispatch
package/dist/index.cjs CHANGED
@@ -3986,6 +3986,78 @@ function expandFlowClaimStates(args) {
3986
3986
  return expanded;
3987
3987
  }
3988
3988
 
3989
+ // src/flow-block-validation.ts
3990
+ var MAX_FLOW_BLOCK_MS = 4294967295;
3991
+ var FLOW_BLOCK_MS_ERROR = "blockMs must be a safe non-negative integer no greater than 4294967295";
3992
+ function validateFlowBlockMs(value) {
3993
+ if (value != null && (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > MAX_FLOW_BLOCK_MS)) {
3994
+ throw new TypeError(FLOW_BLOCK_MS_ERROR);
3995
+ }
3996
+ }
3997
+ function validateRawFlowBlockMs(value) {
3998
+ let parsed;
3999
+ try {
4000
+ parsed = integerArg(value);
4001
+ } catch {
4002
+ throw new TypeError(FLOW_BLOCK_MS_ERROR);
4003
+ }
4004
+ validateFlowBlockMs(parsed);
4005
+ }
4006
+ function validateRawFlowClaimBlockOptions(args) {
4007
+ for (let index = 1; index < args.length; ) {
4008
+ const token = asText(args[index]).toUpperCase();
4009
+ switch (token) {
4010
+ case "BLOCK":
4011
+ case "BLOCK_MS":
4012
+ validateRawFlowBlockMs(args[index + 1]);
4013
+ index += 2;
4014
+ break;
4015
+ case "STATE":
4016
+ case "PARTITION":
4017
+ case "WORKER":
4018
+ case "LEASE_MS":
4019
+ case "LIMIT":
4020
+ case "PRIORITY":
4021
+ case "NOW":
4022
+ case "RECLAIM_RATIO":
4023
+ case "RETURN":
4024
+ case "MAXBYTES":
4025
+ case "VALUE":
4026
+ case "VALUE_MAX_BYTES":
4027
+ index += 2;
4028
+ break;
4029
+ case "STATES":
4030
+ case "PARTITIONS": {
4031
+ const count = Number(args[index + 1]);
4032
+ const valuesStart = index + 2;
4033
+ if (!Number.isSafeInteger(count) || count < 0 || count > args.length - valuesStart) {
4034
+ validateRawFlowClaimBlockFallback(args, valuesStart);
4035
+ return;
4036
+ }
4037
+ index = valuesStart + count;
4038
+ break;
4039
+ }
4040
+ case "RECLAIM_EXPIRED":
4041
+ case "INCLUDE_STATE":
4042
+ index += index + 1 < args.length && isBoolToken(args[index + 1]) ? 2 : 1;
4043
+ break;
4044
+ case "PAYLOAD":
4045
+ case "NOPAYLOAD":
4046
+ index += 1;
4047
+ break;
4048
+ default:
4049
+ validateRawFlowClaimBlockFallback(args, index);
4050
+ return;
4051
+ }
4052
+ }
4053
+ }
4054
+ function validateRawFlowClaimBlockFallback(args, start) {
4055
+ for (let index = start; index < args.length; index += 1) {
4056
+ const token = asText(args[index]).toUpperCase();
4057
+ if (token === "BLOCK" || token === "BLOCK_MS") validateRawFlowBlockMs(args[index + 1]);
4058
+ }
4059
+ }
4060
+
3989
4061
  // src/protocol-flow.ts
3990
4062
  function flowCreatePayload(args) {
3991
4063
  if (args.length < 7) return void 0;
@@ -4113,6 +4185,7 @@ function flowCreateManyPayload(args, maxBodyBytes, allowCompact) {
4113
4185
  }
4114
4186
  function flowClaimDuePayload(args, maxBodyBytes, allowCompact) {
4115
4187
  if (args.length < 1) return void 0;
4188
+ validateRawFlowClaimBlockOptions(args);
4116
4189
  const options = parseFlowOptions(args, 1, args.length, {
4117
4190
  allowed: /* @__PURE__ */ new Set([
4118
4191
  "STATE",
@@ -4139,6 +4212,7 @@ function flowClaimDuePayload(args, maxBodyBytes, allowCompact) {
4139
4212
  readValues: true
4140
4213
  });
4141
4214
  if (options == null) return void 0;
4215
+ validateFlowBlockMs(options.block_ms);
4142
4216
  const returnMode = options.return == null ? "" : asText(options.return).toUpperCase();
4143
4217
  if (!returnMode.startsWith("JOBS_COMPACT")) {
4144
4218
  const fallback = Array.isArray(options.states) ? commandExec(["FLOW.CLAIM_DUE", ...expandFlowClaimStates(args)]) : commandExec(["FLOW.CLAIM_DUE", ...args]);
@@ -18653,6 +18727,7 @@ var FerricStoreClaimClient = class extends FerricStoreMutationClient {
18653
18727
  }
18654
18728
  claimDueRequest(type, options, reusableAfterAwait = false) {
18655
18729
  const captured = snapshotClaimOptions(options, reusableAfterAwait);
18730
+ validateFlowBlockMs(captured.blockMs);
18656
18731
  if (captured.state != null && captured.states != null) {
18657
18732
  throw new Error("state and states are mutually exclusive");
18658
18733
  }
@@ -20085,11 +20160,11 @@ function workerClaimBlockMs(options, useBlocking) {
20085
20160
  if (!useBlocking || options.blockMs == null) {
20086
20161
  return void 0;
20087
20162
  }
20088
- if (options.signal == null || !Number.isFinite(options.blockMs) || options.blockMs < 0) {
20089
- return options.blockMs;
20090
- }
20091
- const abortPollMs = positiveInteger5(options.abortPollMs, 1e3);
20092
- return options.blockMs === 0 ? abortPollMs : Math.min(Math.trunc(options.blockMs), abortPollMs);
20163
+ validateFlowBlockMs(options.blockMs);
20164
+ const blockMs = options.blockMs;
20165
+ if (options.signal == null) return blockMs;
20166
+ const abortPollMs = Math.min(positiveInteger5(options.abortPollMs, 1e3), MAX_FLOW_BLOCK_MS);
20167
+ return blockMs === 0 ? abortPollMs : Math.min(blockMs, abortPollMs);
20093
20168
  }
20094
20169
  function workerMaxIdleSleepMs(options, idleSleepMs = workerIdleSleepMs(options)) {
20095
20170
  return Math.max(idleSleepMs, nonNegativeDuration(options.maxIdleSleepMs, 5e3));
@@ -21988,7 +22063,7 @@ function throwError(value) {
21988
22063
  }
21989
22064
 
21990
22065
  // src/version.ts
21991
- var FERRICSTORE_SDK_VERSION = "0.13.3";
22066
+ var FERRICSTORE_SDK_VERSION = "0.13.5";
21992
22067
  var FERRICSTORE_MINIMUM_SERVER_VERSION = "0.11.4";
21993
22068
  var FERRICSTORE_NATIVE_PROTOCOL_VERSION = 1;
21994
22069
  // Annotate the CommonJS export names for ESM import in node: