@requence/service 0.8.1 → 0.8.2-edge.1149

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 (33) hide show
  1. package/build/chunk-974rc2jy.js +200 -0
  2. package/build/chunk-974rc2jy.js.map +12 -0
  3. package/build/cli.js +1 -1
  4. package/build/index.js +184 -35
  5. package/build/index.js.map +8 -7
  6. package/build/types/helpers/src/protocol/NodeTree.d.ts +82 -4
  7. package/build/types/helpers/src/protocol/NodeTree.d.ts.map +1 -1
  8. package/build/types/helpers/src/protocol/clientProperties.d.ts +66 -0
  9. package/build/types/helpers/src/protocol/clientProperties.d.ts.map +1 -0
  10. package/build/types/helpers/src/protocol/command.d.ts +8 -0
  11. package/build/types/helpers/src/protocol/command.d.ts.map +1 -1
  12. package/build/types/helpers/src/protocol/index.d.ts +1 -0
  13. package/build/types/helpers/src/protocol/index.d.ts.map +1 -1
  14. package/build/types/helpers/src/protocol/nodeType.d.ts +8 -0
  15. package/build/types/helpers/src/protocol/nodeType.d.ts.map +1 -1
  16. package/build/types/helpers/src/protocol/templateNodeTypes.d.ts.map +1 -1
  17. package/build/types/helpers/src/protocol/treeNodes.d.ts +32 -0
  18. package/build/types/helpers/src/protocol/treeNodes.d.ts.map +1 -1
  19. package/build/types/helpers/src/protocol/update.d.ts +18 -2
  20. package/build/types/helpers/src/protocol/update.d.ts.map +1 -1
  21. package/build/types/helpers/src/utils/amqpPublishRetry.d.ts +40 -0
  22. package/build/types/helpers/src/utils/amqpPublishRetry.d.ts.map +1 -1
  23. package/build/types/service/src/boundary.d.ts +12 -0
  24. package/build/types/service/src/boundary.d.ts.map +1 -1
  25. package/build/types/service/src/createAmqpConnection.d.ts +9 -1
  26. package/build/types/service/src/createAmqpConnection.d.ts.map +1 -1
  27. package/build/types/service/src/errors.d.ts +14 -0
  28. package/build/types/service/src/errors.d.ts.map +1 -1
  29. package/build/types/service/src/index.d.ts +18 -2
  30. package/build/types/service/src/index.d.ts.map +1 -1
  31. package/package.json +2 -1
  32. package/build/chunk-8r349zge.js +0 -99
  33. package/build/chunk-8r349zge.js.map +0 -11
package/build/index.js CHANGED
@@ -1,13 +1,19 @@
1
1
  import {
2
+ CAPABILITY_HEADER_KEYS,
2
3
  PayloadTooLargeError,
3
4
  RequenceConnectionError,
4
5
  RequenceUnreachableError,
6
+ UnsupportedCapabilityError,
5
7
  assertReachable,
8
+ buildServiceClientProperties,
9
+ buildServiceIdentityHeaders,
6
10
  deobfuscate,
7
11
  isUnreachableStatus,
8
12
  obfuscate,
9
- reachableFetch
10
- } from "./chunk-8r349zge.js";
13
+ reachableFetch,
14
+ readRequiredCapabilities,
15
+ unsupportedCapabilities
16
+ } from "./chunk-974rc2jy.js";
11
17
 
12
18
  // src/index.ts
13
19
  import fs from "node:fs";
@@ -185,6 +191,70 @@ function createCallback(callback) {
185
191
  // ../helpers/src/utils/amqpHeartbeat.ts
186
192
  var DEFAULT_AMQP_HEARTBEAT_SECONDS = 30;
187
193
 
194
+ // ../helpers/src/msgpack/index.ts
195
+ import { Buffer as Buffer2 } from "node:buffer";
196
+ import { Packr, addExtension } from "msgpackr";
197
+ var MSGPACK_EXTENSION_IDS = {
198
+ referenceCounter: 1,
199
+ nodeTree: 2,
200
+ url: 3
201
+ };
202
+ var packingForWire = false;
203
+ addExtension({
204
+ Class: URL,
205
+ get type() {
206
+ return packingForWire ? undefined : MSGPACK_EXTENSION_IDS.url;
207
+ },
208
+ write: (v) => v.href,
209
+ read: (href) => new URL(href)
210
+ });
211
+ var packr = new Packr({ structuredClone: true });
212
+ var wirePackr = new Packr({
213
+ useRecords: false,
214
+ structuredClone: false,
215
+ encodeUndefinedAsNil: true,
216
+ mapAsEmptyObject: true,
217
+ setAsEmptyObject: true,
218
+ int64AsType: "number"
219
+ });
220
+ function packWire(value) {
221
+ packingForWire = true;
222
+ try {
223
+ return wirePackr.pack(value);
224
+ } finally {
225
+ packingForWire = false;
226
+ }
227
+ }
228
+ function unpackWire(buffer) {
229
+ return wirePackr.unpack(buffer);
230
+ }
231
+ function wireByteLength(value) {
232
+ return wirePackr.pack(value).length;
233
+ }
234
+ var WIRE_CONTENT_TYPES = {
235
+ json: "application/json",
236
+ msgpack: "application/msgpack"
237
+ };
238
+ function wireCodecFromContentType(contentType) {
239
+ return contentType === WIRE_CONTENT_TYPES.msgpack ? "msgpack" : "json";
240
+ }
241
+ function encodeWireBody(value, codec) {
242
+ return {
243
+ body: codec === "msgpack" ? packWire(value) : Buffer2.from(JSON.stringify(value ?? null)),
244
+ contentType: WIRE_CONTENT_TYPES[codec]
245
+ };
246
+ }
247
+ function decodeWireBody(content, contentType) {
248
+ return wireCodecFromContentType(contentType) === "msgpack" ? unpackWire(content) : JSON.parse(Buffer2.from(content).toString());
249
+ }
250
+ function wireBodyByteLength(value, codec) {
251
+ if (codec === "msgpack") {
252
+ return wireByteLength(value);
253
+ }
254
+ const json = JSON.stringify(value);
255
+ return json === undefined ? 0 : Buffer2.byteLength(json);
256
+ }
257
+
188
258
  // src/createAmqpConnection.ts
189
259
  import { connect } from "amqp-connection-manager";
190
260
  import { z as z6 } from "zod/v4";
@@ -697,7 +767,7 @@ function createRequenceStreamHandler() {
697
767
  };
698
768
  }
699
769
  // ../files/src/handlers/claimCheckHandler.ts
700
- import { Buffer as Buffer2 } from "node:buffer";
770
+ import { Buffer as Buffer3 } from "node:buffer";
701
771
  var DEFAULT_MAX_PAYLOAD_SIZE = 4 * 1024 * 1024;
702
772
  function isRecord2(value) {
703
773
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -716,6 +786,10 @@ async function offload(ctx, uploadUrl, json) {
716
786
  }
717
787
  return toClaimCheckObject({ url: data.url, size: data.size });
718
788
  }
789
+ function jsonByteLength(value) {
790
+ const json = JSON.stringify(value);
791
+ return json === undefined ? 0 : Buffer3.byteLength(json);
792
+ }
719
793
  function createMessageHandler() {
720
794
  return {
721
795
  async wrapOutbound(body, ctx) {
@@ -723,8 +797,8 @@ function createMessageHandler() {
723
797
  if (maxBytes <= 0 || body === undefined) {
724
798
  return body;
725
799
  }
726
- const json = JSON.stringify(body);
727
- if (json === undefined || Buffer2.byteLength(json) <= maxBytes) {
800
+ const measure = ctx.measure ?? jsonByteLength;
801
+ if (measure(body) <= maxBytes) {
728
802
  return body;
729
803
  }
730
804
  const { uploadUrl } = ctx;
@@ -733,25 +807,26 @@ function createMessageHandler() {
733
807
  return body;
734
808
  }
735
809
  if (!isRecord2(body)) {
810
+ const json = JSON.stringify(body);
811
+ if (json === undefined) {
812
+ return body;
813
+ }
736
814
  return offload(ctx, uploadUrl, json);
737
815
  }
738
- const entries = Object.entries(body).map(([key, value]) => {
739
- const valueJson = JSON.stringify(value);
740
- return {
741
- key,
742
- valueJson,
743
- size: valueJson === undefined ? 0 : Buffer2.byteLength(valueJson)
744
- };
745
- }).sort((a, b) => b.size - a.size);
816
+ const entries = Object.entries(body).map(([key, value]) => ({
817
+ key,
818
+ valueJson: JSON.stringify(value),
819
+ size: measure(value)
820
+ })).sort((a, b) => b.size - a.size);
746
821
  const wrapped = { ...body };
747
- let total = Buffer2.byteLength(json);
822
+ let total = measure(body);
748
823
  for (const entry of entries) {
749
824
  if (total <= maxBytes || entry.valueJson === undefined || entry.size <= 256) {
750
825
  break;
751
826
  }
752
827
  const ref = await offload(ctx, uploadUrl, entry.valueJson);
753
828
  wrapped[entry.key] = ref;
754
- total += Buffer2.byteLength(JSON.stringify(ref)) - entry.size;
829
+ total += measure(ref) - entry.size;
755
830
  }
756
831
  return wrapped;
757
832
  }
@@ -1015,6 +1090,8 @@ function createOutboundBoundary(base) {
1015
1090
  const warn = base.warn ?? ((message, error) => error === undefined ? console.warn(message) : console.warn(message, error));
1016
1091
  const ledger = [];
1017
1092
  const errors = [];
1093
+ const codec = base.wireCodec ?? "json";
1094
+ const measure = (value) => wireBodyByteLength(value, codec);
1018
1095
  const track = (promise) => {
1019
1096
  ledger.push(promise.then(() => {}, (error) => {
1020
1097
  errors.push(error instanceof Error ? error : new Error(String(error)));
@@ -1030,6 +1107,7 @@ function createOutboundBoundary(base) {
1030
1107
  streamUrl: base.streamUrl,
1031
1108
  maxPayloadSize: base.maxPayloadSize,
1032
1109
  maxFileSize: base.maxFileSize,
1110
+ measure,
1033
1111
  outputName: opts.outputName ?? null,
1034
1112
  onCallback: opts.onCallback,
1035
1113
  ...opts.bestEffort ? {
@@ -1186,7 +1264,10 @@ var headerSchema = z6.object({
1186
1264
  taskId: msg.properties.headers.taskId,
1187
1265
  mode: msg.properties.headers.mode
1188
1266
  }));
1189
- var payloadSchema = z6.object({ content: z6.instanceof(Buffer) }).transform((msg) => JSON.parse(msg.content.toString())).pipe(z6.object({
1267
+ var payloadSchema = z6.object({
1268
+ content: z6.instanceof(Buffer),
1269
+ properties: z6.object({ contentType: z6.string().optional() })
1270
+ }).transform((msg) => decodeWireBody(msg.content, msg.properties.contentType)).pipe(z6.object({
1190
1271
  input: z6.unknown(),
1191
1272
  configuration: z6.unknown(),
1192
1273
  options: z6.object({
@@ -1197,7 +1278,16 @@ var payloadSchema = z6.object({ content: z6.instanceof(Buffer) }).transform((msg
1197
1278
  })
1198
1279
  }));
1199
1280
  var backchannelMessageSchema = z6.object({
1200
- content: z6.instanceof(Buffer).transform((content) => JSON.parse(content.toString())).pipe(z6.discriminatedUnion("type", [
1281
+ content: z6.instanceof(Buffer),
1282
+ properties: z6.object({
1283
+ correlationId: z6.string(),
1284
+ contentType: z6.string().optional()
1285
+ })
1286
+ }).transform((message) => ({
1287
+ ...message,
1288
+ content: decodeWireBody(message.content, message.properties.contentType)
1289
+ })).pipe(z6.object({
1290
+ content: z6.discriminatedUnion("type", [
1201
1291
  z6.object({
1202
1292
  type: z6.literal("stop")
1203
1293
  }),
@@ -1206,11 +1296,11 @@ var backchannelMessageSchema = z6.object({
1206
1296
  callbackId: z6.uuid(),
1207
1297
  arg: z6.any()
1208
1298
  })
1209
- ])),
1299
+ ]),
1210
1300
  properties: z6.object({
1211
1301
  correlationId: z6.string()
1212
1302
  })
1213
- }).transform((message) => ({
1303
+ })).transform((message) => ({
1214
1304
  payload: message.content,
1215
1305
  messageId: message.properties.correlationId
1216
1306
  }));
@@ -1221,6 +1311,7 @@ var connectionOptionsSchema = z6.object({
1221
1311
  z6.instanceof(URL).refine((url) => url.protocol.match(/^amqps?:/), "Wrong protocol")
1222
1312
  ]),
1223
1313
  version: z6.string(),
1314
+ name: z6.string().optional(),
1224
1315
  devOverlay: z6.string().optional(),
1225
1316
  silent: z6.boolean().optional(),
1226
1317
  prefetch: z6.number().int().optional(),
@@ -1234,6 +1325,7 @@ function isMessageHandlerGenerator(handler) {
1234
1325
  return handler.constructor.name === "GeneratorFunction" || handler.constructor.name === "AsyncGeneratorFunction";
1235
1326
  }
1236
1327
  var activeMessages = new Map;
1328
+ var messageCodecs = new Map;
1237
1329
  function isChannelClosedError(error) {
1238
1330
  return error instanceof Error && error.name === "IllegalOperationError";
1239
1331
  }
@@ -1263,8 +1355,10 @@ function createConnection({
1263
1355
  connectionTimeout,
1264
1356
  heartbeatInterval = DEFAULT_AMQP_HEARTBEAT_SECONDS,
1265
1357
  connectionOptions,
1358
+ name,
1266
1359
  devOverlay = "",
1267
1360
  maxMessageSize,
1361
+ onConnectionStateChange,
1268
1362
  ...rest
1269
1363
  }, messageHandler) {
1270
1364
  const passthroughByteReferences = rest.passthroughByteReferences ?? false;
@@ -1272,13 +1366,33 @@ function createConnection({
1272
1366
  const queue = devOverlay ? `${baseQueue}-dev-overlay-${devOverlay}` : baseQueue;
1273
1367
  const exchange = url.username;
1274
1368
  const connection = connect(url.toString(), {
1275
- connectionOptions,
1369
+ connectionOptions: {
1370
+ ...connectionOptions,
1371
+ clientProperties: {
1372
+ ...connectionOptions?.clientProperties,
1373
+ ...buildServiceClientProperties({
1374
+ libVersion: "javascript@0.8.2-edge.1149",
1375
+ serviceVersion: version,
1376
+ name,
1377
+ devOverlay: Boolean(devOverlay)
1378
+ })
1379
+ }
1380
+ },
1276
1381
  heartbeatIntervalInSeconds: heartbeatInterval
1277
1382
  });
1278
1383
  connection.on("disconnect", ({ err }) => {
1279
1384
  if (!silent && err) {
1280
1385
  console.error("Requence AMQP connection lost:", err.message);
1281
1386
  }
1387
+ onConnectionStateChange?.({ connected: false, err });
1388
+ });
1389
+ let hasConnected = false;
1390
+ connection.on("connect", () => {
1391
+ if (hasConnected && !silent) {
1392
+ console.info("Requence AMQP reconnected");
1393
+ }
1394
+ hasConnected = true;
1395
+ onConnectionStateChange?.({ connected: true });
1282
1396
  });
1283
1397
  const connectedPromise = new Promise((resolve2, reject) => {
1284
1398
  const unsubscribe = () => {
@@ -1371,19 +1485,18 @@ function createConnection({
1371
1485
  priority,
1372
1486
  ...headers
1373
1487
  }) => {
1374
- const body = Buffer.from(JSON.stringify(data ?? null));
1488
+ const { body, contentType } = encodeWireBody(data ?? null, messageCodecs.get(messageId) ?? "json");
1375
1489
  if (body.byteLength > maxMessageSize) {
1376
1490
  return Promise.reject(new PayloadTooLargeError(body.byteLength, maxMessageSize));
1377
1491
  }
1378
1492
  return channelWrapper.publish(exchange, "", body, {
1379
1493
  correlationId: messageId,
1380
- contentType: "application/json",
1494
+ contentType,
1381
1495
  persistent: true,
1382
1496
  priority,
1383
1497
  headers: {
1384
1498
  outputName: outputName ?? null,
1385
1499
  connectionId,
1386
- libVersion: "javascript@0.8.1",
1387
1500
  ...headers
1388
1501
  }
1389
1502
  });
@@ -1454,6 +1567,12 @@ function createConnection({
1454
1567
  try {
1455
1568
  const { messageId, taskId, mode } = headerSchema.parse(message);
1456
1569
  messageIdForCleanup = messageId;
1570
+ const unsupported = unsupportedCapabilities(readRequiredCapabilities(message.properties.headers));
1571
+ if (unsupported.length > 0) {
1572
+ throw new UnsupportedCapabilityError(unsupported);
1573
+ }
1574
+ const dispatchCodec = wireCodecFromContentType(message.properties.contentType);
1575
+ messageCodecs.set(messageId, dispatchCodec);
1457
1576
  let deferred = false;
1458
1577
  let deferredReason = null;
1459
1578
  const messageExecution = Promise.withResolvers();
@@ -1480,6 +1599,7 @@ function createConnection({
1480
1599
  streamUrl: payload.options.streamUrl,
1481
1600
  maxPayloadSize: payload.options.maxPayloadSize,
1482
1601
  maxFileSize: payload.options.maxFileSize,
1602
+ wireCodec: dispatchCodec,
1483
1603
  signal: abortController.signal,
1484
1604
  warn: (msg, error) => console.warn(`${msg} (task ${taskId})`, error instanceof Error ? error.message : error ?? "")
1485
1605
  });
@@ -1557,7 +1677,11 @@ function createConnection({
1557
1677
  taskId,
1558
1678
  priority: message.properties.priority,
1559
1679
  begin: true,
1560
- epoch
1680
+ epoch,
1681
+ ...buildServiceIdentityHeaders({
1682
+ libVersion: "javascript@0.8.2-edge.1149",
1683
+ name
1684
+ })
1561
1685
  });
1562
1686
  if (isMessageHandlerGenerator(messageHandler)) {
1563
1687
  if (mode === "CONTINUOUS") {
@@ -1693,6 +1817,29 @@ function createConnection({
1693
1817
  });
1694
1818
  return;
1695
1819
  }
1820
+ if (error instanceof UnsupportedCapabilityError) {
1821
+ if (!silent) {
1822
+ console.error(error.message);
1823
+ }
1824
+ if (!acked) {
1825
+ safeAck(channel, message);
1826
+ }
1827
+ channelWrapper.publish(`${exchange}-retry`, "operator", message.content, {
1828
+ ...message.properties,
1829
+ headers: {
1830
+ ...message.properties.headers,
1831
+ version,
1832
+ [CAPABILITY_HEADER_KEYS.mismatch]: true,
1833
+ index: publishIndex++,
1834
+ "error-message": error.message
1835
+ }
1836
+ }).catch((publishError) => {
1837
+ if (!silent) {
1838
+ console.error("Failed to publish capability mismatch message:", publishError);
1839
+ }
1840
+ });
1841
+ return;
1842
+ }
1696
1843
  if (error instanceof AbortError && error.message.length > 0) {
1697
1844
  if (!acked) {
1698
1845
  safeAck(channel, message);
@@ -1703,7 +1850,6 @@ function createConnection({
1703
1850
  headers: {
1704
1851
  ...message.properties.headers,
1705
1852
  index: publishIndex++,
1706
- libVersion: "javascript@0.8.1",
1707
1853
  abort: true
1708
1854
  }
1709
1855
  }).catch((publishError) => {
@@ -1734,7 +1880,6 @@ function createConnection({
1734
1880
  version,
1735
1881
  exception: true,
1736
1882
  index: publishIndex++,
1737
- libVersion: "javascript@0.8.1",
1738
1883
  "error-message": error.message || "error in service handler"
1739
1884
  }
1740
1885
  }).catch((publishError) => {
@@ -1747,6 +1892,7 @@ function createConnection({
1747
1892
  } finally {
1748
1893
  if (messageIdForCleanup) {
1749
1894
  generatorTerminators.delete(messageIdForCleanup);
1895
+ messageCodecs.delete(messageIdForCleanup);
1750
1896
  }
1751
1897
  registeredCallbackIds.forEach((id) => callbacks.delete(id));
1752
1898
  resolveActiveMessage();
@@ -1818,7 +1964,6 @@ function createConnection({
1818
1964
  contentType: "text/plain",
1819
1965
  headers: {
1820
1966
  taskId,
1821
- libVersion: "javascript@0.8.1",
1822
1967
  index: publishIndex++,
1823
1968
  abort: true
1824
1969
  }
@@ -2017,13 +2162,16 @@ function createService(optionsOrVersion, optionalMessageHandler) {
2017
2162
  devOverlay = devParts[1];
2018
2163
  }
2019
2164
  const envMaxMessageSize = process.env.REQUENCE_MAX_MESSAGE_SIZE ? Number(process.env.REQUENCE_MAX_MESSAGE_SIZE) : undefined;
2020
- return createConnection(connectionOptionsSchema.parse({
2021
- ...options,
2022
- connectionOptions: resolveConnectionOptions(options.connectionOptions),
2023
- maxMessageSize: options.maxMessageSize ?? envMaxMessageSize,
2024
- url,
2025
- devOverlay
2026
- }), messageHandler);
2165
+ return createConnection({
2166
+ ...connectionOptionsSchema.parse({
2167
+ ...options,
2168
+ connectionOptions: resolveConnectionOptions(options.connectionOptions),
2169
+ maxMessageSize: options.maxMessageSize ?? envMaxMessageSize,
2170
+ url,
2171
+ devOverlay
2172
+ }),
2173
+ onConnectionStateChange: options.onConnectionStateChange
2174
+ }, messageHandler);
2027
2175
  }
2028
2176
  export {
2029
2177
  wrapIterable,
@@ -2033,6 +2181,7 @@ export {
2033
2181
  createCallback,
2034
2182
  asyncEventEmitter,
2035
2183
  assertReachable,
2184
+ UnsupportedCapabilityError,
2036
2185
  RequenceUnreachableError,
2037
2186
  RequenceStream,
2038
2187
  RequenceFile,
@@ -2040,5 +2189,5 @@ export {
2040
2189
  PayloadTooLargeError
2041
2190
  };
2042
2191
 
2043
- //# debugId=06D2FC35693704C864756E2164756E21
2192
+ //# debugId=339E2FADB6C273CF64756E2164756E21
2044
2193
  //# sourceMappingURL=index.js.map