@ferricstore/ferricstore 0.1.4 → 0.1.6
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 +56 -1
- package/dist/index.cjs +1320 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +282 -9
- package/dist/index.d.ts +282 -9
- package/dist/index.js +1317 -45
- package/dist/index.js.map +1 -1
- package/docs/api/assets/hierarchy.js +1 -1
- package/docs/api/assets/highlight.css +6 -6
- package/docs/api/assets/navigation.js +1 -1
- package/docs/api/assets/search.js +1 -1
- package/docs/api/classes/FerricStoreClient.html +25 -2
- package/docs/api/classes/FerricStoreError.html +3 -3
- package/docs/api/classes/FlowAlreadyExistsError.html +3 -3
- package/docs/api/classes/FlowNotFoundError.html +3 -3
- package/docs/api/classes/FlowWrongStateError.html +3 -3
- package/docs/api/classes/InvalidCommandError.html +3 -3
- package/docs/api/classes/LockHeldError.html +3 -3
- package/docs/api/classes/LockNotOwnedError.html +3 -3
- package/docs/api/classes/NativeAdapter.html +3 -2
- package/docs/api/classes/OverloadedError.html +3 -3
- package/docs/api/classes/ReconnectingExecutor.html +4 -2
- package/docs/api/classes/RoutingTopology.html +9 -0
- package/docs/api/classes/StaleLeaseError.html +3 -3
- package/docs/api/classes/TopologyNativeAdapterPool.html +8 -0
- package/docs/api/classes/Workflow.html +3 -2
- package/docs/api/classes/WorkflowClient.html +2 -2
- package/docs/api/classes/WorkflowContext.html +2 -2
- package/docs/api/classes/WorkflowFlowCommands.html +2 -2
- package/docs/api/classes/WorkflowWorker.html +2 -2
- package/docs/api/functions/isReconnectableClosedConnectionError.html +1 -1
- package/docs/api/hierarchy.html +1 -1
- package/docs/api/index.html +21 -7
- package/docs/api/interfaces/AutoBatchOptions.html +2 -2
- package/docs/api/interfaces/CancelOptions.html +2 -2
- package/docs/api/interfaces/ClaimDueOptions.html +2 -2
- package/docs/api/interfaces/ClaimedItem.html +2 -3
- package/docs/api/interfaces/CommandExecutor.html +4 -2
- package/docs/api/interfaces/CompleteOptions.html +2 -2
- package/docs/api/interfaces/CompleteOutcome.html +1 -1
- package/docs/api/interfaces/CreateManyOptions.html +2 -2
- package/docs/api/interfaces/CreateOptions.html +2 -2
- package/docs/api/interfaces/ExecutePipelineOptions.html +2 -2
- package/docs/api/interfaces/FailOptions.html +2 -2
- package/docs/api/interfaces/FailOutcome.html +1 -1
- package/docs/api/interfaces/FencedItem.html +2 -2
- package/docs/api/interfaces/FerricStoreClientFromUrlOptions.html +2 -2
- package/docs/api/interfaces/FerricStoreClientOptions.html +2 -2
- package/docs/api/interfaces/FetchOrComputeResult.html +2 -2
- package/docs/api/interfaces/FlowPolicyOptions.html +7 -0
- package/docs/api/interfaces/FlowRecord.html +2 -2
- package/docs/api/interfaces/FlowStatePolicy.html +3 -0
- package/docs/api/interfaces/InvocationCreateOptions.html +4 -0
- package/docs/api/interfaces/KeyInfo.html +2 -2
- package/docs/api/interfaces/MutateOptions.html +2 -2
- package/docs/api/interfaces/NamedValueMutation.html +1 -1
- package/docs/api/interfaces/NativeAdapterOptions.html +8 -2
- package/docs/api/interfaces/ProtocolCommand.html +5 -0
- package/docs/api/interfaces/RateLimitResult.html +2 -2
- package/docs/api/interfaces/ReadOptions.html +2 -2
- package/docs/api/interfaces/ReclaimOptions.html +2 -2
- package/docs/api/interfaces/ReconnectOptions.html +2 -2
- package/docs/api/interfaces/RequestContext.html +4 -0
- package/docs/api/interfaces/RequestContextOptions.html +2 -0
- package/docs/api/interfaces/RetryOptions.html +2 -2
- package/docs/api/interfaces/RetryOutcome.html +1 -1
- package/docs/api/interfaces/RoutingEndpoint.html +5 -0
- package/docs/api/interfaces/RoutingRoute.html +7 -0
- package/docs/api/interfaces/SearchOptions.html +12 -0
- package/docs/api/interfaces/StateOptions.html +3 -2
- package/docs/api/interfaces/StateRegistration.html +3 -2
- package/docs/api/interfaces/TDigestCreateOptions.html +1 -1
- package/docs/api/interfaces/TDigestMergeOptions.html +1 -1
- package/docs/api/interfaces/TransitionOptions.html +2 -2
- package/docs/api/interfaces/TransitionOutcome.html +1 -1
- package/docs/api/interfaces/WorkflowOptions.html +2 -2
- package/docs/api/interfaces/WorkflowWorkerResult.html +2 -2
- package/docs/api/modules.html +1 -1
- package/docs/api/types/CommandArgument.html +1 -1
- package/docs/api/types/EndpointPolicy.html +1 -0
- package/docs/api/types/FlowStateMode.html +1 -0
- package/docs/api/types/FlowStatePolicyLike.html +1 -0
- package/docs/api/types/ManagementPairs.html +1 -0
- package/docs/api/types/QueueBatchHandler.html +1 -1
- package/docs/api/types/QueueHandler.html +1 -1
- package/docs/api/types/QueueJob.html +1 -0
- package/docs/api/types/SearchStateMeta.html +1 -0
- package/docs/api/types/WorkflowHandler.html +1 -1
- package/docs/api/variables/COMMAND_OPCODES.html +1 -0
- package/docs/python-parity.md +4 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
BitmapStore: () => BitmapStore,
|
|
34
34
|
BloomFilterStore: () => BloomFilterStore,
|
|
35
|
+
COMMAND_OPCODES: () => COMMAND_OPCODES,
|
|
35
36
|
CountMinSketchStore: () => CountMinSketchStore,
|
|
36
37
|
CuckooFilterStore: () => CuckooFilterStore,
|
|
37
38
|
FerricStoreClient: () => FerricStoreClient,
|
|
@@ -56,12 +57,14 @@ __export(index_exports, {
|
|
|
56
57
|
QueueWorker: () => QueueWorker,
|
|
57
58
|
RawCodec: () => RawCodec,
|
|
58
59
|
ReconnectingExecutor: () => ReconnectingExecutor,
|
|
60
|
+
RoutingTopology: () => RoutingTopology,
|
|
59
61
|
SetStore: () => SetStore,
|
|
60
62
|
SortedSetStore: () => SortedSetStore,
|
|
61
63
|
StaleLeaseError: () => StaleLeaseError,
|
|
62
64
|
StreamStore: () => StreamStore,
|
|
63
65
|
TDigestStore: () => TDigestStore,
|
|
64
66
|
TopKStore: () => TopKStore,
|
|
67
|
+
TopologyNativeAdapterPool: () => TopologyNativeAdapterPool,
|
|
65
68
|
Workflow: () => Workflow,
|
|
66
69
|
WorkflowClient: () => WorkflowClient,
|
|
67
70
|
WorkflowContext: () => WorkflowContext,
|
|
@@ -189,24 +192,171 @@ var FLAG_CUSTOM_PAYLOAD = 2;
|
|
|
189
192
|
var FLAG_COMPRESSED = 8;
|
|
190
193
|
var FLAG_MORE_CHUNKS = 32;
|
|
191
194
|
var STATUS_OK = 0;
|
|
195
|
+
var COMMAND_OPCODES = {
|
|
196
|
+
"HELLO": 1,
|
|
197
|
+
"AUTH": 2,
|
|
198
|
+
"PING": 3,
|
|
199
|
+
"CLIENT.SETNAME": 4,
|
|
200
|
+
"CLIENT.INFO": 5,
|
|
201
|
+
"ROUTE": 6,
|
|
202
|
+
"SHARDS": 7,
|
|
203
|
+
"BACKPRESSURE": 8,
|
|
204
|
+
"QUIT": 9,
|
|
205
|
+
"GOAWAY": 10,
|
|
206
|
+
"OPTIONS": 11,
|
|
207
|
+
"STARTUP": 12,
|
|
208
|
+
"WINDOW_UPDATE": 13,
|
|
209
|
+
"PIPELINE": 14,
|
|
210
|
+
"ROUTE_BATCH": 15,
|
|
211
|
+
"EVENT": 16,
|
|
212
|
+
"SUBSCRIBE_EVENTS": 17,
|
|
213
|
+
"UNSUBSCRIBE_EVENTS": 18,
|
|
214
|
+
"COMMAND_EXEC": 256,
|
|
215
|
+
"GET": 257,
|
|
216
|
+
"SET": 258,
|
|
217
|
+
"DEL": 259,
|
|
218
|
+
"MGET": 260,
|
|
219
|
+
"MSET": 261,
|
|
220
|
+
"CAS": 262,
|
|
221
|
+
"LOCK": 263,
|
|
222
|
+
"UNLOCK": 264,
|
|
223
|
+
"EXTEND": 265,
|
|
224
|
+
"RATELIMIT.ADD": 266,
|
|
225
|
+
"FETCH_OR_COMPUTE": 267,
|
|
226
|
+
"FETCH_OR_COMPUTE_RESULT": 268,
|
|
227
|
+
"FETCH_OR_COMPUTE_ERROR": 269,
|
|
228
|
+
"HSET": 272,
|
|
229
|
+
"HGET": 273,
|
|
230
|
+
"HMGET": 274,
|
|
231
|
+
"HGETALL": 275,
|
|
232
|
+
"LPUSH": 288,
|
|
233
|
+
"RPUSH": 289,
|
|
234
|
+
"LPOP": 290,
|
|
235
|
+
"RPOP": 291,
|
|
236
|
+
"LRANGE": 292,
|
|
237
|
+
"SADD": 304,
|
|
238
|
+
"SREM": 305,
|
|
239
|
+
"SMEMBERS": 306,
|
|
240
|
+
"SISMEMBER": 307,
|
|
241
|
+
"ZADD": 320,
|
|
242
|
+
"ZREM": 321,
|
|
243
|
+
"ZRANGE": 322,
|
|
244
|
+
"ZSCORE": 323,
|
|
245
|
+
"FLOW.CREATE": 513,
|
|
246
|
+
"FLOW.GET": 514,
|
|
247
|
+
"FLOW.CLAIM_DUE": 515,
|
|
248
|
+
"FLOW.COMPLETE": 516,
|
|
249
|
+
"FLOW.TRANSITION": 517,
|
|
250
|
+
"FLOW.RETRY": 518,
|
|
251
|
+
"FLOW.FAIL": 519,
|
|
252
|
+
"FLOW.CANCEL": 520,
|
|
253
|
+
"FLOW.EXTEND_LEASE": 521,
|
|
254
|
+
"FLOW.HISTORY": 522,
|
|
255
|
+
"FLOW.VALUE.PUT": 523,
|
|
256
|
+
"FLOW.VALUE.MGET": 524,
|
|
257
|
+
"FLOW.SIGNAL": 525,
|
|
258
|
+
"FLOW.LIST": 526,
|
|
259
|
+
"FLOW.CREATE_MANY": 527,
|
|
260
|
+
"FLOW.COMPLETE_MANY": 528,
|
|
261
|
+
"FLOW.TRANSITION_MANY": 529,
|
|
262
|
+
"FLOW.RETRY_MANY": 530,
|
|
263
|
+
"FLOW.FAIL_MANY": 531,
|
|
264
|
+
"FLOW.CANCEL_MANY": 532,
|
|
265
|
+
"FLOW.RECLAIM": 533,
|
|
266
|
+
"FLOW.REWIND": 534,
|
|
267
|
+
"FLOW.TERMINALS": 535,
|
|
268
|
+
"FLOW.FAILURES": 536,
|
|
269
|
+
"FLOW.BY_PARENT": 537,
|
|
270
|
+
"FLOW.BY_ROOT": 538,
|
|
271
|
+
"FLOW.BY_CORRELATION": 539,
|
|
272
|
+
"FLOW.INFO": 540,
|
|
273
|
+
"FLOW.STUCK": 541,
|
|
274
|
+
"FLOW.POLICY.SET": 542,
|
|
275
|
+
"FLOW.POLICY.GET": 543,
|
|
276
|
+
"FLOW.SPAWN_CHILDREN": 544,
|
|
277
|
+
"FLOW.RETENTION_CLEANUP": 545,
|
|
278
|
+
"FLOW.STEP_CONTINUE": 546,
|
|
279
|
+
"FLOW.START_AND_CLAIM": 547,
|
|
280
|
+
"FLOW.RUN_STEPS_MANY": 548,
|
|
281
|
+
"FLOW.SCHEDULE.CREATE": 549,
|
|
282
|
+
"FLOW.SCHEDULE.GET": 550,
|
|
283
|
+
"FLOW.SCHEDULE.DELETE": 551,
|
|
284
|
+
"FLOW.SCHEDULE.FIRE_DUE": 552,
|
|
285
|
+
"FLOW.SCHEDULE.LIST": 553,
|
|
286
|
+
"FLOW.SCHEDULE.FIRE": 554,
|
|
287
|
+
"FLOW.SCHEDULE.PAUSE": 555,
|
|
288
|
+
"FLOW.SCHEDULE.RESUME": 556,
|
|
289
|
+
"FLOW.STATS": 557,
|
|
290
|
+
"FLOW.ATTRIBUTES": 558,
|
|
291
|
+
"FLOW.ATTRIBUTE_VALUES": 559,
|
|
292
|
+
"FLOW.SEARCH": 560,
|
|
293
|
+
"FLOW.EFFECT.RESERVE": 576,
|
|
294
|
+
"FLOW.EFFECT.CONFIRM": 577,
|
|
295
|
+
"FLOW.EFFECT.FAIL": 578,
|
|
296
|
+
"FLOW.EFFECT.COMPENSATE": 579,
|
|
297
|
+
"FLOW.EFFECT.GET": 580,
|
|
298
|
+
"FLOW.GOVERNANCE.LEDGER": 581,
|
|
299
|
+
"FLOW.APPROVAL.REQUEST": 582,
|
|
300
|
+
"FLOW.APPROVAL.APPROVE": 583,
|
|
301
|
+
"FLOW.APPROVAL.REJECT": 584,
|
|
302
|
+
"FLOW.APPROVAL.GET": 585,
|
|
303
|
+
"FLOW.CIRCUIT.OPEN": 586,
|
|
304
|
+
"FLOW.CIRCUIT.CLOSE": 587,
|
|
305
|
+
"FLOW.CIRCUIT.GET": 588,
|
|
306
|
+
"FLOW.BUDGET.RESERVE": 589,
|
|
307
|
+
"FLOW.BUDGET.GET": 590,
|
|
308
|
+
"FLOW.LIMIT.LEASE": 591,
|
|
309
|
+
"FLOW.LIMIT.SPEND": 592,
|
|
310
|
+
"FLOW.LIMIT.RELEASE": 593,
|
|
311
|
+
"FLOW.LIMIT.GET": 594,
|
|
312
|
+
"FLOW.APPROVAL.LIST": 595,
|
|
313
|
+
"FLOW.GOVERNANCE.OVERVIEW": 596,
|
|
314
|
+
"FLOW.BUDGET.LIST": 597,
|
|
315
|
+
"FLOW.LIMIT.LIST": 598,
|
|
316
|
+
"FLOW.BUDGET.COMMIT": 599,
|
|
317
|
+
"FLOW.BUDGET.RELEASE": 600,
|
|
318
|
+
"CLUSTER.HEALTH": 769,
|
|
319
|
+
"CLUSTER.STATS": 770,
|
|
320
|
+
"CLUSTER.KEYSLOT": 771,
|
|
321
|
+
"CLUSTER.SLOTS": 772,
|
|
322
|
+
"CLUSTER.STATUS": 773,
|
|
323
|
+
"CLUSTER.JOIN": 774,
|
|
324
|
+
"CLUSTER.LEAVE": 775,
|
|
325
|
+
"CLUSTER.FAILOVER": 776,
|
|
326
|
+
"CLUSTER.PROMOTE": 777,
|
|
327
|
+
"CLUSTER.DEMOTE": 778,
|
|
328
|
+
"CLUSTER.ROLE": 779,
|
|
329
|
+
"FERRICSTORE.KEY_INFO": 780,
|
|
330
|
+
"FERRICSTORE.CONFIG": 781,
|
|
331
|
+
"FERRICSTORE.HOTNESS": 782,
|
|
332
|
+
"FERRICSTORE.METRICS": 783,
|
|
333
|
+
"FERRICSTORE.BLOBGC": 784
|
|
334
|
+
};
|
|
192
335
|
var OPCODES = {
|
|
193
|
-
startup:
|
|
194
|
-
auth:
|
|
195
|
-
ping:
|
|
196
|
-
clientSetName:
|
|
197
|
-
clientInfo:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
336
|
+
startup: COMMAND_OPCODES.STARTUP,
|
|
337
|
+
auth: COMMAND_OPCODES.AUTH,
|
|
338
|
+
ping: COMMAND_OPCODES.PING,
|
|
339
|
+
clientSetName: COMMAND_OPCODES["CLIENT.SETNAME"],
|
|
340
|
+
clientInfo: COMMAND_OPCODES["CLIENT.INFO"],
|
|
341
|
+
route: COMMAND_OPCODES.ROUTE,
|
|
342
|
+
routeBatch: COMMAND_OPCODES.ROUTE_BATCH,
|
|
343
|
+
shards: COMMAND_OPCODES.SHARDS,
|
|
344
|
+
backpressure: COMMAND_OPCODES.BACKPRESSURE,
|
|
345
|
+
options: COMMAND_OPCODES.OPTIONS,
|
|
346
|
+
quit: COMMAND_OPCODES.QUIT,
|
|
347
|
+
commandExec: COMMAND_OPCODES.COMMAND_EXEC,
|
|
348
|
+
get: COMMAND_OPCODES.GET,
|
|
349
|
+
set: COMMAND_OPCODES.SET,
|
|
350
|
+
del: COMMAND_OPCODES.DEL,
|
|
351
|
+
mget: COMMAND_OPCODES.MGET,
|
|
352
|
+
mset: COMMAND_OPCODES.MSET,
|
|
353
|
+
pipeline: COMMAND_OPCODES.PIPELINE,
|
|
354
|
+
flowCreate: COMMAND_OPCODES["FLOW.CREATE"],
|
|
355
|
+
flowClaimDue: COMMAND_OPCODES["FLOW.CLAIM_DUE"],
|
|
356
|
+
flowComplete: COMMAND_OPCODES["FLOW.COMPLETE"],
|
|
357
|
+
flowCreateMany: COMMAND_OPCODES["FLOW.CREATE_MANY"],
|
|
358
|
+
flowCompleteMany: COMMAND_OPCODES["FLOW.COMPLETE_MANY"],
|
|
359
|
+
flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
|
|
210
360
|
};
|
|
211
361
|
var COMPACT_FLOW_CLAIM_JOBS = 128;
|
|
212
362
|
var COMPACT_OK_LIST = 129;
|
|
@@ -339,12 +489,46 @@ function buildProtocolCommand(args) {
|
|
|
339
489
|
}
|
|
340
490
|
const command = asText(args[0]).toUpperCase();
|
|
341
491
|
const commandArgs = args.slice(1);
|
|
492
|
+
if (command === "COMMAND_EXEC" && commandArgs.length >= 1) {
|
|
493
|
+
return commandExec(commandArgs);
|
|
494
|
+
}
|
|
495
|
+
if (command === "HELLO" || command === "STARTUP" || command === "WINDOW_UPDATE") {
|
|
496
|
+
return { laneId: 0, opcode: COMMAND_OPCODES[command], payload: optionMap(commandArgs) };
|
|
497
|
+
}
|
|
498
|
+
if (command === "AUTH") {
|
|
499
|
+
const payload = commandArgs.length === 1 ? { password: commandArgs[0], username: "default" } : { password: commandArgs[1], username: commandArgs[0] };
|
|
500
|
+
return { laneId: 0, opcode: OPCODES.auth, payload };
|
|
501
|
+
}
|
|
342
502
|
if (command === "PING") {
|
|
343
503
|
return { laneId: 0, opcode: OPCODES.ping, payload: commandArgs.length === 0 ? {} : { message: commandArgs[0] } };
|
|
344
504
|
}
|
|
505
|
+
if (command === "OPTIONS") {
|
|
506
|
+
return { laneId: 0, opcode: OPCODES.options, payload: {} };
|
|
507
|
+
}
|
|
508
|
+
if (command === "BACKPRESSURE") {
|
|
509
|
+
return { laneId: 0, opcode: OPCODES.backpressure, payload: {} };
|
|
510
|
+
}
|
|
511
|
+
if (command === "QUIT") {
|
|
512
|
+
return { laneId: 0, opcode: OPCODES.quit, payload: {} };
|
|
513
|
+
}
|
|
514
|
+
if (command === "ROUTE" && commandArgs.length >= 1) {
|
|
515
|
+
return { laneId: 0, opcode: OPCODES.route, payload: { key: commandArgs[0] } };
|
|
516
|
+
}
|
|
517
|
+
if (command === "ROUTE_BATCH") {
|
|
518
|
+
return { laneId: 0, opcode: OPCODES.routeBatch, payload: { keys: commandArgs } };
|
|
519
|
+
}
|
|
520
|
+
if (command === "SHARDS") {
|
|
521
|
+
return { laneId: 0, opcode: OPCODES.shards, payload: {} };
|
|
522
|
+
}
|
|
345
523
|
if (command === "CLIENT" && asText(commandArgs[0]).toUpperCase() === "SETNAME" && commandArgs.length === 2) {
|
|
346
524
|
return { laneId: 0, opcode: OPCODES.clientSetName, payload: { name: commandArgs[1] } };
|
|
347
525
|
}
|
|
526
|
+
if (command === "CLIENT.SETNAME" && commandArgs.length === 1) {
|
|
527
|
+
return { laneId: 0, opcode: OPCODES.clientSetName, payload: { name: commandArgs[0] } };
|
|
528
|
+
}
|
|
529
|
+
if (command === "CLIENT" && asText(commandArgs[0]).toUpperCase() === "INFO" && commandArgs.length === 1 || command === "CLIENT.INFO" && commandArgs.length === 0) {
|
|
530
|
+
return { laneId: 0, opcode: OPCODES.clientInfo, payload: {} };
|
|
531
|
+
}
|
|
348
532
|
if (command === "GET" && commandArgs.length >= 1) {
|
|
349
533
|
return { opcode: OPCODES.get, payload: { key: commandArgs[0] } };
|
|
350
534
|
}
|
|
@@ -363,7 +547,7 @@ function buildProtocolCommand(args) {
|
|
|
363
547
|
if (command === "DEL") {
|
|
364
548
|
return { opcode: OPCODES.del, payload: { keys: commandArgs } };
|
|
365
549
|
}
|
|
366
|
-
if (command.startsWith("FLOW.") && hasFlowCommandOnlyOption(commandArgs)) {
|
|
550
|
+
if (command.startsWith("FLOW.") && hasFlowCommandOnlyOption(command, commandArgs)) {
|
|
367
551
|
return commandExec(args);
|
|
368
552
|
}
|
|
369
553
|
if (command === "FLOW.CREATE") {
|
|
@@ -381,20 +565,73 @@ function buildProtocolCommand(args) {
|
|
|
381
565
|
if (command === "FLOW.COMPLETE_MANY") {
|
|
382
566
|
return flowCompleteManyPayload(commandArgs) ?? commandExec(args);
|
|
383
567
|
}
|
|
568
|
+
if (command === "FLOW.SEARCH") {
|
|
569
|
+
return flowSearchPayload(commandArgs) ?? commandExec(args);
|
|
570
|
+
}
|
|
384
571
|
return commandExec(args);
|
|
385
572
|
}
|
|
386
573
|
function commandExec(args) {
|
|
387
574
|
if (args.length === 0) {
|
|
388
575
|
throw new FerricStoreError("command requires at least one argument");
|
|
389
576
|
}
|
|
577
|
+
const commandArgs = args.slice(1);
|
|
578
|
+
const payload = {
|
|
579
|
+
args: commandArgs,
|
|
580
|
+
command: asText(args[0]).toUpperCase()
|
|
581
|
+
};
|
|
582
|
+
if (commandArgs.length >= 2 && commandTokenIs(commandArgs[commandArgs.length - 2], "REQUEST_CONTEXT")) {
|
|
583
|
+
const requestContext = normalizeRequestContext(commandArgs[commandArgs.length - 1]);
|
|
584
|
+
payload.args = commandArgs.slice(0, -2);
|
|
585
|
+
if (requestContext != null) {
|
|
586
|
+
payload.request_context = requestContext;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
390
589
|
return {
|
|
391
590
|
opcode: OPCODES.commandExec,
|
|
392
|
-
payload
|
|
393
|
-
args: args.slice(1),
|
|
394
|
-
command: asText(args[0]).toUpperCase()
|
|
395
|
-
}
|
|
591
|
+
payload
|
|
396
592
|
};
|
|
397
593
|
}
|
|
594
|
+
function normalizeRequestContext(context) {
|
|
595
|
+
if (!isPlainObject(context)) {
|
|
596
|
+
return void 0;
|
|
597
|
+
}
|
|
598
|
+
const out = {};
|
|
599
|
+
const subject = optionalText(context.subject);
|
|
600
|
+
const tenant = optionalText(context.tenant);
|
|
601
|
+
const scopes = normalizeRequestContextScopes(context.scopes);
|
|
602
|
+
if (subject != null) {
|
|
603
|
+
out.subject = subject;
|
|
604
|
+
}
|
|
605
|
+
if (tenant != null) {
|
|
606
|
+
out.tenant = tenant;
|
|
607
|
+
}
|
|
608
|
+
if (scopes.length > 0) {
|
|
609
|
+
out.scopes = scopes;
|
|
610
|
+
}
|
|
611
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
612
|
+
}
|
|
613
|
+
function normalizeRequestContextScopes(scopes) {
|
|
614
|
+
const values = typeof scopes === "string" || import_node_buffer.Buffer.isBuffer(scopes) || scopes instanceof Uint8Array ? asText(scopes).split(/\s+/u) : Array.isArray(scopes) ? scopes.map((scope) => optionalText(scope)).filter((scope) => scope != null) : [];
|
|
615
|
+
return [...new Set(values.filter((scope) => scope.length > 0))];
|
|
616
|
+
}
|
|
617
|
+
function optionalText(value) {
|
|
618
|
+
if (value == null || value === "") {
|
|
619
|
+
return void 0;
|
|
620
|
+
}
|
|
621
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || import_node_buffer.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
622
|
+
return asText(value);
|
|
623
|
+
}
|
|
624
|
+
return void 0;
|
|
625
|
+
}
|
|
626
|
+
function commandTokenIs(value, expected) {
|
|
627
|
+
if (typeof value === "string") {
|
|
628
|
+
return value.toUpperCase() === expected;
|
|
629
|
+
}
|
|
630
|
+
if (import_node_buffer.Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
631
|
+
return asText(value).toUpperCase() === expected;
|
|
632
|
+
}
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
398
635
|
function pipelineCommand(commands) {
|
|
399
636
|
const compact = compactPipelinePayload(commands);
|
|
400
637
|
if (compact != null) {
|
|
@@ -725,13 +962,13 @@ function writeOptionalBinary(out, offset, value) {
|
|
|
725
962
|
}
|
|
726
963
|
return writeBinary(out, offset, value);
|
|
727
964
|
}
|
|
728
|
-
function hasFlowCommandOnlyOption(args) {
|
|
965
|
+
function hasFlowCommandOnlyOption(command, args) {
|
|
729
966
|
return args.some((arg) => {
|
|
730
967
|
if (typeof arg !== "string" && !import_node_buffer.Buffer.isBuffer(arg)) {
|
|
731
968
|
return false;
|
|
732
969
|
}
|
|
733
970
|
const token = asText(arg).toUpperCase();
|
|
734
|
-
return token === "
|
|
971
|
+
return token === "INDEXED_STATE_META" || command !== "FLOW.SEARCH" && token === "STATE_META";
|
|
735
972
|
});
|
|
736
973
|
}
|
|
737
974
|
function flowCreatePayload(args) {
|
|
@@ -849,6 +1086,12 @@ function flowCompleteManyPayload(args) {
|
|
|
849
1086
|
if (!auto && !mixed) payload.partition_key = partition;
|
|
850
1087
|
return { opcode: OPCODES.flowCompleteMany, payload };
|
|
851
1088
|
}
|
|
1089
|
+
function flowSearchPayload(args) {
|
|
1090
|
+
if (args.length < 1) return void 0;
|
|
1091
|
+
const payload = optionMap(args.slice(1));
|
|
1092
|
+
normalizeFlowSearchStateMeta(payload);
|
|
1093
|
+
return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
|
|
1094
|
+
}
|
|
852
1095
|
function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options) {
|
|
853
1096
|
if ("priority" in options || "idempotent" in options || "retention_ttl_ms" in options || typeof options.type === "undefined" || typeof options.state === "undefined" || typeof options.now_ms !== "number") {
|
|
854
1097
|
return void 0;
|
|
@@ -951,6 +1194,78 @@ function compactFlowCompleteManyPayload(partition, rawItems, mixed, auto, option
|
|
|
951
1194
|
}
|
|
952
1195
|
return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.flowCompleteMany, payload: out };
|
|
953
1196
|
}
|
|
1197
|
+
var OPTION_FIELDS = {
|
|
1198
|
+
CONSISTENT_PROJECTION: "consistent_projection",
|
|
1199
|
+
COUNT: "count",
|
|
1200
|
+
FROM_MS: "from_ms",
|
|
1201
|
+
INCLUDE_COLD: "include_cold",
|
|
1202
|
+
PARTITION: "partition_key",
|
|
1203
|
+
REV: "rev",
|
|
1204
|
+
STATE: "state",
|
|
1205
|
+
TERMINAL_ONLY: "terminal_only",
|
|
1206
|
+
TO_MS: "to_ms"
|
|
1207
|
+
};
|
|
1208
|
+
var BOOL_OPTION_FIELDS = /* @__PURE__ */ new Set(["consistent_projection", "include_cold", "rev", "terminal_only"]);
|
|
1209
|
+
function optionMap(args) {
|
|
1210
|
+
const payload = {};
|
|
1211
|
+
for (let index = 0; index < args.length; ) {
|
|
1212
|
+
const token = asText(args[index]).toUpperCase();
|
|
1213
|
+
if (token === "ATTRIBUTE") {
|
|
1214
|
+
if (index + 2 >= args.length) {
|
|
1215
|
+
throw new FerricStoreError("ATTRIBUTE requires name and value");
|
|
1216
|
+
}
|
|
1217
|
+
const name = asText(args[index + 1]);
|
|
1218
|
+
const attributes = ensureObjectField(payload, "attributes");
|
|
1219
|
+
attributes[name] = args[index + 2];
|
|
1220
|
+
index += 3;
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
if (token === "STATE_META") {
|
|
1224
|
+
if (index + 2 >= args.length) {
|
|
1225
|
+
throw new FerricStoreError("STATE_META requires name and value");
|
|
1226
|
+
}
|
|
1227
|
+
const name = asText(args[index + 1]);
|
|
1228
|
+
const stateMeta = ensureObjectField(payload, "state_meta");
|
|
1229
|
+
stateMeta[name] = args[index + 2];
|
|
1230
|
+
index += 3;
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
1233
|
+
const field2 = OPTION_FIELDS[token] ?? token.toLowerCase();
|
|
1234
|
+
if (index + 1 >= args.length) {
|
|
1235
|
+
throw new FerricStoreError(`${token} requires a value`);
|
|
1236
|
+
}
|
|
1237
|
+
const value = args[index + 1];
|
|
1238
|
+
payload[field2] = BOOL_OPTION_FIELDS.has(field2) ? boolArg(value) : value;
|
|
1239
|
+
index += 2;
|
|
1240
|
+
}
|
|
1241
|
+
return payload;
|
|
1242
|
+
}
|
|
1243
|
+
function ensureObjectField(payload, field2) {
|
|
1244
|
+
const value = payload[field2];
|
|
1245
|
+
if (isPlainObject(value)) {
|
|
1246
|
+
return value;
|
|
1247
|
+
}
|
|
1248
|
+
const next = {};
|
|
1249
|
+
payload[field2] = next;
|
|
1250
|
+
return next;
|
|
1251
|
+
}
|
|
1252
|
+
function normalizeFlowSearchStateMeta(payload) {
|
|
1253
|
+
const stateMeta = payload.state_meta;
|
|
1254
|
+
if (!isPlainObject(stateMeta) || Object.keys(stateMeta).length === 0) {
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
if (Object.values(stateMeta).every(isPlainObject)) {
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
const state = payload.state;
|
|
1261
|
+
if (state == null) {
|
|
1262
|
+
throw new FerricStoreError("FLOW.SEARCH STATE_META filters require STATE or nested state metadata");
|
|
1263
|
+
}
|
|
1264
|
+
payload.state_meta = { [asText(state)]: stateMeta };
|
|
1265
|
+
}
|
|
1266
|
+
function isPlainObject(value) {
|
|
1267
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer.Buffer.isBuffer(value) && !(value instanceof Uint8Array);
|
|
1268
|
+
}
|
|
954
1269
|
function parseFlowOptions(args, start, end, config) {
|
|
955
1270
|
const payload = {};
|
|
956
1271
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1509,6 +1824,9 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
1509
1824
|
const command = buildProtocolCommand(args);
|
|
1510
1825
|
return await this.request(command);
|
|
1511
1826
|
}
|
|
1827
|
+
async executeProtocolCommand(command, laneId) {
|
|
1828
|
+
return await this.request(laneId == null ? command : { ...command, laneId });
|
|
1829
|
+
}
|
|
1512
1830
|
async executePipeline(commands, options = {}) {
|
|
1513
1831
|
if (commands.length === 0) {
|
|
1514
1832
|
return [];
|
|
@@ -1720,6 +2038,20 @@ var ReconnectingExecutor = class {
|
|
|
1720
2038
|
return await Promise.all(commands.map((command) => executor.executeCommand(...command)));
|
|
1721
2039
|
});
|
|
1722
2040
|
}
|
|
2041
|
+
async refreshTopology() {
|
|
2042
|
+
const executor = await this.executorPromise;
|
|
2043
|
+
if (executor.refreshTopology == null) {
|
|
2044
|
+
throw new FerricStoreError("topology refresh requires a topology-aware native executor");
|
|
2045
|
+
}
|
|
2046
|
+
return await executor.refreshTopology();
|
|
2047
|
+
}
|
|
2048
|
+
async route(key) {
|
|
2049
|
+
const executor = await this.executorPromise;
|
|
2050
|
+
if (executor.route == null) {
|
|
2051
|
+
throw new FerricStoreError("route lookup requires a topology-aware native executor");
|
|
2052
|
+
}
|
|
2053
|
+
return await executor.route(key);
|
|
2054
|
+
}
|
|
1723
2055
|
async close() {
|
|
1724
2056
|
if (this.closed) {
|
|
1725
2057
|
return;
|
|
@@ -1810,6 +2142,653 @@ function normalizeKeepAliveInitialDelay(value) {
|
|
|
1810
2142
|
return Math.max(0, Math.trunc(value ?? 3e4));
|
|
1811
2143
|
}
|
|
1812
2144
|
|
|
2145
|
+
// src/topology.ts
|
|
2146
|
+
var import_node_buffer3 = require("buffer");
|
|
2147
|
+
var ROUTE_SLOT_COUNT = 1024;
|
|
2148
|
+
var ROUTE_SLOT_MASK = ROUTE_SLOT_COUNT - 1;
|
|
2149
|
+
var RoutingTopology = class _RoutingTopology {
|
|
2150
|
+
routeEpoch;
|
|
2151
|
+
shardCount;
|
|
2152
|
+
slots;
|
|
2153
|
+
endpoints;
|
|
2154
|
+
constructor(routeEpoch, shardCount, slots, endpoints) {
|
|
2155
|
+
this.routeEpoch = routeEpoch;
|
|
2156
|
+
this.shardCount = shardCount;
|
|
2157
|
+
this.slots = slots;
|
|
2158
|
+
this.endpoints = endpoints;
|
|
2159
|
+
}
|
|
2160
|
+
static empty() {
|
|
2161
|
+
return new _RoutingTopology(0, 0, Array.from({ length: ROUTE_SLOT_COUNT }), /* @__PURE__ */ new Map());
|
|
2162
|
+
}
|
|
2163
|
+
static build(payload) {
|
|
2164
|
+
const ranges = getField(payload, "ranges");
|
|
2165
|
+
if (!Array.isArray(ranges)) {
|
|
2166
|
+
throw new FerricStoreError("invalid SHARDS topology payload", { raw: payload });
|
|
2167
|
+
}
|
|
2168
|
+
const slots = Array.from({ length: ROUTE_SLOT_COUNT });
|
|
2169
|
+
const endpoints = /* @__PURE__ */ new Map();
|
|
2170
|
+
for (const item of ranges) {
|
|
2171
|
+
if (textOrUndefined(getField(item, "hint")) === "leader_unknown") {
|
|
2172
|
+
throw new FerricStoreError("SHARDS range has no leader", { raw: item });
|
|
2173
|
+
}
|
|
2174
|
+
const first = numberOrUndefined(getField(item, "first_slot"));
|
|
2175
|
+
const last = numberOrUndefined(getField(item, "last_slot"));
|
|
2176
|
+
const shard = numberOrUndefined(getField(item, "shard"));
|
|
2177
|
+
const laneId = numberOrUndefined(getField(item, "lane_id"));
|
|
2178
|
+
const endpoint = endpointFromRange(item);
|
|
2179
|
+
if (first == null || last == null || shard == null || laneId == null || first < 0 || last < first || last >= ROUTE_SLOT_COUNT) {
|
|
2180
|
+
throw new FerricStoreError("invalid SHARDS range", { raw: item });
|
|
2181
|
+
}
|
|
2182
|
+
const endpointKey = endpointKeyFor(endpoint);
|
|
2183
|
+
const route = {
|
|
2184
|
+
endpoint,
|
|
2185
|
+
endpointKey,
|
|
2186
|
+
laneId,
|
|
2187
|
+
leaderNode: endpoint.node,
|
|
2188
|
+
shard
|
|
2189
|
+
};
|
|
2190
|
+
for (let slot = first; slot <= last; slot += 1) {
|
|
2191
|
+
slots[slot] = route;
|
|
2192
|
+
}
|
|
2193
|
+
endpoints.set(endpointKey, endpoint);
|
|
2194
|
+
}
|
|
2195
|
+
return new _RoutingTopology(
|
|
2196
|
+
numberOrUndefined(getField(payload, "route_epoch")) ?? 0,
|
|
2197
|
+
numberOrUndefined(getField(payload, "shard_count")) ?? 0,
|
|
2198
|
+
slots,
|
|
2199
|
+
endpoints
|
|
2200
|
+
);
|
|
2201
|
+
}
|
|
2202
|
+
static slotForKey(key) {
|
|
2203
|
+
const textKey = import_node_buffer3.Buffer.isBuffer(key) ? key.toString("utf8") : key;
|
|
2204
|
+
let hashInput;
|
|
2205
|
+
if (textKey.startsWith("f:{")) {
|
|
2206
|
+
hashInput = flowHashTag(textKey.slice(3), textKey);
|
|
2207
|
+
} else if (textKey.startsWith("X:f:{")) {
|
|
2208
|
+
hashInput = flowHashTag(textKey.slice(5), textKey);
|
|
2209
|
+
} else {
|
|
2210
|
+
hashInput = hashTagOrKey(textKey);
|
|
2211
|
+
}
|
|
2212
|
+
return crc32(import_node_buffer3.Buffer.from(hashInput)) & ROUTE_SLOT_MASK;
|
|
2213
|
+
}
|
|
2214
|
+
routeKey(key) {
|
|
2215
|
+
const slot = _RoutingTopology.slotForKey(key);
|
|
2216
|
+
const route = this.slots[slot];
|
|
2217
|
+
if (route == null) {
|
|
2218
|
+
throw new FerricStoreError(`no route for slot ${slot}`);
|
|
2219
|
+
}
|
|
2220
|
+
return { ...route, slot };
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2223
|
+
var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
2224
|
+
adapterOptions;
|
|
2225
|
+
adapters = /* @__PURE__ */ new Map();
|
|
2226
|
+
endpointPolicy;
|
|
2227
|
+
endpointValidator;
|
|
2228
|
+
seedEndpointKeys;
|
|
2229
|
+
seedUrls;
|
|
2230
|
+
tls;
|
|
2231
|
+
trustedHosts;
|
|
2232
|
+
warmConnections;
|
|
2233
|
+
topologyValue = RoutingTopology.empty();
|
|
2234
|
+
constructor(urls, options = {}) {
|
|
2235
|
+
if (urls.length === 0) {
|
|
2236
|
+
throw new FerricStoreError("TopologyNativeAdapterPool requires at least one seed URL");
|
|
2237
|
+
}
|
|
2238
|
+
this.seedUrls = [...urls];
|
|
2239
|
+
this.endpointPolicy = options.endpointPolicy ?? "seed_hosts";
|
|
2240
|
+
this.endpointValidator = options.endpointValidator;
|
|
2241
|
+
this.warmConnections = options.warmConnections ?? false;
|
|
2242
|
+
this.tls = options.tlsOptions != null || urls.some((url) => parseFerricUrl2(url).tls);
|
|
2243
|
+
this.adapterOptions = nativeOnlyOptions(withSeedAuthDefaults(urls, options));
|
|
2244
|
+
this.seedEndpointKeys = new Set(urls.map((url) => endpointKeyFor(endpointFromUrl(url))));
|
|
2245
|
+
this.trustedHosts = normalizedHostSet(options.trustedHosts ?? []);
|
|
2246
|
+
}
|
|
2247
|
+
static async fromUrls(urls, options = {}) {
|
|
2248
|
+
const pool = new _TopologyNativeAdapterPool(urls, options);
|
|
2249
|
+
await pool.refreshTopology();
|
|
2250
|
+
return pool;
|
|
2251
|
+
}
|
|
2252
|
+
get topology() {
|
|
2253
|
+
return this.topologyValue;
|
|
2254
|
+
}
|
|
2255
|
+
async refreshTopology() {
|
|
2256
|
+
let lastError;
|
|
2257
|
+
for (const url of this.refreshCandidateUrls()) {
|
|
2258
|
+
try {
|
|
2259
|
+
const adapter = await this.adapterForUrl(url);
|
|
2260
|
+
const topology = RoutingTopology.build(await adapter.executeCommand("SHARDS"));
|
|
2261
|
+
this.topologyValue = topology;
|
|
2262
|
+
if (this.warmConnections) {
|
|
2263
|
+
await Promise.allSettled([...topology.endpoints.values()].map(async (endpoint) => await this.adapterForEndpoint(endpoint)));
|
|
2264
|
+
}
|
|
2265
|
+
return topology;
|
|
2266
|
+
} catch (error) {
|
|
2267
|
+
lastError = error;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
throw new FerricStoreError("no FerricStore topology endpoint reachable", { raw: lastError });
|
|
2271
|
+
}
|
|
2272
|
+
route(key) {
|
|
2273
|
+
const route = this.topologyValue.routeKey(key);
|
|
2274
|
+
this.validateEndpoint(route.endpoint);
|
|
2275
|
+
return route;
|
|
2276
|
+
}
|
|
2277
|
+
async executeCommand(...args) {
|
|
2278
|
+
const routed = this.routeData(args);
|
|
2279
|
+
if (routed == null) {
|
|
2280
|
+
return await (await this.controlAdapter()).executeCommand(...args);
|
|
2281
|
+
}
|
|
2282
|
+
const adapter = await this.adapterForEndpoint(routed.route.endpoint);
|
|
2283
|
+
try {
|
|
2284
|
+
return await adapter.executeProtocolCommand(routed.command, routed.route.laneId);
|
|
2285
|
+
} catch (error) {
|
|
2286
|
+
if (isRetryableRouteError(error)) {
|
|
2287
|
+
await this.refreshTopology().catch(() => void 0);
|
|
2288
|
+
}
|
|
2289
|
+
throw error;
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
async executePipeline(commands, options = {}) {
|
|
2293
|
+
if (commands.length === 0) {
|
|
2294
|
+
return [];
|
|
2295
|
+
}
|
|
2296
|
+
const route = this.singleRouteForCommands(commands);
|
|
2297
|
+
if (route == null) {
|
|
2298
|
+
return await (await this.controlAdapter()).executePipeline(commands, options);
|
|
2299
|
+
}
|
|
2300
|
+
const adapter = await this.adapterForEndpoint(route.endpoint);
|
|
2301
|
+
try {
|
|
2302
|
+
const response = await adapter.executeProtocolCommand(pipelineCommand(commands), route.laneId);
|
|
2303
|
+
return unwrapPipelineResponse(response, options);
|
|
2304
|
+
} catch (error) {
|
|
2305
|
+
if (isRetryableRouteError(error)) {
|
|
2306
|
+
await this.refreshTopology().catch(() => void 0);
|
|
2307
|
+
}
|
|
2308
|
+
throw error;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
async close() {
|
|
2312
|
+
await Promise.allSettled([...this.adapters.values()].map(async (adapter) => await adapter.close()));
|
|
2313
|
+
this.adapters.clear();
|
|
2314
|
+
}
|
|
2315
|
+
routeData(args) {
|
|
2316
|
+
if (args.length === 0) {
|
|
2317
|
+
return void 0;
|
|
2318
|
+
}
|
|
2319
|
+
let command;
|
|
2320
|
+
try {
|
|
2321
|
+
command = buildProtocolCommand(args);
|
|
2322
|
+
} catch {
|
|
2323
|
+
return void 0;
|
|
2324
|
+
}
|
|
2325
|
+
const key = routingKey(args, command);
|
|
2326
|
+
if (key == null) {
|
|
2327
|
+
return void 0;
|
|
2328
|
+
}
|
|
2329
|
+
return { command, route: this.route(key) };
|
|
2330
|
+
}
|
|
2331
|
+
singleRouteForCommands(commands) {
|
|
2332
|
+
let route;
|
|
2333
|
+
for (const command of commands) {
|
|
2334
|
+
const routed = this.routeData(command);
|
|
2335
|
+
if (routed == null) {
|
|
2336
|
+
return void 0;
|
|
2337
|
+
}
|
|
2338
|
+
const current = routed.route;
|
|
2339
|
+
if (route == null) {
|
|
2340
|
+
route = current;
|
|
2341
|
+
} else if (route.endpointKey !== current.endpointKey || route.laneId !== current.laneId) {
|
|
2342
|
+
return void 0;
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
return route;
|
|
2346
|
+
}
|
|
2347
|
+
async controlAdapter() {
|
|
2348
|
+
for (const url of this.refreshCandidateUrls()) {
|
|
2349
|
+
try {
|
|
2350
|
+
return await this.adapterForUrl(url);
|
|
2351
|
+
} catch {
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
return await this.adapterForUrl(this.seedUrls[0] ?? "ferric://127.0.0.1:6388");
|
|
2355
|
+
}
|
|
2356
|
+
async adapterForUrl(url) {
|
|
2357
|
+
const endpoint = endpointFromUrl(url);
|
|
2358
|
+
const key = endpointKeyFor(endpoint);
|
|
2359
|
+
const existing = this.adapters.get(key);
|
|
2360
|
+
if (existing != null) {
|
|
2361
|
+
return existing;
|
|
2362
|
+
}
|
|
2363
|
+
const adapter = await NativeAdapter.fromUrl(url, this.adapterOptions);
|
|
2364
|
+
this.adapters.set(key, adapter);
|
|
2365
|
+
return adapter;
|
|
2366
|
+
}
|
|
2367
|
+
async adapterForEndpoint(endpoint) {
|
|
2368
|
+
this.validateEndpoint(endpoint);
|
|
2369
|
+
const key = endpointKeyFor(endpoint);
|
|
2370
|
+
const existing = this.adapters.get(key);
|
|
2371
|
+
if (existing != null) {
|
|
2372
|
+
return existing;
|
|
2373
|
+
}
|
|
2374
|
+
const adapter = await NativeAdapter.fromUrl(urlFromEndpoint(endpoint, this.tls), this.adapterOptions);
|
|
2375
|
+
this.adapters.set(key, adapter);
|
|
2376
|
+
return adapter;
|
|
2377
|
+
}
|
|
2378
|
+
validateEndpoint(endpoint) {
|
|
2379
|
+
let allowed;
|
|
2380
|
+
if (this.endpointPolicy === "any" || this.endpointPolicy === "none") {
|
|
2381
|
+
allowed = true;
|
|
2382
|
+
} else if (this.endpointPolicy === "seed_hosts") {
|
|
2383
|
+
allowed = this.seedEndpointKeys.has(endpointKeyFor(endpoint)) || this.trustedHosts.has(endpoint.host.toLowerCase());
|
|
2384
|
+
} else if ("allowHosts" in this.endpointPolicy) {
|
|
2385
|
+
allowed = normalizedHostSet(this.endpointPolicy.allowHosts).has(endpoint.host.toLowerCase());
|
|
2386
|
+
} else {
|
|
2387
|
+
throw new FerricStoreError("invalid endpoint policy", { raw: this.endpointPolicy });
|
|
2388
|
+
}
|
|
2389
|
+
if (!allowed) {
|
|
2390
|
+
throw new FerricStoreError("unsafe learned endpoint", { raw: endpoint });
|
|
2391
|
+
}
|
|
2392
|
+
if (this.endpointValidator != null && !this.endpointValidator(endpoint)) {
|
|
2393
|
+
throw new FerricStoreError("unsafe learned endpoint", { raw: endpoint });
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
refreshCandidateUrls() {
|
|
2397
|
+
const urls = [
|
|
2398
|
+
...this.seedUrls,
|
|
2399
|
+
...[...this.topologyValue.endpoints.values()].map((endpoint) => urlFromEndpoint(endpoint, this.tls))
|
|
2400
|
+
];
|
|
2401
|
+
return [...new Set(urls)];
|
|
2402
|
+
}
|
|
2403
|
+
};
|
|
2404
|
+
function routingKey(args, command) {
|
|
2405
|
+
const name = commandName(args);
|
|
2406
|
+
if (command.opcode < 256 || name === "CLUSTER.KEYSLOT" || name === "SHARDS" || name === "ROUTE") {
|
|
2407
|
+
return void 0;
|
|
2408
|
+
}
|
|
2409
|
+
const keyFromArgs = routingKeyFromArgs(name, args);
|
|
2410
|
+
if (keyFromArgs != null) {
|
|
2411
|
+
return keyFromArgs;
|
|
2412
|
+
}
|
|
2413
|
+
if (!isPlainObject2(command.payload)) {
|
|
2414
|
+
return void 0;
|
|
2415
|
+
}
|
|
2416
|
+
for (const field2 of ["key", "partition_key", "id", "owner_flow_id", "parent_id", "root_id", "correlation_id", "scope"]) {
|
|
2417
|
+
const value = getField(command.payload, field2);
|
|
2418
|
+
if (typeof value === "string" || import_node_buffer3.Buffer.isBuffer(value)) {
|
|
2419
|
+
return value;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
const keys = getField(command.payload, "keys");
|
|
2423
|
+
if (Array.isArray(keys)) {
|
|
2424
|
+
return singleShardKey(keys);
|
|
2425
|
+
}
|
|
2426
|
+
const pairsValue = getField(command.payload, "pairs");
|
|
2427
|
+
if (Array.isArray(pairsValue)) {
|
|
2428
|
+
return singleShardKey(
|
|
2429
|
+
pairsValue.filter((pair) => Array.isArray(pair) && pair.length > 0).map((pair) => pair[0])
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
return void 0;
|
|
2433
|
+
}
|
|
2434
|
+
function routingKeyFromArgs(name, args) {
|
|
2435
|
+
if (name == null) {
|
|
2436
|
+
return void 0;
|
|
2437
|
+
}
|
|
2438
|
+
if (name === "MGET" || name === "DEL") {
|
|
2439
|
+
return singleShardKey(args.slice(1));
|
|
2440
|
+
}
|
|
2441
|
+
if (name === "MSET") {
|
|
2442
|
+
const keys = [];
|
|
2443
|
+
for (let index = 1; index < args.length; index += 2) {
|
|
2444
|
+
keys.push(args[index]);
|
|
2445
|
+
}
|
|
2446
|
+
return singleShardKey(keys);
|
|
2447
|
+
}
|
|
2448
|
+
if (name === "BITOP") {
|
|
2449
|
+
return bitopRoutingKey(args);
|
|
2450
|
+
}
|
|
2451
|
+
if (name === "RENAME" || name === "RENAMENX") {
|
|
2452
|
+
return singleShardKey(args.slice(1, 3));
|
|
2453
|
+
}
|
|
2454
|
+
if (name === "XREAD" || name === "XREADGROUP") {
|
|
2455
|
+
return streamReadRoutingKey(args);
|
|
2456
|
+
}
|
|
2457
|
+
if (name.startsWith("FLOW.")) {
|
|
2458
|
+
return flowRoutingKey(name, args);
|
|
2459
|
+
}
|
|
2460
|
+
if (firstKeyCommands.has(name)) {
|
|
2461
|
+
const key = args[1];
|
|
2462
|
+
return typeof key === "string" || import_node_buffer3.Buffer.isBuffer(key) ? key : void 0;
|
|
2463
|
+
}
|
|
2464
|
+
return void 0;
|
|
2465
|
+
}
|
|
2466
|
+
function flowRoutingKey(name, args) {
|
|
2467
|
+
const flowArgs = args.slice(1);
|
|
2468
|
+
if (flowArgs.length === 0) {
|
|
2469
|
+
return void 0;
|
|
2470
|
+
}
|
|
2471
|
+
if (name === "FLOW.CLAIM_DUE" || name === "FLOW.RECLAIM") {
|
|
2472
|
+
return flowPartitionRoutingKey(flowArgs, 1);
|
|
2473
|
+
}
|
|
2474
|
+
if (name === "FLOW.CREATE_MANY" || name === "FLOW.COMPLETE_MANY" || name === "FLOW.TRANSITION_MANY" || name === "FLOW.RETRY_MANY" || name === "FLOW.FAIL_MANY" || name === "FLOW.CANCEL_MANY") {
|
|
2475
|
+
const partition2 = flowArgs[0];
|
|
2476
|
+
if (typeof partition2 === "string" && partition2.toUpperCase() !== "AUTO" && partition2.toUpperCase() !== "MIXED") {
|
|
2477
|
+
return partition2;
|
|
2478
|
+
}
|
|
2479
|
+
if (import_node_buffer3.Buffer.isBuffer(partition2)) {
|
|
2480
|
+
const text2 = partition2.toString("utf8").toUpperCase();
|
|
2481
|
+
if (text2 !== "AUTO" && text2 !== "MIXED") {
|
|
2482
|
+
return partition2;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
return void 0;
|
|
2486
|
+
}
|
|
2487
|
+
const partition = flowPartitionRoutingKey(flowArgs, 1);
|
|
2488
|
+
if (partition != null) {
|
|
2489
|
+
return partition;
|
|
2490
|
+
}
|
|
2491
|
+
if (typeScopedFlowCommands.has(name)) {
|
|
2492
|
+
return void 0;
|
|
2493
|
+
}
|
|
2494
|
+
const id = flowArgs[0];
|
|
2495
|
+
return typeof id === "string" || import_node_buffer3.Buffer.isBuffer(id) ? id : void 0;
|
|
2496
|
+
}
|
|
2497
|
+
function bitopRoutingKey(args) {
|
|
2498
|
+
if (args.length < 4) {
|
|
2499
|
+
return void 0;
|
|
2500
|
+
}
|
|
2501
|
+
return singleShardKey(args.slice(2));
|
|
2502
|
+
}
|
|
2503
|
+
function streamReadRoutingKey(args) {
|
|
2504
|
+
const streamsIndex = args.findIndex((arg) => commandPart(arg) === "STREAMS");
|
|
2505
|
+
if (streamsIndex < 0) {
|
|
2506
|
+
return void 0;
|
|
2507
|
+
}
|
|
2508
|
+
const streamArgs = args.slice(streamsIndex + 1);
|
|
2509
|
+
if (streamArgs.length === 0 || streamArgs.length % 2 !== 0) {
|
|
2510
|
+
return void 0;
|
|
2511
|
+
}
|
|
2512
|
+
return singleShardKey(streamArgs.slice(0, streamArgs.length / 2));
|
|
2513
|
+
}
|
|
2514
|
+
function flowPartitionRoutingKey(args, start) {
|
|
2515
|
+
for (let index = start; index < args.length; index += 1) {
|
|
2516
|
+
const token = commandPart(args[index]);
|
|
2517
|
+
if (token === "PARTITION") {
|
|
2518
|
+
const key = args[index + 1];
|
|
2519
|
+
return typeof key === "string" || import_node_buffer3.Buffer.isBuffer(key) ? key : void 0;
|
|
2520
|
+
}
|
|
2521
|
+
if (token === "PARTITIONS") {
|
|
2522
|
+
const count = Number(args[index + 1]);
|
|
2523
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
2524
|
+
return void 0;
|
|
2525
|
+
}
|
|
2526
|
+
return singleShardKey(args.slice(index + 2, index + 2 + count));
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
return void 0;
|
|
2530
|
+
}
|
|
2531
|
+
function singleShardKey(keys) {
|
|
2532
|
+
const usable = keys.filter((key) => typeof key === "string" || import_node_buffer3.Buffer.isBuffer(key));
|
|
2533
|
+
if (usable.length === 0) {
|
|
2534
|
+
return void 0;
|
|
2535
|
+
}
|
|
2536
|
+
const first = usable[0];
|
|
2537
|
+
if (first == null) {
|
|
2538
|
+
return void 0;
|
|
2539
|
+
}
|
|
2540
|
+
const firstSlot = RoutingTopology.slotForKey(first);
|
|
2541
|
+
return usable.every((key) => RoutingTopology.slotForKey(key) === firstSlot) ? first : void 0;
|
|
2542
|
+
}
|
|
2543
|
+
function commandName(args) {
|
|
2544
|
+
const first = commandPart(args[0]);
|
|
2545
|
+
if (first == null) {
|
|
2546
|
+
return void 0;
|
|
2547
|
+
}
|
|
2548
|
+
if (first === "FLOW" && args.length > 1) {
|
|
2549
|
+
const second = commandPart(args[1]);
|
|
2550
|
+
return second == null ? first : `${first}.${second}`;
|
|
2551
|
+
}
|
|
2552
|
+
if (first === "CLIENT" && args.length > 1) {
|
|
2553
|
+
const second = commandPart(args[1]);
|
|
2554
|
+
return second == null ? first : `${first}.${second}`;
|
|
2555
|
+
}
|
|
2556
|
+
if (first === "CLUSTER" && args.length > 1) {
|
|
2557
|
+
const second = commandPart(args[1]);
|
|
2558
|
+
return second == null ? first : `${first}.${second}`;
|
|
2559
|
+
}
|
|
2560
|
+
return first;
|
|
2561
|
+
}
|
|
2562
|
+
function commandPart(value) {
|
|
2563
|
+
if (typeof value === "string") {
|
|
2564
|
+
return value.toUpperCase();
|
|
2565
|
+
}
|
|
2566
|
+
if (import_node_buffer3.Buffer.isBuffer(value)) {
|
|
2567
|
+
return value.toString("utf8").toUpperCase();
|
|
2568
|
+
}
|
|
2569
|
+
return void 0;
|
|
2570
|
+
}
|
|
2571
|
+
function isPlainObject2(value) {
|
|
2572
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !import_node_buffer3.Buffer.isBuffer(value);
|
|
2573
|
+
}
|
|
2574
|
+
function getField(source, ...keys) {
|
|
2575
|
+
if (source instanceof Map) {
|
|
2576
|
+
for (const key of keys) {
|
|
2577
|
+
if (source.has(key)) return source.get(key);
|
|
2578
|
+
const bufferKey = import_node_buffer3.Buffer.from(key);
|
|
2579
|
+
for (const [itemKey, value] of source.entries()) {
|
|
2580
|
+
if (import_node_buffer3.Buffer.isBuffer(itemKey) && itemKey.equals(bufferKey)) {
|
|
2581
|
+
return value;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
return void 0;
|
|
2586
|
+
}
|
|
2587
|
+
if (isPlainObject2(source)) {
|
|
2588
|
+
for (const key of keys) {
|
|
2589
|
+
if (key in source) return source[key];
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
return void 0;
|
|
2593
|
+
}
|
|
2594
|
+
function textOrUndefined(value) {
|
|
2595
|
+
if (typeof value === "string") {
|
|
2596
|
+
return value;
|
|
2597
|
+
}
|
|
2598
|
+
if (import_node_buffer3.Buffer.isBuffer(value)) {
|
|
2599
|
+
return value.toString("utf8");
|
|
2600
|
+
}
|
|
2601
|
+
return void 0;
|
|
2602
|
+
}
|
|
2603
|
+
function numberOrUndefined(value) {
|
|
2604
|
+
return typeof value === "number" && Number.isInteger(value) ? value : void 0;
|
|
2605
|
+
}
|
|
2606
|
+
function endpointFromRange(item) {
|
|
2607
|
+
const endpointValue = getField(item, "endpoint");
|
|
2608
|
+
const raw = isPlainObject2(endpointValue) || endpointValue instanceof Map ? endpointValue : item;
|
|
2609
|
+
const host = textOrUndefined(getField(raw, "host", "native_host"));
|
|
2610
|
+
const nativePort = numberOrUndefined(getField(raw, "native_port"));
|
|
2611
|
+
if (host == null || nativePort == null) {
|
|
2612
|
+
throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
|
|
2613
|
+
}
|
|
2614
|
+
const nativeTlsPort = numberOrUndefined(getField(raw, "native_tls_port"));
|
|
2615
|
+
return {
|
|
2616
|
+
host,
|
|
2617
|
+
nativePort,
|
|
2618
|
+
node: textOrUndefined(getField(raw, "node", "leader_node", "owner_node")) ?? host,
|
|
2619
|
+
...nativeTlsPort == null ? {} : { nativeTlsPort }
|
|
2620
|
+
};
|
|
2621
|
+
}
|
|
2622
|
+
function endpointFromUrl(url) {
|
|
2623
|
+
const parsed = parseFerricUrl2(url);
|
|
2624
|
+
return {
|
|
2625
|
+
host: parsed.host,
|
|
2626
|
+
nativePort: parsed.port,
|
|
2627
|
+
node: parsed.host,
|
|
2628
|
+
...parsed.tls ? { nativeTlsPort: parsed.port } : {}
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
function parseFerricUrl2(value) {
|
|
2632
|
+
const url = new URL(value);
|
|
2633
|
+
if (url.protocol !== "ferric:" && url.protocol !== "ferrics:") {
|
|
2634
|
+
throw new FerricStoreError(`unsupported FerricStore URL scheme: ${url.protocol}`);
|
|
2635
|
+
}
|
|
2636
|
+
return {
|
|
2637
|
+
host: url.hostname || "127.0.0.1",
|
|
2638
|
+
...url.password === "" ? {} : { password: decodeURIComponent(url.password) },
|
|
2639
|
+
port: Number(url.port || (url.protocol === "ferrics:" ? 6389 : 6388)),
|
|
2640
|
+
tls: url.protocol === "ferrics:",
|
|
2641
|
+
...url.username === "" ? {} : { username: decodeURIComponent(url.username) }
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2644
|
+
function endpointKeyFor(endpoint) {
|
|
2645
|
+
return `${endpoint.host.toLowerCase()}:${endpoint.nativePort}`;
|
|
2646
|
+
}
|
|
2647
|
+
function urlFromEndpoint(endpoint, useTls) {
|
|
2648
|
+
const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
|
|
2649
|
+
const host = endpoint.host.includes(":") && !endpoint.host.startsWith("[") ? `[${endpoint.host}]` : endpoint.host;
|
|
2650
|
+
return `${useTls ? "ferrics" : "ferric"}://${host}:${port}`;
|
|
2651
|
+
}
|
|
2652
|
+
function nativeOnlyOptions(options) {
|
|
2653
|
+
const nativeOptions = { ...options };
|
|
2654
|
+
delete nativeOptions.endpointPolicy;
|
|
2655
|
+
delete nativeOptions.endpointValidator;
|
|
2656
|
+
delete nativeOptions.haRouting;
|
|
2657
|
+
delete nativeOptions.seeds;
|
|
2658
|
+
delete nativeOptions.trustedHosts;
|
|
2659
|
+
delete nativeOptions.warmConnections;
|
|
2660
|
+
return nativeOptions;
|
|
2661
|
+
}
|
|
2662
|
+
function withSeedAuthDefaults(urls, options) {
|
|
2663
|
+
const next = { ...options };
|
|
2664
|
+
for (const url of urls) {
|
|
2665
|
+
const parsed = parseFerricUrl2(url);
|
|
2666
|
+
if (next.username == null && parsed.username != null) {
|
|
2667
|
+
next.username = parsed.username;
|
|
2668
|
+
}
|
|
2669
|
+
if (next.password == null && parsed.password != null) {
|
|
2670
|
+
next.password = parsed.password;
|
|
2671
|
+
}
|
|
2672
|
+
if (next.username != null && next.password != null) {
|
|
2673
|
+
break;
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
return next;
|
|
2677
|
+
}
|
|
2678
|
+
function isRetryableRouteError(error) {
|
|
2679
|
+
if (!(error instanceof Error)) {
|
|
2680
|
+
return false;
|
|
2681
|
+
}
|
|
2682
|
+
const message = error.message.toLowerCase();
|
|
2683
|
+
return message.includes("connection closed") || message.includes("connection is closed") || message.includes("shard not available") || message.includes("leader") || message.includes("route");
|
|
2684
|
+
}
|
|
2685
|
+
function normalizedHostSet(hosts) {
|
|
2686
|
+
return new Set(hosts.filter((host) => host != null && host !== "").map((host) => host.toLowerCase()));
|
|
2687
|
+
}
|
|
2688
|
+
function hashTagOrKey(key) {
|
|
2689
|
+
const start = key.indexOf("{");
|
|
2690
|
+
if (start < 0) {
|
|
2691
|
+
return key;
|
|
2692
|
+
}
|
|
2693
|
+
const end = key.indexOf("}", start + 1);
|
|
2694
|
+
return end > start + 1 ? key.slice(start + 1, end) : key;
|
|
2695
|
+
}
|
|
2696
|
+
function flowHashTag(rest, fallbackKey) {
|
|
2697
|
+
const end = rest.indexOf("}");
|
|
2698
|
+
return end > 0 ? rest.slice(0, end) : hashTagOrKey(fallbackKey);
|
|
2699
|
+
}
|
|
2700
|
+
var crc32Table = new Uint32Array(256);
|
|
2701
|
+
for (let index = 0; index < 256; index += 1) {
|
|
2702
|
+
let value = index;
|
|
2703
|
+
for (let bit = 0; bit < 8; bit += 1) {
|
|
2704
|
+
value = (value & 1) !== 0 ? 3988292384 ^ value >>> 1 : value >>> 1;
|
|
2705
|
+
}
|
|
2706
|
+
crc32Table[index] = value >>> 0;
|
|
2707
|
+
}
|
|
2708
|
+
function crc32(buffer) {
|
|
2709
|
+
let value = 4294967295;
|
|
2710
|
+
for (const byte of buffer) {
|
|
2711
|
+
value = value >>> 8 ^ (crc32Table[(value ^ byte) & 255] ?? 0);
|
|
2712
|
+
}
|
|
2713
|
+
return (value ^ 4294967295) >>> 0;
|
|
2714
|
+
}
|
|
2715
|
+
var firstKeyCommands = /* @__PURE__ */ new Set([
|
|
2716
|
+
"BITCOUNT",
|
|
2717
|
+
"BITFIELD",
|
|
2718
|
+
"BITPOS",
|
|
2719
|
+
"CAS",
|
|
2720
|
+
"EXISTS",
|
|
2721
|
+
"EXPIRE",
|
|
2722
|
+
"EXPIREAT",
|
|
2723
|
+
"FETCH_OR_COMPUTE",
|
|
2724
|
+
"FETCH_OR_COMPUTE_ERROR",
|
|
2725
|
+
"FETCH_OR_COMPUTE_RESULT",
|
|
2726
|
+
"FERRICSTORE.KEY_INFO",
|
|
2727
|
+
"GET",
|
|
2728
|
+
"GETBIT",
|
|
2729
|
+
"GETDEL",
|
|
2730
|
+
"GETEX",
|
|
2731
|
+
"HDEL",
|
|
2732
|
+
"HEXISTS",
|
|
2733
|
+
"HGET",
|
|
2734
|
+
"HGETALL",
|
|
2735
|
+
"HINCRBY",
|
|
2736
|
+
"HKEYS",
|
|
2737
|
+
"HLEN",
|
|
2738
|
+
"HMGET",
|
|
2739
|
+
"HMSET",
|
|
2740
|
+
"HSET",
|
|
2741
|
+
"HVALS",
|
|
2742
|
+
"LOCK",
|
|
2743
|
+
"LPOP",
|
|
2744
|
+
"LPUSH",
|
|
2745
|
+
"LRANGE",
|
|
2746
|
+
"LREM",
|
|
2747
|
+
"RATELIMIT.ADD",
|
|
2748
|
+
"RPOP",
|
|
2749
|
+
"RPUSH",
|
|
2750
|
+
"SADD",
|
|
2751
|
+
"SCARD",
|
|
2752
|
+
"SISMEMBER",
|
|
2753
|
+
"SMEMBERS",
|
|
2754
|
+
"SREM",
|
|
2755
|
+
"SET",
|
|
2756
|
+
"SETBIT",
|
|
2757
|
+
"STRLEN",
|
|
2758
|
+
"TTL",
|
|
2759
|
+
"TYPE",
|
|
2760
|
+
"UNLINK",
|
|
2761
|
+
"UNLOCK",
|
|
2762
|
+
"XADD",
|
|
2763
|
+
"XLEN",
|
|
2764
|
+
"XRANGE",
|
|
2765
|
+
"ZADD",
|
|
2766
|
+
"ZCARD",
|
|
2767
|
+
"ZRANGE",
|
|
2768
|
+
"ZREM",
|
|
2769
|
+
"ZSCORE"
|
|
2770
|
+
]);
|
|
2771
|
+
var typeScopedFlowCommands = /* @__PURE__ */ new Set([
|
|
2772
|
+
"FLOW.APPROVAL.LIST",
|
|
2773
|
+
"FLOW.ATTRIBUTE_VALUES",
|
|
2774
|
+
"FLOW.ATTRIBUTES",
|
|
2775
|
+
"FLOW.BUDGET.LIST",
|
|
2776
|
+
"FLOW.FAILURES",
|
|
2777
|
+
"FLOW.GOVERNANCE.OVERVIEW",
|
|
2778
|
+
"FLOW.INFO",
|
|
2779
|
+
"FLOW.LIMIT.LIST",
|
|
2780
|
+
"FLOW.LIST",
|
|
2781
|
+
"FLOW.POLICY.GET",
|
|
2782
|
+
"FLOW.POLICY.SET",
|
|
2783
|
+
"FLOW.RETENTION_CLEANUP",
|
|
2784
|
+
"FLOW.SCHEDULE.FIRE_DUE",
|
|
2785
|
+
"FLOW.SCHEDULE.LIST",
|
|
2786
|
+
"FLOW.SEARCH",
|
|
2787
|
+
"FLOW.STATS",
|
|
2788
|
+
"FLOW.STUCK",
|
|
2789
|
+
"FLOW.TERMINALS"
|
|
2790
|
+
]);
|
|
2791
|
+
|
|
1813
2792
|
// src/codecs.ts
|
|
1814
2793
|
var RawCodec = class {
|
|
1815
2794
|
encode(value) {
|
|
@@ -2023,7 +3002,7 @@ function parseKvResponse(value) {
|
|
|
2023
3002
|
return { value };
|
|
2024
3003
|
}
|
|
2025
3004
|
function autoPartitionKeyForId(id) {
|
|
2026
|
-
return `${AUTO_PARTITION_PREFIX}${
|
|
3005
|
+
return `${AUTO_PARTITION_PREFIX}${crc322(Buffer.from(id)) % AUTO_PARTITION_BUCKETS}`;
|
|
2027
3006
|
}
|
|
2028
3007
|
function expandManyResponse(value, count) {
|
|
2029
3008
|
if (Array.isArray(value) && value.length === count) {
|
|
@@ -2093,7 +3072,7 @@ function coerceDiagnosticValue(value) {
|
|
|
2093
3072
|
}
|
|
2094
3073
|
return value;
|
|
2095
3074
|
}
|
|
2096
|
-
function
|
|
3075
|
+
function crc322(buffer) {
|
|
2097
3076
|
let crc = 4294967295;
|
|
2098
3077
|
for (const byte of buffer) {
|
|
2099
3078
|
crc ^= byte;
|
|
@@ -3019,14 +3998,14 @@ function claimedItemFromResp(value, codec) {
|
|
|
3019
3998
|
const partition = tuple[1] == null ? null : bytes(tuple[1]);
|
|
3020
3999
|
const leaseToken = bytes(tuple[2]);
|
|
3021
4000
|
const fencingToken = integer(tuple[3]);
|
|
3022
|
-
const attrs = tuple[5] ?? (
|
|
4001
|
+
const attrs = tuple[5] ?? (isPlainObject3(tuple[4]) ? tuple[4] : void 0);
|
|
3023
4002
|
const item = {
|
|
3024
4003
|
id: text(id),
|
|
3025
4004
|
partitionKey: optionalString(partition),
|
|
3026
4005
|
leaseToken,
|
|
3027
4006
|
fencingToken,
|
|
3028
4007
|
runState: optionalString(tuple[4]),
|
|
3029
|
-
attributes:
|
|
4008
|
+
attributes: isPlainObject3(attrs) ? attrs : void 0,
|
|
3030
4009
|
type: "",
|
|
3031
4010
|
state: "running"
|
|
3032
4011
|
};
|
|
@@ -3146,9 +4125,9 @@ function decodeValues(value, codec) {
|
|
|
3146
4125
|
}
|
|
3147
4126
|
function plainObjectField(value, key) {
|
|
3148
4127
|
const item = field(value, key);
|
|
3149
|
-
return
|
|
4128
|
+
return isPlainObject3(item) ? item : void 0;
|
|
3150
4129
|
}
|
|
3151
|
-
function
|
|
4130
|
+
function isPlainObject3(value) {
|
|
3152
4131
|
return typeof value === "object" && value != null && !Buffer.isBuffer(value) && !(value instanceof Uint8Array) && !Array.isArray(value);
|
|
3153
4132
|
}
|
|
3154
4133
|
|
|
@@ -3200,7 +4179,18 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3200
4179
|
}
|
|
3201
4180
|
static async fromUrl(url, options = {}) {
|
|
3202
4181
|
const reconnectOptions = options.reconnect ?? options.nativeOptions?.autoReconnect ?? true;
|
|
3203
|
-
const
|
|
4182
|
+
const nativeOptions = options.nativeOptions ?? {};
|
|
4183
|
+
const seeds = nativeOptions.seeds ?? [];
|
|
4184
|
+
const createExecutor = async () => nativeOptions.haRouting === true || seeds.length > 0 ? await TopologyNativeAdapterPool.fromUrls([url, ...seeds], nativeOptions) : await NativeAdapter.fromUrl(url, nativeOptions);
|
|
4185
|
+
const executor = reconnectOptions === false ? await createExecutor() : new ReconnectingExecutor(createExecutor, reconnectOptions === true ? {} : reconnectOptions);
|
|
4186
|
+
return new _FerricStoreClient(executor, options);
|
|
4187
|
+
}
|
|
4188
|
+
static async fromUrls(urls, options = {}) {
|
|
4189
|
+
if (urls.length === 0) {
|
|
4190
|
+
throw new Error("FerricStoreClient.fromUrls requires at least one URL");
|
|
4191
|
+
}
|
|
4192
|
+
const reconnectOptions = options.reconnect ?? options.nativeOptions?.autoReconnect ?? true;
|
|
4193
|
+
const createExecutor = async () => await TopologyNativeAdapterPool.fromUrls(urls, options.nativeOptions);
|
|
3204
4194
|
const executor = reconnectOptions === false ? await createExecutor() : new ReconnectingExecutor(createExecutor, reconnectOptions === true ? {} : reconnectOptions);
|
|
3205
4195
|
return new _FerricStoreClient(executor, options);
|
|
3206
4196
|
}
|
|
@@ -3216,6 +4206,18 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3216
4206
|
async close() {
|
|
3217
4207
|
await this.executor.close?.();
|
|
3218
4208
|
}
|
|
4209
|
+
async refreshTopology() {
|
|
4210
|
+
if (this.executor.refreshTopology == null) {
|
|
4211
|
+
throw new Error("topology refresh requires a topology-aware native executor");
|
|
4212
|
+
}
|
|
4213
|
+
return await this.executor.refreshTopology();
|
|
4214
|
+
}
|
|
4215
|
+
async route(key) {
|
|
4216
|
+
if (this.executor.route == null) {
|
|
4217
|
+
throw new Error("route lookup requires a topology-aware native executor");
|
|
4218
|
+
}
|
|
4219
|
+
return await this.executor.route(key);
|
|
4220
|
+
}
|
|
3219
4221
|
async ping(message) {
|
|
3220
4222
|
return await this.command("PING", ...message == null ? [] : [message]);
|
|
3221
4223
|
}
|
|
@@ -3278,7 +4280,7 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3278
4280
|
return response == null ? null : text(response);
|
|
3279
4281
|
}
|
|
3280
4282
|
async clientInfo() {
|
|
3281
|
-
return
|
|
4283
|
+
return infoText(await this.command("CLIENT", "INFO"));
|
|
3282
4284
|
}
|
|
3283
4285
|
async clientList(options = {}) {
|
|
3284
4286
|
return text(await this.command("CLIENT", "LIST", ...options.type == null ? [] : ["TYPE", options.type]));
|
|
@@ -3333,7 +4335,7 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3333
4335
|
return Number(await this.command("PUBSUB", "NUMPAT"));
|
|
3334
4336
|
}
|
|
3335
4337
|
async aclSetUser(username, rules) {
|
|
3336
|
-
return okResponse(await this.command("ACL", "SETUSER", username, ...rules));
|
|
4338
|
+
return okResponse(await this.command("ACL", "SETUSER", username, ...ruleArgs(rules)));
|
|
3337
4339
|
}
|
|
3338
4340
|
async aclDelUser(...usernames) {
|
|
3339
4341
|
return Number(await this.command("ACL", "DELUSER", ...usernames));
|
|
@@ -3344,6 +4346,9 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3344
4346
|
async aclList() {
|
|
3345
4347
|
return arrayResponse(await this.command("ACL", "LIST"));
|
|
3346
4348
|
}
|
|
4349
|
+
async aclListUsers() {
|
|
4350
|
+
return await this.aclList();
|
|
4351
|
+
}
|
|
3347
4352
|
async aclWhoami() {
|
|
3348
4353
|
return text(await this.command("ACL", "WHOAMI"));
|
|
3349
4354
|
}
|
|
@@ -3439,6 +4444,107 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3439
4444
|
async ferricstoreDoctor(...args) {
|
|
3440
4445
|
return await this.command("FERRICSTORE.DOCTOR", ...args);
|
|
3441
4446
|
}
|
|
4447
|
+
async capabilities() {
|
|
4448
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.CAPABILITIES"));
|
|
4449
|
+
}
|
|
4450
|
+
async ensureNamespace(prefix, attrs = {}) {
|
|
4451
|
+
return normalizeAdminResponse(
|
|
4452
|
+
await this.command("FERRICSTORE.NAMESPACE", "ENSURE", prefix, ...managementPairArgs(attrs))
|
|
4453
|
+
);
|
|
4454
|
+
}
|
|
4455
|
+
async getNamespace(prefix) {
|
|
4456
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.NAMESPACE", "GET", prefix));
|
|
4457
|
+
}
|
|
4458
|
+
async listNamespaces() {
|
|
4459
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.NAMESPACE", "LIST"));
|
|
4460
|
+
}
|
|
4461
|
+
async deleteNamespace(prefix) {
|
|
4462
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.NAMESPACE", "DELETE", prefix));
|
|
4463
|
+
}
|
|
4464
|
+
async setQuota(namespace, quotaSpec = {}) {
|
|
4465
|
+
return normalizeAdminResponse(
|
|
4466
|
+
await this.command("FERRICSTORE.QUOTA", "SET", namespace, ...managementPairArgs(quotaSpec))
|
|
4467
|
+
);
|
|
4468
|
+
}
|
|
4469
|
+
async getQuota(namespace) {
|
|
4470
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.QUOTA", "GET", namespace));
|
|
4471
|
+
}
|
|
4472
|
+
async quotaUsage(namespace) {
|
|
4473
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.QUOTA", "USAGE", namespace));
|
|
4474
|
+
}
|
|
4475
|
+
async clusterInfo() {
|
|
4476
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.TELEMETRY", "CLUSTER_INFO"));
|
|
4477
|
+
}
|
|
4478
|
+
async namespaceUsage(prefix) {
|
|
4479
|
+
return normalizeAdminResponse(
|
|
4480
|
+
await this.command("FERRICSTORE.TELEMETRY", "NAMESPACE_USAGE", prefix)
|
|
4481
|
+
);
|
|
4482
|
+
}
|
|
4483
|
+
async flowQuery(attrs = {}) {
|
|
4484
|
+
const response = normalizeAdminResponse(
|
|
4485
|
+
await this.command("FERRICSTORE.TELEMETRY", "FLOW_QUERY", ...managementPairArgs(attrs))
|
|
4486
|
+
);
|
|
4487
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4488
|
+
}
|
|
4489
|
+
async flowHistory(id, attrs = {}) {
|
|
4490
|
+
const response = normalizeAdminResponse(
|
|
4491
|
+
await this.command("FERRICSTORE.TELEMETRY", "FLOW_HISTORY", id, ...managementPairArgs(attrs))
|
|
4492
|
+
);
|
|
4493
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4494
|
+
}
|
|
4495
|
+
async invocationDefinitionPut(definition, options = {}) {
|
|
4496
|
+
return normalizeAdminResponse(
|
|
4497
|
+
await this.command(
|
|
4498
|
+
...commandWithRequestContext(
|
|
4499
|
+
"INVOCATION.DEFINITION.PUT",
|
|
4500
|
+
[jsonArg(definition)],
|
|
4501
|
+
options.requestContext
|
|
4502
|
+
)
|
|
4503
|
+
)
|
|
4504
|
+
);
|
|
4505
|
+
}
|
|
4506
|
+
async invocationDefinitionGet(name, options = {}) {
|
|
4507
|
+
return normalizeAdminResponse(
|
|
4508
|
+
await this.command(
|
|
4509
|
+
...commandWithRequestContext("INVOCATION.DEFINITION.GET", [name], options.requestContext)
|
|
4510
|
+
)
|
|
4511
|
+
);
|
|
4512
|
+
}
|
|
4513
|
+
async invocationDefinitionList(options = {}) {
|
|
4514
|
+
const response = normalizeAdminResponse(
|
|
4515
|
+
await this.command(
|
|
4516
|
+
...commandWithRequestContext("INVOCATION.DEFINITION.LIST", [], options.requestContext)
|
|
4517
|
+
)
|
|
4518
|
+
);
|
|
4519
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4520
|
+
}
|
|
4521
|
+
async invocationCreate(name, attrs, options = {}) {
|
|
4522
|
+
const envelope = { attrs };
|
|
4523
|
+
if (options.context != null) {
|
|
4524
|
+
envelope.context = options.context;
|
|
4525
|
+
}
|
|
4526
|
+
if (options.idempotencyKey != null) {
|
|
4527
|
+
envelope.idempotency_key = options.idempotencyKey;
|
|
4528
|
+
}
|
|
4529
|
+
return normalizeAdminResponse(
|
|
4530
|
+
await this.command(
|
|
4531
|
+
...commandWithRequestContext("INVOCATION.CREATE", [name, jsonArg(envelope)], options.requestContext)
|
|
4532
|
+
)
|
|
4533
|
+
);
|
|
4534
|
+
}
|
|
4535
|
+
async invocationGet(id, options = {}) {
|
|
4536
|
+
return normalizeAdminResponse(
|
|
4537
|
+
await this.command(...commandWithRequestContext("INVOCATION.GET", [id], options.requestContext))
|
|
4538
|
+
);
|
|
4539
|
+
}
|
|
4540
|
+
async invocationPartitionList(name, options = {}) {
|
|
4541
|
+
const args = [name];
|
|
4542
|
+
append(args, "SCOPE", options.scope);
|
|
4543
|
+
const response = normalizeAdminResponse(
|
|
4544
|
+
await this.command(...commandWithRequestContext("INVOCATION.PARTITION.LIST", args, options.requestContext))
|
|
4545
|
+
);
|
|
4546
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4547
|
+
}
|
|
3442
4548
|
async create(id, options) {
|
|
3443
4549
|
const currentNowMs = options.nowMs ?? nowMs();
|
|
3444
4550
|
const args = [
|
|
@@ -3471,7 +4577,6 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3471
4577
|
async enqueue(id, options) {
|
|
3472
4578
|
return await this.create(id, {
|
|
3473
4579
|
...options,
|
|
3474
|
-
priority: options.priority ?? 0,
|
|
3475
4580
|
state: options.state ?? "queued"
|
|
3476
4581
|
});
|
|
3477
4582
|
}
|
|
@@ -3483,7 +4588,6 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3483
4588
|
return await this.createMany(options.partitionKey, items, {
|
|
3484
4589
|
...options,
|
|
3485
4590
|
independent: options.independent ?? true,
|
|
3486
|
-
priority: options.priority ?? 0,
|
|
3487
4591
|
state: options.state ?? "queued"
|
|
3488
4592
|
});
|
|
3489
4593
|
}
|
|
@@ -3498,7 +4602,6 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3498
4602
|
const response = await this.createMany(bucket, groupItems, {
|
|
3499
4603
|
...options,
|
|
3500
4604
|
independent: options.independent ?? true,
|
|
3501
|
-
priority: options.priority ?? 0,
|
|
3502
4605
|
state: options.state ?? "queued"
|
|
3503
4606
|
});
|
|
3504
4607
|
const expanded = expandManyResponse(response, indexedItems.length);
|
|
@@ -3651,8 +4754,7 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3651
4754
|
...options,
|
|
3652
4755
|
includeState: options.includeState ?? false,
|
|
3653
4756
|
jobOnly: true,
|
|
3654
|
-
limit: options.limit ?? 100
|
|
3655
|
-
priority: options.priority ?? 0
|
|
4757
|
+
limit: options.limit ?? 100
|
|
3656
4758
|
});
|
|
3657
4759
|
}
|
|
3658
4760
|
async reclaim(type, options) {
|
|
@@ -3919,6 +5021,14 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3919
5021
|
async list(type, options = {}) {
|
|
3920
5022
|
return await this.indexQuery("FLOW.LIST", type, options);
|
|
3921
5023
|
}
|
|
5024
|
+
async search(type, options = {}) {
|
|
5025
|
+
const args = ["FLOW.SEARCH", type];
|
|
5026
|
+
appendReadOptions(args, options);
|
|
5027
|
+
appendAttributes(args, options.attributes);
|
|
5028
|
+
appendSearchStateMeta(args, options.state, options.stateMeta);
|
|
5029
|
+
const response = await this.command(...args);
|
|
5030
|
+
return Array.isArray(response) ? this.records(response) : [];
|
|
5031
|
+
}
|
|
3922
5032
|
async terminals(type, options = {}) {
|
|
3923
5033
|
return await this.indexQuery("FLOW.TERMINALS", type, options);
|
|
3924
5034
|
}
|
|
@@ -3995,9 +5105,14 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3995
5105
|
const args = ["FLOW.POLICY.SET", type];
|
|
3996
5106
|
append(args, "INDEXED_STATE_META", options.indexedStateMeta);
|
|
3997
5107
|
append(args, "STATE", options.state);
|
|
5108
|
+
appendPolicyMode(args, options.state, options.mode);
|
|
3998
5109
|
if (options.retry != null) {
|
|
3999
5110
|
appendRetryPolicy(args, options.retry);
|
|
4000
5111
|
}
|
|
5112
|
+
for (const [state, policy] of Object.entries(options.states ?? {})) {
|
|
5113
|
+
args.push("STATE", state);
|
|
5114
|
+
appendFlowStatePolicy(args, policy);
|
|
5115
|
+
}
|
|
4001
5116
|
append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
|
|
4002
5117
|
return await this.command(...args);
|
|
4003
5118
|
}
|
|
@@ -4088,6 +5203,18 @@ var ErrorMappingExecutor = class {
|
|
|
4088
5203
|
throwMapped(error);
|
|
4089
5204
|
}
|
|
4090
5205
|
}
|
|
5206
|
+
async refreshTopology() {
|
|
5207
|
+
if (this.executor.refreshTopology == null) {
|
|
5208
|
+
throw new Error("topology refresh requires a topology-aware native executor");
|
|
5209
|
+
}
|
|
5210
|
+
return await this.executor.refreshTopology();
|
|
5211
|
+
}
|
|
5212
|
+
async route(key) {
|
|
5213
|
+
if (this.executor.route == null) {
|
|
5214
|
+
throw new Error("route lookup requires a topology-aware native executor");
|
|
5215
|
+
}
|
|
5216
|
+
return await this.executor.route(key);
|
|
5217
|
+
}
|
|
4091
5218
|
async close() {
|
|
4092
5219
|
await this.executor.close?.();
|
|
4093
5220
|
}
|
|
@@ -4123,6 +5250,18 @@ var AutoBatchExecutor = class {
|
|
|
4123
5250
|
}
|
|
4124
5251
|
return await Promise.all(commands.map((command) => this.executor.executeCommand(...command)));
|
|
4125
5252
|
}
|
|
5253
|
+
async refreshTopology() {
|
|
5254
|
+
if (this.executor.refreshTopology == null) {
|
|
5255
|
+
throw new Error("topology refresh requires a topology-aware native executor");
|
|
5256
|
+
}
|
|
5257
|
+
return await this.executor.refreshTopology();
|
|
5258
|
+
}
|
|
5259
|
+
async route(key) {
|
|
5260
|
+
if (this.executor.route == null) {
|
|
5261
|
+
throw new Error("route lookup requires a topology-aware native executor");
|
|
5262
|
+
}
|
|
5263
|
+
return await this.executor.route(key);
|
|
5264
|
+
}
|
|
4126
5265
|
async close() {
|
|
4127
5266
|
this.scheduled = false;
|
|
4128
5267
|
if (this.timer != null) {
|
|
@@ -4283,7 +5422,7 @@ var neverAutoBatchCommandPrefixes = /* @__PURE__ */ new Set([
|
|
|
4283
5422
|
]);
|
|
4284
5423
|
var neverAutoBatchCommands = /* @__PURE__ */ new Set(["FLOW.CLAIM_DUE", "FLOW.RECLAIM"]);
|
|
4285
5424
|
function autoBatchCommandAllowed(command, mode) {
|
|
4286
|
-
const name =
|
|
5425
|
+
const name = commandName2(command);
|
|
4287
5426
|
if (name == null || neverAutoBatchCommands.has(name)) {
|
|
4288
5427
|
return false;
|
|
4289
5428
|
}
|
|
@@ -4293,18 +5432,18 @@ function autoBatchCommandAllowed(command, mode) {
|
|
|
4293
5432
|
}
|
|
4294
5433
|
return mode === "all" || safeAutoBatchCommands.has(name);
|
|
4295
5434
|
}
|
|
4296
|
-
function
|
|
4297
|
-
const first =
|
|
5435
|
+
function commandName2(command) {
|
|
5436
|
+
const first = commandPart2(command[0]);
|
|
4298
5437
|
if (first == null) {
|
|
4299
5438
|
return null;
|
|
4300
5439
|
}
|
|
4301
5440
|
if (first === "FLOW" && command.length > 1) {
|
|
4302
|
-
const second =
|
|
5441
|
+
const second = commandPart2(command[1]);
|
|
4303
5442
|
return second == null ? first : `${first}.${second}`;
|
|
4304
5443
|
}
|
|
4305
5444
|
return first;
|
|
4306
5445
|
}
|
|
4307
|
-
function
|
|
5446
|
+
function commandPart2(value) {
|
|
4308
5447
|
if (typeof value === "string") {
|
|
4309
5448
|
return value.toUpperCase();
|
|
4310
5449
|
}
|
|
@@ -4329,6 +5468,90 @@ function appendStateMeta(args, stateMeta) {
|
|
|
4329
5468
|
args.push("STATE_META", name, value);
|
|
4330
5469
|
}
|
|
4331
5470
|
}
|
|
5471
|
+
function appendAttributes(args, attributes) {
|
|
5472
|
+
for (const [name, value] of Object.entries(attributes ?? {})) {
|
|
5473
|
+
args.push("ATTRIBUTE", name, value);
|
|
5474
|
+
}
|
|
5475
|
+
}
|
|
5476
|
+
function appendSearchStateMeta(args, state, stateMeta) {
|
|
5477
|
+
const entries = Object.entries(stateMeta ?? {});
|
|
5478
|
+
if (entries.length === 0) {
|
|
5479
|
+
return;
|
|
5480
|
+
}
|
|
5481
|
+
if (entries.every(([, value]) => isPlainObject4(value))) {
|
|
5482
|
+
for (const [metaState, values] of entries) {
|
|
5483
|
+
args.push("STATE_META", metaState, values);
|
|
5484
|
+
}
|
|
5485
|
+
return;
|
|
5486
|
+
}
|
|
5487
|
+
if (state == null) {
|
|
5488
|
+
throw new Error("search stateMeta filters require state or nested state metadata");
|
|
5489
|
+
}
|
|
5490
|
+
args.push("STATE_META", state, stateMeta);
|
|
5491
|
+
}
|
|
5492
|
+
function normalizeAdminResponse(value) {
|
|
5493
|
+
return normalizeRefMeta(value);
|
|
5494
|
+
}
|
|
5495
|
+
function jsonArg(value) {
|
|
5496
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
5497
|
+
}
|
|
5498
|
+
function commandWithRequestContext(command, args, requestContext) {
|
|
5499
|
+
const commandArgs = [command, ...args];
|
|
5500
|
+
if (requestContext != null) {
|
|
5501
|
+
commandArgs.push("REQUEST_CONTEXT", requestContext);
|
|
5502
|
+
}
|
|
5503
|
+
return commandArgs;
|
|
5504
|
+
}
|
|
5505
|
+
function infoText(value) {
|
|
5506
|
+
if (typeof value === "string" || Buffer.isBuffer(value)) {
|
|
5507
|
+
return text(value);
|
|
5508
|
+
}
|
|
5509
|
+
const normalized = normalizeRefMeta(value);
|
|
5510
|
+
if (isPlainObject4(normalized)) {
|
|
5511
|
+
return Object.entries(normalized).map(([key, item]) => `${key}=${diagnosticValueText(item)}`).join(" ");
|
|
5512
|
+
}
|
|
5513
|
+
return diagnosticValueText(normalized);
|
|
5514
|
+
}
|
|
5515
|
+
function diagnosticValueText(value) {
|
|
5516
|
+
if (value == null) {
|
|
5517
|
+
return "";
|
|
5518
|
+
}
|
|
5519
|
+
if (Buffer.isBuffer(value)) {
|
|
5520
|
+
return value.toString("utf8");
|
|
5521
|
+
}
|
|
5522
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
5523
|
+
return String(value);
|
|
5524
|
+
}
|
|
5525
|
+
return JSON.stringify(value);
|
|
5526
|
+
}
|
|
5527
|
+
function managementPairArgs(pairs2) {
|
|
5528
|
+
const args = [];
|
|
5529
|
+
for (const [key, value] of Object.entries(pairs2)) {
|
|
5530
|
+
if (value != null) {
|
|
5531
|
+
args.push(key.toUpperCase(), value);
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
return args;
|
|
5535
|
+
}
|
|
5536
|
+
function appendFlowStatePolicy(args, policy) {
|
|
5537
|
+
if (isFlowStatePolicy(policy)) {
|
|
5538
|
+
appendPolicyMode(args, "state", policy.mode);
|
|
5539
|
+
if (policy.retry != null) {
|
|
5540
|
+
appendRetryPolicy(args, policy.retry);
|
|
5541
|
+
}
|
|
5542
|
+
return;
|
|
5543
|
+
}
|
|
5544
|
+
appendRetryPolicy(args, policy);
|
|
5545
|
+
}
|
|
5546
|
+
function isFlowStatePolicy(policy) {
|
|
5547
|
+
return typeof policy === "object" && policy != null && ("mode" in policy || "retry" in policy);
|
|
5548
|
+
}
|
|
5549
|
+
function ruleArgs(rules) {
|
|
5550
|
+
return typeof rules === "string" ? [rules] : [...rules];
|
|
5551
|
+
}
|
|
5552
|
+
function isPlainObject4(value) {
|
|
5553
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer.isBuffer(value);
|
|
5554
|
+
}
|
|
4332
5555
|
function sharedCreateManyStateMeta(items, stateMeta) {
|
|
4333
5556
|
const itemMetas = items.map((item) => item.stateMeta).filter((meta) => meta != null);
|
|
4334
5557
|
if (itemMetas.length === 0) {
|
|
@@ -4415,6 +5638,24 @@ function appendRetryPolicy(args, policy) {
|
|
|
4415
5638
|
append(args, "JITTER_PCT", policy.jitterPct);
|
|
4416
5639
|
append(args, "EXHAUSTED_TO", policy.exhaustedTo);
|
|
4417
5640
|
}
|
|
5641
|
+
function appendPolicyMode(args, state, mode) {
|
|
5642
|
+
if (mode == null) {
|
|
5643
|
+
return;
|
|
5644
|
+
}
|
|
5645
|
+
if (state == null) {
|
|
5646
|
+
throw new Error("policy mode requires state");
|
|
5647
|
+
}
|
|
5648
|
+
switch (mode) {
|
|
5649
|
+
case "fifo":
|
|
5650
|
+
args.push("MODE", "FIFO");
|
|
5651
|
+
return;
|
|
5652
|
+
case "parallel":
|
|
5653
|
+
args.push("MODE", "PARALLEL");
|
|
5654
|
+
return;
|
|
5655
|
+
default:
|
|
5656
|
+
throw new Error("policy mode must be 'fifo' or 'parallel'");
|
|
5657
|
+
}
|
|
5658
|
+
}
|
|
4418
5659
|
function appendPayloadRead(args, payload, maxBytes) {
|
|
4419
5660
|
if (payload === false) {
|
|
4420
5661
|
args.push("NOPAYLOAD");
|
|
@@ -4879,6 +6120,7 @@ var Workflow = class {
|
|
|
4879
6120
|
exceptionPolicy: normalizeExceptionPolicy(options.exceptionPolicy),
|
|
4880
6121
|
handler,
|
|
4881
6122
|
leaseMs: options.leaseMs ?? 3e4,
|
|
6123
|
+
...options.mode == null ? {} : { mode: normalizeStateMode(options.mode) },
|
|
4882
6124
|
name,
|
|
4883
6125
|
returnRecord: options.returnRecord ?? false,
|
|
4884
6126
|
valueMaxBytes: options.valueMaxBytes ?? this.valueConfig.valueMaxBytes,
|
|
@@ -4913,6 +6155,21 @@ var Workflow = class {
|
|
|
4913
6155
|
worker(options = {}) {
|
|
4914
6156
|
return new WorkflowWorker(this, options);
|
|
4915
6157
|
}
|
|
6158
|
+
async installPolicy(options = {}) {
|
|
6159
|
+
const states = {};
|
|
6160
|
+
for (const registration of this.states.values()) {
|
|
6161
|
+
if (registration.mode != null || registration.retryPolicy != null) {
|
|
6162
|
+
states[registration.name] = {
|
|
6163
|
+
...registration.mode == null ? {} : { mode: registration.mode },
|
|
6164
|
+
...registration.retryPolicy == null ? {} : { retry: registration.retryPolicy }
|
|
6165
|
+
};
|
|
6166
|
+
}
|
|
6167
|
+
}
|
|
6168
|
+
return await this.client.installPolicy(this.type, {
|
|
6169
|
+
...options,
|
|
6170
|
+
states
|
|
6171
|
+
});
|
|
6172
|
+
}
|
|
4916
6173
|
stateNames() {
|
|
4917
6174
|
return [...this.states.keys()];
|
|
4918
6175
|
}
|
|
@@ -5173,13 +6430,15 @@ var WorkflowWorker = class {
|
|
|
5173
6430
|
}
|
|
5174
6431
|
async applyJob(job, registration) {
|
|
5175
6432
|
const ctx = new WorkflowContext(this.workflow, job, registration.name);
|
|
6433
|
+
let outcome;
|
|
5176
6434
|
try {
|
|
5177
6435
|
const value = await registration.handler(ctx);
|
|
5178
|
-
|
|
5179
|
-
await applyOutcome(this.workflow.client, ctx, outcome, registration.returnRecord);
|
|
6436
|
+
outcome = isOutcome(value) ? value : complete({ result: value });
|
|
5180
6437
|
} catch (error) {
|
|
5181
6438
|
await this.applyHandlerError(ctx, registration, error);
|
|
6439
|
+
return;
|
|
5182
6440
|
}
|
|
6441
|
+
await applyOutcome(this.workflow.client, ctx, outcome, registration.returnRecord);
|
|
5183
6442
|
}
|
|
5184
6443
|
async applyHandlerError(ctx, registration, error) {
|
|
5185
6444
|
const policy = this.options.exceptionPolicy ?? registration.exceptionPolicy;
|
|
@@ -5210,6 +6469,7 @@ async function applyOutcome(client, ctx, outcome, returnRecord) {
|
|
|
5210
6469
|
}
|
|
5211
6470
|
}
|
|
5212
6471
|
async function applyTransition(client, ctx, outcome, returnRecord) {
|
|
6472
|
+
validateTransitionPolicy(ctx, outcome);
|
|
5213
6473
|
await client.transition(ctx.id, {
|
|
5214
6474
|
dropValues: outcome.dropValues,
|
|
5215
6475
|
fencingToken: ctx.fencingToken,
|
|
@@ -5227,6 +6487,12 @@ async function applyTransition(client, ctx, outcome, returnRecord) {
|
|
|
5227
6487
|
values: outcome.values
|
|
5228
6488
|
});
|
|
5229
6489
|
}
|
|
6490
|
+
function validateTransitionPolicy(ctx, outcome) {
|
|
6491
|
+
const target = ctx.workflow.stateRegistration(outcome.toState);
|
|
6492
|
+
if (target?.mode === "fifo" && outcome.priority != null) {
|
|
6493
|
+
throw new Error("priority is not supported for fifo state");
|
|
6494
|
+
}
|
|
6495
|
+
}
|
|
5230
6496
|
async function applyComplete(client, ctx, outcome, returnRecord) {
|
|
5231
6497
|
await client.complete(ctx.id, {
|
|
5232
6498
|
dropValues: outcome.dropValues,
|
|
@@ -5285,6 +6551,12 @@ function errorToPayload(error) {
|
|
|
5285
6551
|
}
|
|
5286
6552
|
return error;
|
|
5287
6553
|
}
|
|
6554
|
+
function normalizeStateMode(mode) {
|
|
6555
|
+
if (mode === "fifo" || mode === "parallel") {
|
|
6556
|
+
return mode;
|
|
6557
|
+
}
|
|
6558
|
+
throw new Error("state mode must be 'fifo' or 'parallel'");
|
|
6559
|
+
}
|
|
5288
6560
|
function valueRefToString(value) {
|
|
5289
6561
|
if (typeof value === "string") {
|
|
5290
6562
|
return value;
|
|
@@ -5302,6 +6574,7 @@ function valueRefToString(value) {
|
|
|
5302
6574
|
0 && (module.exports = {
|
|
5303
6575
|
BitmapStore,
|
|
5304
6576
|
BloomFilterStore,
|
|
6577
|
+
COMMAND_OPCODES,
|
|
5305
6578
|
CountMinSketchStore,
|
|
5306
6579
|
CuckooFilterStore,
|
|
5307
6580
|
FerricStoreClient,
|
|
@@ -5326,12 +6599,14 @@ function valueRefToString(value) {
|
|
|
5326
6599
|
QueueWorker,
|
|
5327
6600
|
RawCodec,
|
|
5328
6601
|
ReconnectingExecutor,
|
|
6602
|
+
RoutingTopology,
|
|
5329
6603
|
SetStore,
|
|
5330
6604
|
SortedSetStore,
|
|
5331
6605
|
StaleLeaseError,
|
|
5332
6606
|
StreamStore,
|
|
5333
6607
|
TDigestStore,
|
|
5334
6608
|
TopKStore,
|
|
6609
|
+
TopologyNativeAdapterPool,
|
|
5335
6610
|
Workflow,
|
|
5336
6611
|
WorkflowClient,
|
|
5337
6612
|
WorkflowContext,
|