@requence/service 0.8.1 → 0.8.2-edge.1151

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 +207 -36
  5. package/build/index.js.map +8 -7
  6. package/build/types/helpers/src/protocol/NodeTree.d.ts +94 -4
  7. package/build/types/helpers/src/protocol/NodeTree.d.ts.map +1 -1
  8. package/build/types/helpers/src/protocol/clientProperties.d.ts +116 -0
  9. package/build/types/helpers/src/protocol/clientProperties.d.ts.map +1 -0
  10. package/build/types/helpers/src/protocol/command.d.ts +16 -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 +22 -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 +82 -0
  18. package/build/types/helpers/src/protocol/treeNodes.d.ts.map +1 -1
  19. package/build/types/helpers/src/protocol/update.d.ts +32 -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,29 @@ 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
+ }
793
+
794
+ class UnserializableValue extends Error {
795
+ }
796
+ function toOffloadJson(value) {
797
+ try {
798
+ return JSON.stringify(value, function(key, encoded) {
799
+ const raw = this[key];
800
+ if (ArrayBuffer.isView(raw) || raw instanceof ArrayBuffer) {
801
+ throw new UnserializableValue;
802
+ }
803
+ return encoded;
804
+ });
805
+ } catch (error) {
806
+ if (error instanceof UnserializableValue) {
807
+ return;
808
+ }
809
+ throw error;
810
+ }
811
+ }
719
812
  function createMessageHandler() {
720
813
  return {
721
814
  async wrapOutbound(body, ctx) {
@@ -723,8 +816,8 @@ function createMessageHandler() {
723
816
  if (maxBytes <= 0 || body === undefined) {
724
817
  return body;
725
818
  }
726
- const json = JSON.stringify(body);
727
- if (json === undefined || Buffer2.byteLength(json) <= maxBytes) {
819
+ const measure = ctx.measure ?? jsonByteLength;
820
+ if (measure(body) <= maxBytes) {
728
821
  return body;
729
822
  }
730
823
  const { uploadUrl } = ctx;
@@ -733,25 +826,29 @@ function createMessageHandler() {
733
826
  return body;
734
827
  }
735
828
  if (!isRecord2(body)) {
829
+ const json = toOffloadJson(body);
830
+ if (json === undefined) {
831
+ return body;
832
+ }
736
833
  return offload(ctx, uploadUrl, json);
737
834
  }
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);
835
+ const entries = Object.entries(body).map(([key, value]) => ({
836
+ key,
837
+ valueJson: toOffloadJson(value),
838
+ size: measure(value)
839
+ })).sort((a, b) => b.size - a.size);
746
840
  const wrapped = { ...body };
747
- let total = Buffer2.byteLength(json);
841
+ let total = measure(body);
748
842
  for (const entry of entries) {
749
- if (total <= maxBytes || entry.valueJson === undefined || entry.size <= 256) {
843
+ if (total <= maxBytes || entry.size <= 256) {
750
844
  break;
751
845
  }
846
+ if (entry.valueJson === undefined) {
847
+ continue;
848
+ }
752
849
  const ref = await offload(ctx, uploadUrl, entry.valueJson);
753
850
  wrapped[entry.key] = ref;
754
- total += Buffer2.byteLength(JSON.stringify(ref)) - entry.size;
851
+ total += measure(ref) - entry.size;
755
852
  }
756
853
  return wrapped;
757
854
  }
@@ -1015,6 +1112,8 @@ function createOutboundBoundary(base) {
1015
1112
  const warn = base.warn ?? ((message, error) => error === undefined ? console.warn(message) : console.warn(message, error));
1016
1113
  const ledger = [];
1017
1114
  const errors = [];
1115
+ const codec = base.wireCodec ?? "json";
1116
+ const measure = (value) => wireBodyByteLength(value, codec);
1018
1117
  const track = (promise) => {
1019
1118
  ledger.push(promise.then(() => {}, (error) => {
1020
1119
  errors.push(error instanceof Error ? error : new Error(String(error)));
@@ -1030,6 +1129,7 @@ function createOutboundBoundary(base) {
1030
1129
  streamUrl: base.streamUrl,
1031
1130
  maxPayloadSize: base.maxPayloadSize,
1032
1131
  maxFileSize: base.maxFileSize,
1132
+ measure,
1033
1133
  outputName: opts.outputName ?? null,
1034
1134
  onCallback: opts.onCallback,
1035
1135
  ...opts.bestEffort ? {
@@ -1186,7 +1286,10 @@ var headerSchema = z6.object({
1186
1286
  taskId: msg.properties.headers.taskId,
1187
1287
  mode: msg.properties.headers.mode
1188
1288
  }));
1189
- var payloadSchema = z6.object({ content: z6.instanceof(Buffer) }).transform((msg) => JSON.parse(msg.content.toString())).pipe(z6.object({
1289
+ var payloadSchema = z6.object({
1290
+ content: z6.instanceof(Buffer),
1291
+ properties: z6.object({ contentType: z6.string().optional() })
1292
+ }).transform((msg) => decodeWireBody(msg.content, msg.properties.contentType)).pipe(z6.object({
1190
1293
  input: z6.unknown(),
1191
1294
  configuration: z6.unknown(),
1192
1295
  options: z6.object({
@@ -1197,7 +1300,16 @@ var payloadSchema = z6.object({ content: z6.instanceof(Buffer) }).transform((msg
1197
1300
  })
1198
1301
  }));
1199
1302
  var backchannelMessageSchema = z6.object({
1200
- content: z6.instanceof(Buffer).transform((content) => JSON.parse(content.toString())).pipe(z6.discriminatedUnion("type", [
1303
+ content: z6.instanceof(Buffer),
1304
+ properties: z6.object({
1305
+ correlationId: z6.string(),
1306
+ contentType: z6.string().optional()
1307
+ })
1308
+ }).transform((message) => ({
1309
+ ...message,
1310
+ content: decodeWireBody(message.content, message.properties.contentType)
1311
+ })).pipe(z6.object({
1312
+ content: z6.discriminatedUnion("type", [
1201
1313
  z6.object({
1202
1314
  type: z6.literal("stop")
1203
1315
  }),
@@ -1206,11 +1318,11 @@ var backchannelMessageSchema = z6.object({
1206
1318
  callbackId: z6.uuid(),
1207
1319
  arg: z6.any()
1208
1320
  })
1209
- ])),
1321
+ ]),
1210
1322
  properties: z6.object({
1211
1323
  correlationId: z6.string()
1212
1324
  })
1213
- }).transform((message) => ({
1325
+ })).transform((message) => ({
1214
1326
  payload: message.content,
1215
1327
  messageId: message.properties.correlationId
1216
1328
  }));
@@ -1221,6 +1333,7 @@ var connectionOptionsSchema = z6.object({
1221
1333
  z6.instanceof(URL).refine((url) => url.protocol.match(/^amqps?:/), "Wrong protocol")
1222
1334
  ]),
1223
1335
  version: z6.string(),
1336
+ name: z6.string().optional(),
1224
1337
  devOverlay: z6.string().optional(),
1225
1338
  silent: z6.boolean().optional(),
1226
1339
  prefetch: z6.number().int().optional(),
@@ -1234,6 +1347,7 @@ function isMessageHandlerGenerator(handler) {
1234
1347
  return handler.constructor.name === "GeneratorFunction" || handler.constructor.name === "AsyncGeneratorFunction";
1235
1348
  }
1236
1349
  var activeMessages = new Map;
1350
+ var messageCodecs = new Map;
1237
1351
  function isChannelClosedError(error) {
1238
1352
  return error instanceof Error && error.name === "IllegalOperationError";
1239
1353
  }
@@ -1263,8 +1377,10 @@ function createConnection({
1263
1377
  connectionTimeout,
1264
1378
  heartbeatInterval = DEFAULT_AMQP_HEARTBEAT_SECONDS,
1265
1379
  connectionOptions,
1380
+ name,
1266
1381
  devOverlay = "",
1267
1382
  maxMessageSize,
1383
+ onConnectionStateChange,
1268
1384
  ...rest
1269
1385
  }, messageHandler) {
1270
1386
  const passthroughByteReferences = rest.passthroughByteReferences ?? false;
@@ -1272,13 +1388,33 @@ function createConnection({
1272
1388
  const queue = devOverlay ? `${baseQueue}-dev-overlay-${devOverlay}` : baseQueue;
1273
1389
  const exchange = url.username;
1274
1390
  const connection = connect(url.toString(), {
1275
- connectionOptions,
1391
+ connectionOptions: {
1392
+ ...connectionOptions,
1393
+ clientProperties: {
1394
+ ...connectionOptions?.clientProperties,
1395
+ ...buildServiceClientProperties({
1396
+ libVersion: "javascript@0.8.2-edge.1151",
1397
+ serviceVersion: version,
1398
+ name,
1399
+ devOverlay: Boolean(devOverlay)
1400
+ })
1401
+ }
1402
+ },
1276
1403
  heartbeatIntervalInSeconds: heartbeatInterval
1277
1404
  });
1278
1405
  connection.on("disconnect", ({ err }) => {
1279
1406
  if (!silent && err) {
1280
1407
  console.error("Requence AMQP connection lost:", err.message);
1281
1408
  }
1409
+ onConnectionStateChange?.({ connected: false, err });
1410
+ });
1411
+ let hasConnected = false;
1412
+ connection.on("connect", () => {
1413
+ if (hasConnected && !silent) {
1414
+ console.info("Requence AMQP reconnected");
1415
+ }
1416
+ hasConnected = true;
1417
+ onConnectionStateChange?.({ connected: true });
1282
1418
  });
1283
1419
  const connectedPromise = new Promise((resolve2, reject) => {
1284
1420
  const unsubscribe = () => {
@@ -1371,19 +1507,18 @@ function createConnection({
1371
1507
  priority,
1372
1508
  ...headers
1373
1509
  }) => {
1374
- const body = Buffer.from(JSON.stringify(data ?? null));
1510
+ const { body, contentType } = encodeWireBody(data ?? null, messageCodecs.get(messageId) ?? "json");
1375
1511
  if (body.byteLength > maxMessageSize) {
1376
1512
  return Promise.reject(new PayloadTooLargeError(body.byteLength, maxMessageSize));
1377
1513
  }
1378
1514
  return channelWrapper.publish(exchange, "", body, {
1379
1515
  correlationId: messageId,
1380
- contentType: "application/json",
1516
+ contentType,
1381
1517
  persistent: true,
1382
1518
  priority,
1383
1519
  headers: {
1384
1520
  outputName: outputName ?? null,
1385
1521
  connectionId,
1386
- libVersion: "javascript@0.8.1",
1387
1522
  ...headers
1388
1523
  }
1389
1524
  });
@@ -1454,6 +1589,12 @@ function createConnection({
1454
1589
  try {
1455
1590
  const { messageId, taskId, mode } = headerSchema.parse(message);
1456
1591
  messageIdForCleanup = messageId;
1592
+ const unsupported = unsupportedCapabilities(readRequiredCapabilities(message.properties.headers));
1593
+ if (unsupported.length > 0) {
1594
+ throw new UnsupportedCapabilityError(unsupported);
1595
+ }
1596
+ const dispatchCodec = wireCodecFromContentType(message.properties.contentType);
1597
+ messageCodecs.set(messageId, dispatchCodec);
1457
1598
  let deferred = false;
1458
1599
  let deferredReason = null;
1459
1600
  const messageExecution = Promise.withResolvers();
@@ -1480,6 +1621,7 @@ function createConnection({
1480
1621
  streamUrl: payload.options.streamUrl,
1481
1622
  maxPayloadSize: payload.options.maxPayloadSize,
1482
1623
  maxFileSize: payload.options.maxFileSize,
1624
+ wireCodec: dispatchCodec,
1483
1625
  signal: abortController.signal,
1484
1626
  warn: (msg, error) => console.warn(`${msg} (task ${taskId})`, error instanceof Error ? error.message : error ?? "")
1485
1627
  });
@@ -1557,7 +1699,11 @@ function createConnection({
1557
1699
  taskId,
1558
1700
  priority: message.properties.priority,
1559
1701
  begin: true,
1560
- epoch
1702
+ epoch,
1703
+ ...buildServiceIdentityHeaders({
1704
+ libVersion: "javascript@0.8.2-edge.1151",
1705
+ name
1706
+ })
1561
1707
  });
1562
1708
  if (isMessageHandlerGenerator(messageHandler)) {
1563
1709
  if (mode === "CONTINUOUS") {
@@ -1693,6 +1839,29 @@ function createConnection({
1693
1839
  });
1694
1840
  return;
1695
1841
  }
1842
+ if (error instanceof UnsupportedCapabilityError) {
1843
+ if (!silent) {
1844
+ console.error(error.message);
1845
+ }
1846
+ if (!acked) {
1847
+ safeAck(channel, message);
1848
+ }
1849
+ channelWrapper.publish(`${exchange}-retry`, "operator", message.content, {
1850
+ ...message.properties,
1851
+ headers: {
1852
+ ...message.properties.headers,
1853
+ version,
1854
+ [CAPABILITY_HEADER_KEYS.mismatch]: true,
1855
+ index: publishIndex++,
1856
+ "error-message": error.message
1857
+ }
1858
+ }).catch((publishError) => {
1859
+ if (!silent) {
1860
+ console.error("Failed to publish capability mismatch message:", publishError);
1861
+ }
1862
+ });
1863
+ return;
1864
+ }
1696
1865
  if (error instanceof AbortError && error.message.length > 0) {
1697
1866
  if (!acked) {
1698
1867
  safeAck(channel, message);
@@ -1703,7 +1872,6 @@ function createConnection({
1703
1872
  headers: {
1704
1873
  ...message.properties.headers,
1705
1874
  index: publishIndex++,
1706
- libVersion: "javascript@0.8.1",
1707
1875
  abort: true
1708
1876
  }
1709
1877
  }).catch((publishError) => {
@@ -1734,7 +1902,6 @@ function createConnection({
1734
1902
  version,
1735
1903
  exception: true,
1736
1904
  index: publishIndex++,
1737
- libVersion: "javascript@0.8.1",
1738
1905
  "error-message": error.message || "error in service handler"
1739
1906
  }
1740
1907
  }).catch((publishError) => {
@@ -1747,6 +1914,7 @@ function createConnection({
1747
1914
  } finally {
1748
1915
  if (messageIdForCleanup) {
1749
1916
  generatorTerminators.delete(messageIdForCleanup);
1917
+ messageCodecs.delete(messageIdForCleanup);
1750
1918
  }
1751
1919
  registeredCallbackIds.forEach((id) => callbacks.delete(id));
1752
1920
  resolveActiveMessage();
@@ -1818,7 +1986,6 @@ function createConnection({
1818
1986
  contentType: "text/plain",
1819
1987
  headers: {
1820
1988
  taskId,
1821
- libVersion: "javascript@0.8.1",
1822
1989
  index: publishIndex++,
1823
1990
  abort: true
1824
1991
  }
@@ -2017,13 +2184,16 @@ function createService(optionsOrVersion, optionalMessageHandler) {
2017
2184
  devOverlay = devParts[1];
2018
2185
  }
2019
2186
  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);
2187
+ return createConnection({
2188
+ ...connectionOptionsSchema.parse({
2189
+ ...options,
2190
+ connectionOptions: resolveConnectionOptions(options.connectionOptions),
2191
+ maxMessageSize: options.maxMessageSize ?? envMaxMessageSize,
2192
+ url,
2193
+ devOverlay
2194
+ }),
2195
+ onConnectionStateChange: options.onConnectionStateChange
2196
+ }, messageHandler);
2027
2197
  }
2028
2198
  export {
2029
2199
  wrapIterable,
@@ -2033,6 +2203,7 @@ export {
2033
2203
  createCallback,
2034
2204
  asyncEventEmitter,
2035
2205
  assertReachable,
2206
+ UnsupportedCapabilityError,
2036
2207
  RequenceUnreachableError,
2037
2208
  RequenceStream,
2038
2209
  RequenceFile,
@@ -2040,5 +2211,5 @@ export {
2040
2211
  PayloadTooLargeError
2041
2212
  };
2042
2213
 
2043
- //# debugId=06D2FC35693704C864756E2164756E21
2214
+ //# debugId=886A241C6AA974E564756E2164756E21
2044
2215
  //# sourceMappingURL=index.js.map