@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.js
CHANGED
|
@@ -110,24 +110,171 @@ var FLAG_CUSTOM_PAYLOAD = 2;
|
|
|
110
110
|
var FLAG_COMPRESSED = 8;
|
|
111
111
|
var FLAG_MORE_CHUNKS = 32;
|
|
112
112
|
var STATUS_OK = 0;
|
|
113
|
+
var COMMAND_OPCODES = {
|
|
114
|
+
"HELLO": 1,
|
|
115
|
+
"AUTH": 2,
|
|
116
|
+
"PING": 3,
|
|
117
|
+
"CLIENT.SETNAME": 4,
|
|
118
|
+
"CLIENT.INFO": 5,
|
|
119
|
+
"ROUTE": 6,
|
|
120
|
+
"SHARDS": 7,
|
|
121
|
+
"BACKPRESSURE": 8,
|
|
122
|
+
"QUIT": 9,
|
|
123
|
+
"GOAWAY": 10,
|
|
124
|
+
"OPTIONS": 11,
|
|
125
|
+
"STARTUP": 12,
|
|
126
|
+
"WINDOW_UPDATE": 13,
|
|
127
|
+
"PIPELINE": 14,
|
|
128
|
+
"ROUTE_BATCH": 15,
|
|
129
|
+
"EVENT": 16,
|
|
130
|
+
"SUBSCRIBE_EVENTS": 17,
|
|
131
|
+
"UNSUBSCRIBE_EVENTS": 18,
|
|
132
|
+
"COMMAND_EXEC": 256,
|
|
133
|
+
"GET": 257,
|
|
134
|
+
"SET": 258,
|
|
135
|
+
"DEL": 259,
|
|
136
|
+
"MGET": 260,
|
|
137
|
+
"MSET": 261,
|
|
138
|
+
"CAS": 262,
|
|
139
|
+
"LOCK": 263,
|
|
140
|
+
"UNLOCK": 264,
|
|
141
|
+
"EXTEND": 265,
|
|
142
|
+
"RATELIMIT.ADD": 266,
|
|
143
|
+
"FETCH_OR_COMPUTE": 267,
|
|
144
|
+
"FETCH_OR_COMPUTE_RESULT": 268,
|
|
145
|
+
"FETCH_OR_COMPUTE_ERROR": 269,
|
|
146
|
+
"HSET": 272,
|
|
147
|
+
"HGET": 273,
|
|
148
|
+
"HMGET": 274,
|
|
149
|
+
"HGETALL": 275,
|
|
150
|
+
"LPUSH": 288,
|
|
151
|
+
"RPUSH": 289,
|
|
152
|
+
"LPOP": 290,
|
|
153
|
+
"RPOP": 291,
|
|
154
|
+
"LRANGE": 292,
|
|
155
|
+
"SADD": 304,
|
|
156
|
+
"SREM": 305,
|
|
157
|
+
"SMEMBERS": 306,
|
|
158
|
+
"SISMEMBER": 307,
|
|
159
|
+
"ZADD": 320,
|
|
160
|
+
"ZREM": 321,
|
|
161
|
+
"ZRANGE": 322,
|
|
162
|
+
"ZSCORE": 323,
|
|
163
|
+
"FLOW.CREATE": 513,
|
|
164
|
+
"FLOW.GET": 514,
|
|
165
|
+
"FLOW.CLAIM_DUE": 515,
|
|
166
|
+
"FLOW.COMPLETE": 516,
|
|
167
|
+
"FLOW.TRANSITION": 517,
|
|
168
|
+
"FLOW.RETRY": 518,
|
|
169
|
+
"FLOW.FAIL": 519,
|
|
170
|
+
"FLOW.CANCEL": 520,
|
|
171
|
+
"FLOW.EXTEND_LEASE": 521,
|
|
172
|
+
"FLOW.HISTORY": 522,
|
|
173
|
+
"FLOW.VALUE.PUT": 523,
|
|
174
|
+
"FLOW.VALUE.MGET": 524,
|
|
175
|
+
"FLOW.SIGNAL": 525,
|
|
176
|
+
"FLOW.LIST": 526,
|
|
177
|
+
"FLOW.CREATE_MANY": 527,
|
|
178
|
+
"FLOW.COMPLETE_MANY": 528,
|
|
179
|
+
"FLOW.TRANSITION_MANY": 529,
|
|
180
|
+
"FLOW.RETRY_MANY": 530,
|
|
181
|
+
"FLOW.FAIL_MANY": 531,
|
|
182
|
+
"FLOW.CANCEL_MANY": 532,
|
|
183
|
+
"FLOW.RECLAIM": 533,
|
|
184
|
+
"FLOW.REWIND": 534,
|
|
185
|
+
"FLOW.TERMINALS": 535,
|
|
186
|
+
"FLOW.FAILURES": 536,
|
|
187
|
+
"FLOW.BY_PARENT": 537,
|
|
188
|
+
"FLOW.BY_ROOT": 538,
|
|
189
|
+
"FLOW.BY_CORRELATION": 539,
|
|
190
|
+
"FLOW.INFO": 540,
|
|
191
|
+
"FLOW.STUCK": 541,
|
|
192
|
+
"FLOW.POLICY.SET": 542,
|
|
193
|
+
"FLOW.POLICY.GET": 543,
|
|
194
|
+
"FLOW.SPAWN_CHILDREN": 544,
|
|
195
|
+
"FLOW.RETENTION_CLEANUP": 545,
|
|
196
|
+
"FLOW.STEP_CONTINUE": 546,
|
|
197
|
+
"FLOW.START_AND_CLAIM": 547,
|
|
198
|
+
"FLOW.RUN_STEPS_MANY": 548,
|
|
199
|
+
"FLOW.SCHEDULE.CREATE": 549,
|
|
200
|
+
"FLOW.SCHEDULE.GET": 550,
|
|
201
|
+
"FLOW.SCHEDULE.DELETE": 551,
|
|
202
|
+
"FLOW.SCHEDULE.FIRE_DUE": 552,
|
|
203
|
+
"FLOW.SCHEDULE.LIST": 553,
|
|
204
|
+
"FLOW.SCHEDULE.FIRE": 554,
|
|
205
|
+
"FLOW.SCHEDULE.PAUSE": 555,
|
|
206
|
+
"FLOW.SCHEDULE.RESUME": 556,
|
|
207
|
+
"FLOW.STATS": 557,
|
|
208
|
+
"FLOW.ATTRIBUTES": 558,
|
|
209
|
+
"FLOW.ATTRIBUTE_VALUES": 559,
|
|
210
|
+
"FLOW.SEARCH": 560,
|
|
211
|
+
"FLOW.EFFECT.RESERVE": 576,
|
|
212
|
+
"FLOW.EFFECT.CONFIRM": 577,
|
|
213
|
+
"FLOW.EFFECT.FAIL": 578,
|
|
214
|
+
"FLOW.EFFECT.COMPENSATE": 579,
|
|
215
|
+
"FLOW.EFFECT.GET": 580,
|
|
216
|
+
"FLOW.GOVERNANCE.LEDGER": 581,
|
|
217
|
+
"FLOW.APPROVAL.REQUEST": 582,
|
|
218
|
+
"FLOW.APPROVAL.APPROVE": 583,
|
|
219
|
+
"FLOW.APPROVAL.REJECT": 584,
|
|
220
|
+
"FLOW.APPROVAL.GET": 585,
|
|
221
|
+
"FLOW.CIRCUIT.OPEN": 586,
|
|
222
|
+
"FLOW.CIRCUIT.CLOSE": 587,
|
|
223
|
+
"FLOW.CIRCUIT.GET": 588,
|
|
224
|
+
"FLOW.BUDGET.RESERVE": 589,
|
|
225
|
+
"FLOW.BUDGET.GET": 590,
|
|
226
|
+
"FLOW.LIMIT.LEASE": 591,
|
|
227
|
+
"FLOW.LIMIT.SPEND": 592,
|
|
228
|
+
"FLOW.LIMIT.RELEASE": 593,
|
|
229
|
+
"FLOW.LIMIT.GET": 594,
|
|
230
|
+
"FLOW.APPROVAL.LIST": 595,
|
|
231
|
+
"FLOW.GOVERNANCE.OVERVIEW": 596,
|
|
232
|
+
"FLOW.BUDGET.LIST": 597,
|
|
233
|
+
"FLOW.LIMIT.LIST": 598,
|
|
234
|
+
"FLOW.BUDGET.COMMIT": 599,
|
|
235
|
+
"FLOW.BUDGET.RELEASE": 600,
|
|
236
|
+
"CLUSTER.HEALTH": 769,
|
|
237
|
+
"CLUSTER.STATS": 770,
|
|
238
|
+
"CLUSTER.KEYSLOT": 771,
|
|
239
|
+
"CLUSTER.SLOTS": 772,
|
|
240
|
+
"CLUSTER.STATUS": 773,
|
|
241
|
+
"CLUSTER.JOIN": 774,
|
|
242
|
+
"CLUSTER.LEAVE": 775,
|
|
243
|
+
"CLUSTER.FAILOVER": 776,
|
|
244
|
+
"CLUSTER.PROMOTE": 777,
|
|
245
|
+
"CLUSTER.DEMOTE": 778,
|
|
246
|
+
"CLUSTER.ROLE": 779,
|
|
247
|
+
"FERRICSTORE.KEY_INFO": 780,
|
|
248
|
+
"FERRICSTORE.CONFIG": 781,
|
|
249
|
+
"FERRICSTORE.HOTNESS": 782,
|
|
250
|
+
"FERRICSTORE.METRICS": 783,
|
|
251
|
+
"FERRICSTORE.BLOBGC": 784
|
|
252
|
+
};
|
|
113
253
|
var OPCODES = {
|
|
114
|
-
startup:
|
|
115
|
-
auth:
|
|
116
|
-
ping:
|
|
117
|
-
clientSetName:
|
|
118
|
-
clientInfo:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
254
|
+
startup: COMMAND_OPCODES.STARTUP,
|
|
255
|
+
auth: COMMAND_OPCODES.AUTH,
|
|
256
|
+
ping: COMMAND_OPCODES.PING,
|
|
257
|
+
clientSetName: COMMAND_OPCODES["CLIENT.SETNAME"],
|
|
258
|
+
clientInfo: COMMAND_OPCODES["CLIENT.INFO"],
|
|
259
|
+
route: COMMAND_OPCODES.ROUTE,
|
|
260
|
+
routeBatch: COMMAND_OPCODES.ROUTE_BATCH,
|
|
261
|
+
shards: COMMAND_OPCODES.SHARDS,
|
|
262
|
+
backpressure: COMMAND_OPCODES.BACKPRESSURE,
|
|
263
|
+
options: COMMAND_OPCODES.OPTIONS,
|
|
264
|
+
quit: COMMAND_OPCODES.QUIT,
|
|
265
|
+
commandExec: COMMAND_OPCODES.COMMAND_EXEC,
|
|
266
|
+
get: COMMAND_OPCODES.GET,
|
|
267
|
+
set: COMMAND_OPCODES.SET,
|
|
268
|
+
del: COMMAND_OPCODES.DEL,
|
|
269
|
+
mget: COMMAND_OPCODES.MGET,
|
|
270
|
+
mset: COMMAND_OPCODES.MSET,
|
|
271
|
+
pipeline: COMMAND_OPCODES.PIPELINE,
|
|
272
|
+
flowCreate: COMMAND_OPCODES["FLOW.CREATE"],
|
|
273
|
+
flowClaimDue: COMMAND_OPCODES["FLOW.CLAIM_DUE"],
|
|
274
|
+
flowComplete: COMMAND_OPCODES["FLOW.COMPLETE"],
|
|
275
|
+
flowCreateMany: COMMAND_OPCODES["FLOW.CREATE_MANY"],
|
|
276
|
+
flowCompleteMany: COMMAND_OPCODES["FLOW.COMPLETE_MANY"],
|
|
277
|
+
flowSearch: COMMAND_OPCODES["FLOW.SEARCH"]
|
|
131
278
|
};
|
|
132
279
|
var COMPACT_FLOW_CLAIM_JOBS = 128;
|
|
133
280
|
var COMPACT_OK_LIST = 129;
|
|
@@ -260,12 +407,46 @@ function buildProtocolCommand(args) {
|
|
|
260
407
|
}
|
|
261
408
|
const command = asText(args[0]).toUpperCase();
|
|
262
409
|
const commandArgs = args.slice(1);
|
|
410
|
+
if (command === "COMMAND_EXEC" && commandArgs.length >= 1) {
|
|
411
|
+
return commandExec(commandArgs);
|
|
412
|
+
}
|
|
413
|
+
if (command === "HELLO" || command === "STARTUP" || command === "WINDOW_UPDATE") {
|
|
414
|
+
return { laneId: 0, opcode: COMMAND_OPCODES[command], payload: optionMap(commandArgs) };
|
|
415
|
+
}
|
|
416
|
+
if (command === "AUTH") {
|
|
417
|
+
const payload = commandArgs.length === 1 ? { password: commandArgs[0], username: "default" } : { password: commandArgs[1], username: commandArgs[0] };
|
|
418
|
+
return { laneId: 0, opcode: OPCODES.auth, payload };
|
|
419
|
+
}
|
|
263
420
|
if (command === "PING") {
|
|
264
421
|
return { laneId: 0, opcode: OPCODES.ping, payload: commandArgs.length === 0 ? {} : { message: commandArgs[0] } };
|
|
265
422
|
}
|
|
423
|
+
if (command === "OPTIONS") {
|
|
424
|
+
return { laneId: 0, opcode: OPCODES.options, payload: {} };
|
|
425
|
+
}
|
|
426
|
+
if (command === "BACKPRESSURE") {
|
|
427
|
+
return { laneId: 0, opcode: OPCODES.backpressure, payload: {} };
|
|
428
|
+
}
|
|
429
|
+
if (command === "QUIT") {
|
|
430
|
+
return { laneId: 0, opcode: OPCODES.quit, payload: {} };
|
|
431
|
+
}
|
|
432
|
+
if (command === "ROUTE" && commandArgs.length >= 1) {
|
|
433
|
+
return { laneId: 0, opcode: OPCODES.route, payload: { key: commandArgs[0] } };
|
|
434
|
+
}
|
|
435
|
+
if (command === "ROUTE_BATCH") {
|
|
436
|
+
return { laneId: 0, opcode: OPCODES.routeBatch, payload: { keys: commandArgs } };
|
|
437
|
+
}
|
|
438
|
+
if (command === "SHARDS") {
|
|
439
|
+
return { laneId: 0, opcode: OPCODES.shards, payload: {} };
|
|
440
|
+
}
|
|
266
441
|
if (command === "CLIENT" && asText(commandArgs[0]).toUpperCase() === "SETNAME" && commandArgs.length === 2) {
|
|
267
442
|
return { laneId: 0, opcode: OPCODES.clientSetName, payload: { name: commandArgs[1] } };
|
|
268
443
|
}
|
|
444
|
+
if (command === "CLIENT.SETNAME" && commandArgs.length === 1) {
|
|
445
|
+
return { laneId: 0, opcode: OPCODES.clientSetName, payload: { name: commandArgs[0] } };
|
|
446
|
+
}
|
|
447
|
+
if (command === "CLIENT" && asText(commandArgs[0]).toUpperCase() === "INFO" && commandArgs.length === 1 || command === "CLIENT.INFO" && commandArgs.length === 0) {
|
|
448
|
+
return { laneId: 0, opcode: OPCODES.clientInfo, payload: {} };
|
|
449
|
+
}
|
|
269
450
|
if (command === "GET" && commandArgs.length >= 1) {
|
|
270
451
|
return { opcode: OPCODES.get, payload: { key: commandArgs[0] } };
|
|
271
452
|
}
|
|
@@ -284,7 +465,7 @@ function buildProtocolCommand(args) {
|
|
|
284
465
|
if (command === "DEL") {
|
|
285
466
|
return { opcode: OPCODES.del, payload: { keys: commandArgs } };
|
|
286
467
|
}
|
|
287
|
-
if (command.startsWith("FLOW.") && hasFlowCommandOnlyOption(commandArgs)) {
|
|
468
|
+
if (command.startsWith("FLOW.") && hasFlowCommandOnlyOption(command, commandArgs)) {
|
|
288
469
|
return commandExec(args);
|
|
289
470
|
}
|
|
290
471
|
if (command === "FLOW.CREATE") {
|
|
@@ -302,20 +483,73 @@ function buildProtocolCommand(args) {
|
|
|
302
483
|
if (command === "FLOW.COMPLETE_MANY") {
|
|
303
484
|
return flowCompleteManyPayload(commandArgs) ?? commandExec(args);
|
|
304
485
|
}
|
|
486
|
+
if (command === "FLOW.SEARCH") {
|
|
487
|
+
return flowSearchPayload(commandArgs) ?? commandExec(args);
|
|
488
|
+
}
|
|
305
489
|
return commandExec(args);
|
|
306
490
|
}
|
|
307
491
|
function commandExec(args) {
|
|
308
492
|
if (args.length === 0) {
|
|
309
493
|
throw new FerricStoreError("command requires at least one argument");
|
|
310
494
|
}
|
|
495
|
+
const commandArgs = args.slice(1);
|
|
496
|
+
const payload = {
|
|
497
|
+
args: commandArgs,
|
|
498
|
+
command: asText(args[0]).toUpperCase()
|
|
499
|
+
};
|
|
500
|
+
if (commandArgs.length >= 2 && commandTokenIs(commandArgs[commandArgs.length - 2], "REQUEST_CONTEXT")) {
|
|
501
|
+
const requestContext = normalizeRequestContext(commandArgs[commandArgs.length - 1]);
|
|
502
|
+
payload.args = commandArgs.slice(0, -2);
|
|
503
|
+
if (requestContext != null) {
|
|
504
|
+
payload.request_context = requestContext;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
311
507
|
return {
|
|
312
508
|
opcode: OPCODES.commandExec,
|
|
313
|
-
payload
|
|
314
|
-
args: args.slice(1),
|
|
315
|
-
command: asText(args[0]).toUpperCase()
|
|
316
|
-
}
|
|
509
|
+
payload
|
|
317
510
|
};
|
|
318
511
|
}
|
|
512
|
+
function normalizeRequestContext(context) {
|
|
513
|
+
if (!isPlainObject(context)) {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
const out = {};
|
|
517
|
+
const subject = optionalText(context.subject);
|
|
518
|
+
const tenant = optionalText(context.tenant);
|
|
519
|
+
const scopes = normalizeRequestContextScopes(context.scopes);
|
|
520
|
+
if (subject != null) {
|
|
521
|
+
out.subject = subject;
|
|
522
|
+
}
|
|
523
|
+
if (tenant != null) {
|
|
524
|
+
out.tenant = tenant;
|
|
525
|
+
}
|
|
526
|
+
if (scopes.length > 0) {
|
|
527
|
+
out.scopes = scopes;
|
|
528
|
+
}
|
|
529
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
530
|
+
}
|
|
531
|
+
function normalizeRequestContextScopes(scopes) {
|
|
532
|
+
const values = typeof scopes === "string" || Buffer2.isBuffer(scopes) || scopes instanceof Uint8Array ? asText(scopes).split(/\s+/u) : Array.isArray(scopes) ? scopes.map((scope) => optionalText(scope)).filter((scope) => scope != null) : [];
|
|
533
|
+
return [...new Set(values.filter((scope) => scope.length > 0))];
|
|
534
|
+
}
|
|
535
|
+
function optionalText(value) {
|
|
536
|
+
if (value == null || value === "") {
|
|
537
|
+
return void 0;
|
|
538
|
+
}
|
|
539
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" || Buffer2.isBuffer(value) || value instanceof Uint8Array) {
|
|
540
|
+
return asText(value);
|
|
541
|
+
}
|
|
542
|
+
return void 0;
|
|
543
|
+
}
|
|
544
|
+
function commandTokenIs(value, expected) {
|
|
545
|
+
if (typeof value === "string") {
|
|
546
|
+
return value.toUpperCase() === expected;
|
|
547
|
+
}
|
|
548
|
+
if (Buffer2.isBuffer(value) || value instanceof Uint8Array) {
|
|
549
|
+
return asText(value).toUpperCase() === expected;
|
|
550
|
+
}
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
319
553
|
function pipelineCommand(commands) {
|
|
320
554
|
const compact = compactPipelinePayload(commands);
|
|
321
555
|
if (compact != null) {
|
|
@@ -646,13 +880,13 @@ function writeOptionalBinary(out, offset, value) {
|
|
|
646
880
|
}
|
|
647
881
|
return writeBinary(out, offset, value);
|
|
648
882
|
}
|
|
649
|
-
function hasFlowCommandOnlyOption(args) {
|
|
883
|
+
function hasFlowCommandOnlyOption(command, args) {
|
|
650
884
|
return args.some((arg) => {
|
|
651
885
|
if (typeof arg !== "string" && !Buffer2.isBuffer(arg)) {
|
|
652
886
|
return false;
|
|
653
887
|
}
|
|
654
888
|
const token = asText(arg).toUpperCase();
|
|
655
|
-
return token === "
|
|
889
|
+
return token === "INDEXED_STATE_META" || command !== "FLOW.SEARCH" && token === "STATE_META";
|
|
656
890
|
});
|
|
657
891
|
}
|
|
658
892
|
function flowCreatePayload(args) {
|
|
@@ -770,6 +1004,12 @@ function flowCompleteManyPayload(args) {
|
|
|
770
1004
|
if (!auto && !mixed) payload.partition_key = partition;
|
|
771
1005
|
return { opcode: OPCODES.flowCompleteMany, payload };
|
|
772
1006
|
}
|
|
1007
|
+
function flowSearchPayload(args) {
|
|
1008
|
+
if (args.length < 1) return void 0;
|
|
1009
|
+
const payload = optionMap(args.slice(1));
|
|
1010
|
+
normalizeFlowSearchStateMeta(payload);
|
|
1011
|
+
return { opcode: OPCODES.flowSearch, payload: { type: args[0], ...payload } };
|
|
1012
|
+
}
|
|
773
1013
|
function compactFlowCreateManyPayload(partition, rawItems, mixed, auto, options) {
|
|
774
1014
|
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") {
|
|
775
1015
|
return void 0;
|
|
@@ -872,6 +1112,78 @@ function compactFlowCompleteManyPayload(partition, rawItems, mixed, auto, option
|
|
|
872
1112
|
}
|
|
873
1113
|
return { flags: FLAG_CUSTOM_PAYLOAD, opcode: OPCODES.flowCompleteMany, payload: out };
|
|
874
1114
|
}
|
|
1115
|
+
var OPTION_FIELDS = {
|
|
1116
|
+
CONSISTENT_PROJECTION: "consistent_projection",
|
|
1117
|
+
COUNT: "count",
|
|
1118
|
+
FROM_MS: "from_ms",
|
|
1119
|
+
INCLUDE_COLD: "include_cold",
|
|
1120
|
+
PARTITION: "partition_key",
|
|
1121
|
+
REV: "rev",
|
|
1122
|
+
STATE: "state",
|
|
1123
|
+
TERMINAL_ONLY: "terminal_only",
|
|
1124
|
+
TO_MS: "to_ms"
|
|
1125
|
+
};
|
|
1126
|
+
var BOOL_OPTION_FIELDS = /* @__PURE__ */ new Set(["consistent_projection", "include_cold", "rev", "terminal_only"]);
|
|
1127
|
+
function optionMap(args) {
|
|
1128
|
+
const payload = {};
|
|
1129
|
+
for (let index = 0; index < args.length; ) {
|
|
1130
|
+
const token = asText(args[index]).toUpperCase();
|
|
1131
|
+
if (token === "ATTRIBUTE") {
|
|
1132
|
+
if (index + 2 >= args.length) {
|
|
1133
|
+
throw new FerricStoreError("ATTRIBUTE requires name and value");
|
|
1134
|
+
}
|
|
1135
|
+
const name = asText(args[index + 1]);
|
|
1136
|
+
const attributes = ensureObjectField(payload, "attributes");
|
|
1137
|
+
attributes[name] = args[index + 2];
|
|
1138
|
+
index += 3;
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
if (token === "STATE_META") {
|
|
1142
|
+
if (index + 2 >= args.length) {
|
|
1143
|
+
throw new FerricStoreError("STATE_META requires name and value");
|
|
1144
|
+
}
|
|
1145
|
+
const name = asText(args[index + 1]);
|
|
1146
|
+
const stateMeta = ensureObjectField(payload, "state_meta");
|
|
1147
|
+
stateMeta[name] = args[index + 2];
|
|
1148
|
+
index += 3;
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
const field2 = OPTION_FIELDS[token] ?? token.toLowerCase();
|
|
1152
|
+
if (index + 1 >= args.length) {
|
|
1153
|
+
throw new FerricStoreError(`${token} requires a value`);
|
|
1154
|
+
}
|
|
1155
|
+
const value = args[index + 1];
|
|
1156
|
+
payload[field2] = BOOL_OPTION_FIELDS.has(field2) ? boolArg(value) : value;
|
|
1157
|
+
index += 2;
|
|
1158
|
+
}
|
|
1159
|
+
return payload;
|
|
1160
|
+
}
|
|
1161
|
+
function ensureObjectField(payload, field2) {
|
|
1162
|
+
const value = payload[field2];
|
|
1163
|
+
if (isPlainObject(value)) {
|
|
1164
|
+
return value;
|
|
1165
|
+
}
|
|
1166
|
+
const next = {};
|
|
1167
|
+
payload[field2] = next;
|
|
1168
|
+
return next;
|
|
1169
|
+
}
|
|
1170
|
+
function normalizeFlowSearchStateMeta(payload) {
|
|
1171
|
+
const stateMeta = payload.state_meta;
|
|
1172
|
+
if (!isPlainObject(stateMeta) || Object.keys(stateMeta).length === 0) {
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
if (Object.values(stateMeta).every(isPlainObject)) {
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
const state = payload.state;
|
|
1179
|
+
if (state == null) {
|
|
1180
|
+
throw new FerricStoreError("FLOW.SEARCH STATE_META filters require STATE or nested state metadata");
|
|
1181
|
+
}
|
|
1182
|
+
payload.state_meta = { [asText(state)]: stateMeta };
|
|
1183
|
+
}
|
|
1184
|
+
function isPlainObject(value) {
|
|
1185
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer2.isBuffer(value) && !(value instanceof Uint8Array);
|
|
1186
|
+
}
|
|
875
1187
|
function parseFlowOptions(args, start, end, config) {
|
|
876
1188
|
const payload = {};
|
|
877
1189
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1430,6 +1742,9 @@ var NativeAdapter = class _NativeAdapter {
|
|
|
1430
1742
|
const command = buildProtocolCommand(args);
|
|
1431
1743
|
return await this.request(command);
|
|
1432
1744
|
}
|
|
1745
|
+
async executeProtocolCommand(command, laneId) {
|
|
1746
|
+
return await this.request(laneId == null ? command : { ...command, laneId });
|
|
1747
|
+
}
|
|
1433
1748
|
async executePipeline(commands, options = {}) {
|
|
1434
1749
|
if (commands.length === 0) {
|
|
1435
1750
|
return [];
|
|
@@ -1641,6 +1956,20 @@ var ReconnectingExecutor = class {
|
|
|
1641
1956
|
return await Promise.all(commands.map((command) => executor.executeCommand(...command)));
|
|
1642
1957
|
});
|
|
1643
1958
|
}
|
|
1959
|
+
async refreshTopology() {
|
|
1960
|
+
const executor = await this.executorPromise;
|
|
1961
|
+
if (executor.refreshTopology == null) {
|
|
1962
|
+
throw new FerricStoreError("topology refresh requires a topology-aware native executor");
|
|
1963
|
+
}
|
|
1964
|
+
return await executor.refreshTopology();
|
|
1965
|
+
}
|
|
1966
|
+
async route(key) {
|
|
1967
|
+
const executor = await this.executorPromise;
|
|
1968
|
+
if (executor.route == null) {
|
|
1969
|
+
throw new FerricStoreError("route lookup requires a topology-aware native executor");
|
|
1970
|
+
}
|
|
1971
|
+
return await executor.route(key);
|
|
1972
|
+
}
|
|
1644
1973
|
async close() {
|
|
1645
1974
|
if (this.closed) {
|
|
1646
1975
|
return;
|
|
@@ -1731,6 +2060,653 @@ function normalizeKeepAliveInitialDelay(value) {
|
|
|
1731
2060
|
return Math.max(0, Math.trunc(value ?? 3e4));
|
|
1732
2061
|
}
|
|
1733
2062
|
|
|
2063
|
+
// src/topology.ts
|
|
2064
|
+
import { Buffer as Buffer4 } from "buffer";
|
|
2065
|
+
var ROUTE_SLOT_COUNT = 1024;
|
|
2066
|
+
var ROUTE_SLOT_MASK = ROUTE_SLOT_COUNT - 1;
|
|
2067
|
+
var RoutingTopology = class _RoutingTopology {
|
|
2068
|
+
routeEpoch;
|
|
2069
|
+
shardCount;
|
|
2070
|
+
slots;
|
|
2071
|
+
endpoints;
|
|
2072
|
+
constructor(routeEpoch, shardCount, slots, endpoints) {
|
|
2073
|
+
this.routeEpoch = routeEpoch;
|
|
2074
|
+
this.shardCount = shardCount;
|
|
2075
|
+
this.slots = slots;
|
|
2076
|
+
this.endpoints = endpoints;
|
|
2077
|
+
}
|
|
2078
|
+
static empty() {
|
|
2079
|
+
return new _RoutingTopology(0, 0, Array.from({ length: ROUTE_SLOT_COUNT }), /* @__PURE__ */ new Map());
|
|
2080
|
+
}
|
|
2081
|
+
static build(payload) {
|
|
2082
|
+
const ranges = getField(payload, "ranges");
|
|
2083
|
+
if (!Array.isArray(ranges)) {
|
|
2084
|
+
throw new FerricStoreError("invalid SHARDS topology payload", { raw: payload });
|
|
2085
|
+
}
|
|
2086
|
+
const slots = Array.from({ length: ROUTE_SLOT_COUNT });
|
|
2087
|
+
const endpoints = /* @__PURE__ */ new Map();
|
|
2088
|
+
for (const item of ranges) {
|
|
2089
|
+
if (textOrUndefined(getField(item, "hint")) === "leader_unknown") {
|
|
2090
|
+
throw new FerricStoreError("SHARDS range has no leader", { raw: item });
|
|
2091
|
+
}
|
|
2092
|
+
const first = numberOrUndefined(getField(item, "first_slot"));
|
|
2093
|
+
const last = numberOrUndefined(getField(item, "last_slot"));
|
|
2094
|
+
const shard = numberOrUndefined(getField(item, "shard"));
|
|
2095
|
+
const laneId = numberOrUndefined(getField(item, "lane_id"));
|
|
2096
|
+
const endpoint = endpointFromRange(item);
|
|
2097
|
+
if (first == null || last == null || shard == null || laneId == null || first < 0 || last < first || last >= ROUTE_SLOT_COUNT) {
|
|
2098
|
+
throw new FerricStoreError("invalid SHARDS range", { raw: item });
|
|
2099
|
+
}
|
|
2100
|
+
const endpointKey = endpointKeyFor(endpoint);
|
|
2101
|
+
const route = {
|
|
2102
|
+
endpoint,
|
|
2103
|
+
endpointKey,
|
|
2104
|
+
laneId,
|
|
2105
|
+
leaderNode: endpoint.node,
|
|
2106
|
+
shard
|
|
2107
|
+
};
|
|
2108
|
+
for (let slot = first; slot <= last; slot += 1) {
|
|
2109
|
+
slots[slot] = route;
|
|
2110
|
+
}
|
|
2111
|
+
endpoints.set(endpointKey, endpoint);
|
|
2112
|
+
}
|
|
2113
|
+
return new _RoutingTopology(
|
|
2114
|
+
numberOrUndefined(getField(payload, "route_epoch")) ?? 0,
|
|
2115
|
+
numberOrUndefined(getField(payload, "shard_count")) ?? 0,
|
|
2116
|
+
slots,
|
|
2117
|
+
endpoints
|
|
2118
|
+
);
|
|
2119
|
+
}
|
|
2120
|
+
static slotForKey(key) {
|
|
2121
|
+
const textKey = Buffer4.isBuffer(key) ? key.toString("utf8") : key;
|
|
2122
|
+
let hashInput;
|
|
2123
|
+
if (textKey.startsWith("f:{")) {
|
|
2124
|
+
hashInput = flowHashTag(textKey.slice(3), textKey);
|
|
2125
|
+
} else if (textKey.startsWith("X:f:{")) {
|
|
2126
|
+
hashInput = flowHashTag(textKey.slice(5), textKey);
|
|
2127
|
+
} else {
|
|
2128
|
+
hashInput = hashTagOrKey(textKey);
|
|
2129
|
+
}
|
|
2130
|
+
return crc32(Buffer4.from(hashInput)) & ROUTE_SLOT_MASK;
|
|
2131
|
+
}
|
|
2132
|
+
routeKey(key) {
|
|
2133
|
+
const slot = _RoutingTopology.slotForKey(key);
|
|
2134
|
+
const route = this.slots[slot];
|
|
2135
|
+
if (route == null) {
|
|
2136
|
+
throw new FerricStoreError(`no route for slot ${slot}`);
|
|
2137
|
+
}
|
|
2138
|
+
return { ...route, slot };
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
var TopologyNativeAdapterPool = class _TopologyNativeAdapterPool {
|
|
2142
|
+
adapterOptions;
|
|
2143
|
+
adapters = /* @__PURE__ */ new Map();
|
|
2144
|
+
endpointPolicy;
|
|
2145
|
+
endpointValidator;
|
|
2146
|
+
seedEndpointKeys;
|
|
2147
|
+
seedUrls;
|
|
2148
|
+
tls;
|
|
2149
|
+
trustedHosts;
|
|
2150
|
+
warmConnections;
|
|
2151
|
+
topologyValue = RoutingTopology.empty();
|
|
2152
|
+
constructor(urls, options = {}) {
|
|
2153
|
+
if (urls.length === 0) {
|
|
2154
|
+
throw new FerricStoreError("TopologyNativeAdapterPool requires at least one seed URL");
|
|
2155
|
+
}
|
|
2156
|
+
this.seedUrls = [...urls];
|
|
2157
|
+
this.endpointPolicy = options.endpointPolicy ?? "seed_hosts";
|
|
2158
|
+
this.endpointValidator = options.endpointValidator;
|
|
2159
|
+
this.warmConnections = options.warmConnections ?? false;
|
|
2160
|
+
this.tls = options.tlsOptions != null || urls.some((url) => parseFerricUrl2(url).tls);
|
|
2161
|
+
this.adapterOptions = nativeOnlyOptions(withSeedAuthDefaults(urls, options));
|
|
2162
|
+
this.seedEndpointKeys = new Set(urls.map((url) => endpointKeyFor(endpointFromUrl(url))));
|
|
2163
|
+
this.trustedHosts = normalizedHostSet(options.trustedHosts ?? []);
|
|
2164
|
+
}
|
|
2165
|
+
static async fromUrls(urls, options = {}) {
|
|
2166
|
+
const pool = new _TopologyNativeAdapterPool(urls, options);
|
|
2167
|
+
await pool.refreshTopology();
|
|
2168
|
+
return pool;
|
|
2169
|
+
}
|
|
2170
|
+
get topology() {
|
|
2171
|
+
return this.topologyValue;
|
|
2172
|
+
}
|
|
2173
|
+
async refreshTopology() {
|
|
2174
|
+
let lastError;
|
|
2175
|
+
for (const url of this.refreshCandidateUrls()) {
|
|
2176
|
+
try {
|
|
2177
|
+
const adapter = await this.adapterForUrl(url);
|
|
2178
|
+
const topology = RoutingTopology.build(await adapter.executeCommand("SHARDS"));
|
|
2179
|
+
this.topologyValue = topology;
|
|
2180
|
+
if (this.warmConnections) {
|
|
2181
|
+
await Promise.allSettled([...topology.endpoints.values()].map(async (endpoint) => await this.adapterForEndpoint(endpoint)));
|
|
2182
|
+
}
|
|
2183
|
+
return topology;
|
|
2184
|
+
} catch (error) {
|
|
2185
|
+
lastError = error;
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
throw new FerricStoreError("no FerricStore topology endpoint reachable", { raw: lastError });
|
|
2189
|
+
}
|
|
2190
|
+
route(key) {
|
|
2191
|
+
const route = this.topologyValue.routeKey(key);
|
|
2192
|
+
this.validateEndpoint(route.endpoint);
|
|
2193
|
+
return route;
|
|
2194
|
+
}
|
|
2195
|
+
async executeCommand(...args) {
|
|
2196
|
+
const routed = this.routeData(args);
|
|
2197
|
+
if (routed == null) {
|
|
2198
|
+
return await (await this.controlAdapter()).executeCommand(...args);
|
|
2199
|
+
}
|
|
2200
|
+
const adapter = await this.adapterForEndpoint(routed.route.endpoint);
|
|
2201
|
+
try {
|
|
2202
|
+
return await adapter.executeProtocolCommand(routed.command, routed.route.laneId);
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
if (isRetryableRouteError(error)) {
|
|
2205
|
+
await this.refreshTopology().catch(() => void 0);
|
|
2206
|
+
}
|
|
2207
|
+
throw error;
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
async executePipeline(commands, options = {}) {
|
|
2211
|
+
if (commands.length === 0) {
|
|
2212
|
+
return [];
|
|
2213
|
+
}
|
|
2214
|
+
const route = this.singleRouteForCommands(commands);
|
|
2215
|
+
if (route == null) {
|
|
2216
|
+
return await (await this.controlAdapter()).executePipeline(commands, options);
|
|
2217
|
+
}
|
|
2218
|
+
const adapter = await this.adapterForEndpoint(route.endpoint);
|
|
2219
|
+
try {
|
|
2220
|
+
const response = await adapter.executeProtocolCommand(pipelineCommand(commands), route.laneId);
|
|
2221
|
+
return unwrapPipelineResponse(response, options);
|
|
2222
|
+
} catch (error) {
|
|
2223
|
+
if (isRetryableRouteError(error)) {
|
|
2224
|
+
await this.refreshTopology().catch(() => void 0);
|
|
2225
|
+
}
|
|
2226
|
+
throw error;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
async close() {
|
|
2230
|
+
await Promise.allSettled([...this.adapters.values()].map(async (adapter) => await adapter.close()));
|
|
2231
|
+
this.adapters.clear();
|
|
2232
|
+
}
|
|
2233
|
+
routeData(args) {
|
|
2234
|
+
if (args.length === 0) {
|
|
2235
|
+
return void 0;
|
|
2236
|
+
}
|
|
2237
|
+
let command;
|
|
2238
|
+
try {
|
|
2239
|
+
command = buildProtocolCommand(args);
|
|
2240
|
+
} catch {
|
|
2241
|
+
return void 0;
|
|
2242
|
+
}
|
|
2243
|
+
const key = routingKey(args, command);
|
|
2244
|
+
if (key == null) {
|
|
2245
|
+
return void 0;
|
|
2246
|
+
}
|
|
2247
|
+
return { command, route: this.route(key) };
|
|
2248
|
+
}
|
|
2249
|
+
singleRouteForCommands(commands) {
|
|
2250
|
+
let route;
|
|
2251
|
+
for (const command of commands) {
|
|
2252
|
+
const routed = this.routeData(command);
|
|
2253
|
+
if (routed == null) {
|
|
2254
|
+
return void 0;
|
|
2255
|
+
}
|
|
2256
|
+
const current = routed.route;
|
|
2257
|
+
if (route == null) {
|
|
2258
|
+
route = current;
|
|
2259
|
+
} else if (route.endpointKey !== current.endpointKey || route.laneId !== current.laneId) {
|
|
2260
|
+
return void 0;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
return route;
|
|
2264
|
+
}
|
|
2265
|
+
async controlAdapter() {
|
|
2266
|
+
for (const url of this.refreshCandidateUrls()) {
|
|
2267
|
+
try {
|
|
2268
|
+
return await this.adapterForUrl(url);
|
|
2269
|
+
} catch {
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
return await this.adapterForUrl(this.seedUrls[0] ?? "ferric://127.0.0.1:6388");
|
|
2273
|
+
}
|
|
2274
|
+
async adapterForUrl(url) {
|
|
2275
|
+
const endpoint = endpointFromUrl(url);
|
|
2276
|
+
const key = endpointKeyFor(endpoint);
|
|
2277
|
+
const existing = this.adapters.get(key);
|
|
2278
|
+
if (existing != null) {
|
|
2279
|
+
return existing;
|
|
2280
|
+
}
|
|
2281
|
+
const adapter = await NativeAdapter.fromUrl(url, this.adapterOptions);
|
|
2282
|
+
this.adapters.set(key, adapter);
|
|
2283
|
+
return adapter;
|
|
2284
|
+
}
|
|
2285
|
+
async adapterForEndpoint(endpoint) {
|
|
2286
|
+
this.validateEndpoint(endpoint);
|
|
2287
|
+
const key = endpointKeyFor(endpoint);
|
|
2288
|
+
const existing = this.adapters.get(key);
|
|
2289
|
+
if (existing != null) {
|
|
2290
|
+
return existing;
|
|
2291
|
+
}
|
|
2292
|
+
const adapter = await NativeAdapter.fromUrl(urlFromEndpoint(endpoint, this.tls), this.adapterOptions);
|
|
2293
|
+
this.adapters.set(key, adapter);
|
|
2294
|
+
return adapter;
|
|
2295
|
+
}
|
|
2296
|
+
validateEndpoint(endpoint) {
|
|
2297
|
+
let allowed;
|
|
2298
|
+
if (this.endpointPolicy === "any" || this.endpointPolicy === "none") {
|
|
2299
|
+
allowed = true;
|
|
2300
|
+
} else if (this.endpointPolicy === "seed_hosts") {
|
|
2301
|
+
allowed = this.seedEndpointKeys.has(endpointKeyFor(endpoint)) || this.trustedHosts.has(endpoint.host.toLowerCase());
|
|
2302
|
+
} else if ("allowHosts" in this.endpointPolicy) {
|
|
2303
|
+
allowed = normalizedHostSet(this.endpointPolicy.allowHosts).has(endpoint.host.toLowerCase());
|
|
2304
|
+
} else {
|
|
2305
|
+
throw new FerricStoreError("invalid endpoint policy", { raw: this.endpointPolicy });
|
|
2306
|
+
}
|
|
2307
|
+
if (!allowed) {
|
|
2308
|
+
throw new FerricStoreError("unsafe learned endpoint", { raw: endpoint });
|
|
2309
|
+
}
|
|
2310
|
+
if (this.endpointValidator != null && !this.endpointValidator(endpoint)) {
|
|
2311
|
+
throw new FerricStoreError("unsafe learned endpoint", { raw: endpoint });
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
refreshCandidateUrls() {
|
|
2315
|
+
const urls = [
|
|
2316
|
+
...this.seedUrls,
|
|
2317
|
+
...[...this.topologyValue.endpoints.values()].map((endpoint) => urlFromEndpoint(endpoint, this.tls))
|
|
2318
|
+
];
|
|
2319
|
+
return [...new Set(urls)];
|
|
2320
|
+
}
|
|
2321
|
+
};
|
|
2322
|
+
function routingKey(args, command) {
|
|
2323
|
+
const name = commandName(args);
|
|
2324
|
+
if (command.opcode < 256 || name === "CLUSTER.KEYSLOT" || name === "SHARDS" || name === "ROUTE") {
|
|
2325
|
+
return void 0;
|
|
2326
|
+
}
|
|
2327
|
+
const keyFromArgs = routingKeyFromArgs(name, args);
|
|
2328
|
+
if (keyFromArgs != null) {
|
|
2329
|
+
return keyFromArgs;
|
|
2330
|
+
}
|
|
2331
|
+
if (!isPlainObject2(command.payload)) {
|
|
2332
|
+
return void 0;
|
|
2333
|
+
}
|
|
2334
|
+
for (const field2 of ["key", "partition_key", "id", "owner_flow_id", "parent_id", "root_id", "correlation_id", "scope"]) {
|
|
2335
|
+
const value = getField(command.payload, field2);
|
|
2336
|
+
if (typeof value === "string" || Buffer4.isBuffer(value)) {
|
|
2337
|
+
return value;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
const keys = getField(command.payload, "keys");
|
|
2341
|
+
if (Array.isArray(keys)) {
|
|
2342
|
+
return singleShardKey(keys);
|
|
2343
|
+
}
|
|
2344
|
+
const pairsValue = getField(command.payload, "pairs");
|
|
2345
|
+
if (Array.isArray(pairsValue)) {
|
|
2346
|
+
return singleShardKey(
|
|
2347
|
+
pairsValue.filter((pair) => Array.isArray(pair) && pair.length > 0).map((pair) => pair[0])
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
return void 0;
|
|
2351
|
+
}
|
|
2352
|
+
function routingKeyFromArgs(name, args) {
|
|
2353
|
+
if (name == null) {
|
|
2354
|
+
return void 0;
|
|
2355
|
+
}
|
|
2356
|
+
if (name === "MGET" || name === "DEL") {
|
|
2357
|
+
return singleShardKey(args.slice(1));
|
|
2358
|
+
}
|
|
2359
|
+
if (name === "MSET") {
|
|
2360
|
+
const keys = [];
|
|
2361
|
+
for (let index = 1; index < args.length; index += 2) {
|
|
2362
|
+
keys.push(args[index]);
|
|
2363
|
+
}
|
|
2364
|
+
return singleShardKey(keys);
|
|
2365
|
+
}
|
|
2366
|
+
if (name === "BITOP") {
|
|
2367
|
+
return bitopRoutingKey(args);
|
|
2368
|
+
}
|
|
2369
|
+
if (name === "RENAME" || name === "RENAMENX") {
|
|
2370
|
+
return singleShardKey(args.slice(1, 3));
|
|
2371
|
+
}
|
|
2372
|
+
if (name === "XREAD" || name === "XREADGROUP") {
|
|
2373
|
+
return streamReadRoutingKey(args);
|
|
2374
|
+
}
|
|
2375
|
+
if (name.startsWith("FLOW.")) {
|
|
2376
|
+
return flowRoutingKey(name, args);
|
|
2377
|
+
}
|
|
2378
|
+
if (firstKeyCommands.has(name)) {
|
|
2379
|
+
const key = args[1];
|
|
2380
|
+
return typeof key === "string" || Buffer4.isBuffer(key) ? key : void 0;
|
|
2381
|
+
}
|
|
2382
|
+
return void 0;
|
|
2383
|
+
}
|
|
2384
|
+
function flowRoutingKey(name, args) {
|
|
2385
|
+
const flowArgs = args.slice(1);
|
|
2386
|
+
if (flowArgs.length === 0) {
|
|
2387
|
+
return void 0;
|
|
2388
|
+
}
|
|
2389
|
+
if (name === "FLOW.CLAIM_DUE" || name === "FLOW.RECLAIM") {
|
|
2390
|
+
return flowPartitionRoutingKey(flowArgs, 1);
|
|
2391
|
+
}
|
|
2392
|
+
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") {
|
|
2393
|
+
const partition2 = flowArgs[0];
|
|
2394
|
+
if (typeof partition2 === "string" && partition2.toUpperCase() !== "AUTO" && partition2.toUpperCase() !== "MIXED") {
|
|
2395
|
+
return partition2;
|
|
2396
|
+
}
|
|
2397
|
+
if (Buffer4.isBuffer(partition2)) {
|
|
2398
|
+
const text2 = partition2.toString("utf8").toUpperCase();
|
|
2399
|
+
if (text2 !== "AUTO" && text2 !== "MIXED") {
|
|
2400
|
+
return partition2;
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
return void 0;
|
|
2404
|
+
}
|
|
2405
|
+
const partition = flowPartitionRoutingKey(flowArgs, 1);
|
|
2406
|
+
if (partition != null) {
|
|
2407
|
+
return partition;
|
|
2408
|
+
}
|
|
2409
|
+
if (typeScopedFlowCommands.has(name)) {
|
|
2410
|
+
return void 0;
|
|
2411
|
+
}
|
|
2412
|
+
const id = flowArgs[0];
|
|
2413
|
+
return typeof id === "string" || Buffer4.isBuffer(id) ? id : void 0;
|
|
2414
|
+
}
|
|
2415
|
+
function bitopRoutingKey(args) {
|
|
2416
|
+
if (args.length < 4) {
|
|
2417
|
+
return void 0;
|
|
2418
|
+
}
|
|
2419
|
+
return singleShardKey(args.slice(2));
|
|
2420
|
+
}
|
|
2421
|
+
function streamReadRoutingKey(args) {
|
|
2422
|
+
const streamsIndex = args.findIndex((arg) => commandPart(arg) === "STREAMS");
|
|
2423
|
+
if (streamsIndex < 0) {
|
|
2424
|
+
return void 0;
|
|
2425
|
+
}
|
|
2426
|
+
const streamArgs = args.slice(streamsIndex + 1);
|
|
2427
|
+
if (streamArgs.length === 0 || streamArgs.length % 2 !== 0) {
|
|
2428
|
+
return void 0;
|
|
2429
|
+
}
|
|
2430
|
+
return singleShardKey(streamArgs.slice(0, streamArgs.length / 2));
|
|
2431
|
+
}
|
|
2432
|
+
function flowPartitionRoutingKey(args, start) {
|
|
2433
|
+
for (let index = start; index < args.length; index += 1) {
|
|
2434
|
+
const token = commandPart(args[index]);
|
|
2435
|
+
if (token === "PARTITION") {
|
|
2436
|
+
const key = args[index + 1];
|
|
2437
|
+
return typeof key === "string" || Buffer4.isBuffer(key) ? key : void 0;
|
|
2438
|
+
}
|
|
2439
|
+
if (token === "PARTITIONS") {
|
|
2440
|
+
const count = Number(args[index + 1]);
|
|
2441
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
2442
|
+
return void 0;
|
|
2443
|
+
}
|
|
2444
|
+
return singleShardKey(args.slice(index + 2, index + 2 + count));
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
return void 0;
|
|
2448
|
+
}
|
|
2449
|
+
function singleShardKey(keys) {
|
|
2450
|
+
const usable = keys.filter((key) => typeof key === "string" || Buffer4.isBuffer(key));
|
|
2451
|
+
if (usable.length === 0) {
|
|
2452
|
+
return void 0;
|
|
2453
|
+
}
|
|
2454
|
+
const first = usable[0];
|
|
2455
|
+
if (first == null) {
|
|
2456
|
+
return void 0;
|
|
2457
|
+
}
|
|
2458
|
+
const firstSlot = RoutingTopology.slotForKey(first);
|
|
2459
|
+
return usable.every((key) => RoutingTopology.slotForKey(key) === firstSlot) ? first : void 0;
|
|
2460
|
+
}
|
|
2461
|
+
function commandName(args) {
|
|
2462
|
+
const first = commandPart(args[0]);
|
|
2463
|
+
if (first == null) {
|
|
2464
|
+
return void 0;
|
|
2465
|
+
}
|
|
2466
|
+
if (first === "FLOW" && args.length > 1) {
|
|
2467
|
+
const second = commandPart(args[1]);
|
|
2468
|
+
return second == null ? first : `${first}.${second}`;
|
|
2469
|
+
}
|
|
2470
|
+
if (first === "CLIENT" && args.length > 1) {
|
|
2471
|
+
const second = commandPart(args[1]);
|
|
2472
|
+
return second == null ? first : `${first}.${second}`;
|
|
2473
|
+
}
|
|
2474
|
+
if (first === "CLUSTER" && args.length > 1) {
|
|
2475
|
+
const second = commandPart(args[1]);
|
|
2476
|
+
return second == null ? first : `${first}.${second}`;
|
|
2477
|
+
}
|
|
2478
|
+
return first;
|
|
2479
|
+
}
|
|
2480
|
+
function commandPart(value) {
|
|
2481
|
+
if (typeof value === "string") {
|
|
2482
|
+
return value.toUpperCase();
|
|
2483
|
+
}
|
|
2484
|
+
if (Buffer4.isBuffer(value)) {
|
|
2485
|
+
return value.toString("utf8").toUpperCase();
|
|
2486
|
+
}
|
|
2487
|
+
return void 0;
|
|
2488
|
+
}
|
|
2489
|
+
function isPlainObject2(value) {
|
|
2490
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer4.isBuffer(value);
|
|
2491
|
+
}
|
|
2492
|
+
function getField(source, ...keys) {
|
|
2493
|
+
if (source instanceof Map) {
|
|
2494
|
+
for (const key of keys) {
|
|
2495
|
+
if (source.has(key)) return source.get(key);
|
|
2496
|
+
const bufferKey = Buffer4.from(key);
|
|
2497
|
+
for (const [itemKey, value] of source.entries()) {
|
|
2498
|
+
if (Buffer4.isBuffer(itemKey) && itemKey.equals(bufferKey)) {
|
|
2499
|
+
return value;
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
return void 0;
|
|
2504
|
+
}
|
|
2505
|
+
if (isPlainObject2(source)) {
|
|
2506
|
+
for (const key of keys) {
|
|
2507
|
+
if (key in source) return source[key];
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
return void 0;
|
|
2511
|
+
}
|
|
2512
|
+
function textOrUndefined(value) {
|
|
2513
|
+
if (typeof value === "string") {
|
|
2514
|
+
return value;
|
|
2515
|
+
}
|
|
2516
|
+
if (Buffer4.isBuffer(value)) {
|
|
2517
|
+
return value.toString("utf8");
|
|
2518
|
+
}
|
|
2519
|
+
return void 0;
|
|
2520
|
+
}
|
|
2521
|
+
function numberOrUndefined(value) {
|
|
2522
|
+
return typeof value === "number" && Number.isInteger(value) ? value : void 0;
|
|
2523
|
+
}
|
|
2524
|
+
function endpointFromRange(item) {
|
|
2525
|
+
const endpointValue = getField(item, "endpoint");
|
|
2526
|
+
const raw = isPlainObject2(endpointValue) || endpointValue instanceof Map ? endpointValue : item;
|
|
2527
|
+
const host = textOrUndefined(getField(raw, "host", "native_host"));
|
|
2528
|
+
const nativePort = numberOrUndefined(getField(raw, "native_port"));
|
|
2529
|
+
if (host == null || nativePort == null) {
|
|
2530
|
+
throw new FerricStoreError("invalid SHARDS endpoint", { raw: item });
|
|
2531
|
+
}
|
|
2532
|
+
const nativeTlsPort = numberOrUndefined(getField(raw, "native_tls_port"));
|
|
2533
|
+
return {
|
|
2534
|
+
host,
|
|
2535
|
+
nativePort,
|
|
2536
|
+
node: textOrUndefined(getField(raw, "node", "leader_node", "owner_node")) ?? host,
|
|
2537
|
+
...nativeTlsPort == null ? {} : { nativeTlsPort }
|
|
2538
|
+
};
|
|
2539
|
+
}
|
|
2540
|
+
function endpointFromUrl(url) {
|
|
2541
|
+
const parsed = parseFerricUrl2(url);
|
|
2542
|
+
return {
|
|
2543
|
+
host: parsed.host,
|
|
2544
|
+
nativePort: parsed.port,
|
|
2545
|
+
node: parsed.host,
|
|
2546
|
+
...parsed.tls ? { nativeTlsPort: parsed.port } : {}
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
function parseFerricUrl2(value) {
|
|
2550
|
+
const url = new URL(value);
|
|
2551
|
+
if (url.protocol !== "ferric:" && url.protocol !== "ferrics:") {
|
|
2552
|
+
throw new FerricStoreError(`unsupported FerricStore URL scheme: ${url.protocol}`);
|
|
2553
|
+
}
|
|
2554
|
+
return {
|
|
2555
|
+
host: url.hostname || "127.0.0.1",
|
|
2556
|
+
...url.password === "" ? {} : { password: decodeURIComponent(url.password) },
|
|
2557
|
+
port: Number(url.port || (url.protocol === "ferrics:" ? 6389 : 6388)),
|
|
2558
|
+
tls: url.protocol === "ferrics:",
|
|
2559
|
+
...url.username === "" ? {} : { username: decodeURIComponent(url.username) }
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
function endpointKeyFor(endpoint) {
|
|
2563
|
+
return `${endpoint.host.toLowerCase()}:${endpoint.nativePort}`;
|
|
2564
|
+
}
|
|
2565
|
+
function urlFromEndpoint(endpoint, useTls) {
|
|
2566
|
+
const port = useTls && endpoint.nativeTlsPort != null ? endpoint.nativeTlsPort : endpoint.nativePort;
|
|
2567
|
+
const host = endpoint.host.includes(":") && !endpoint.host.startsWith("[") ? `[${endpoint.host}]` : endpoint.host;
|
|
2568
|
+
return `${useTls ? "ferrics" : "ferric"}://${host}:${port}`;
|
|
2569
|
+
}
|
|
2570
|
+
function nativeOnlyOptions(options) {
|
|
2571
|
+
const nativeOptions = { ...options };
|
|
2572
|
+
delete nativeOptions.endpointPolicy;
|
|
2573
|
+
delete nativeOptions.endpointValidator;
|
|
2574
|
+
delete nativeOptions.haRouting;
|
|
2575
|
+
delete nativeOptions.seeds;
|
|
2576
|
+
delete nativeOptions.trustedHosts;
|
|
2577
|
+
delete nativeOptions.warmConnections;
|
|
2578
|
+
return nativeOptions;
|
|
2579
|
+
}
|
|
2580
|
+
function withSeedAuthDefaults(urls, options) {
|
|
2581
|
+
const next = { ...options };
|
|
2582
|
+
for (const url of urls) {
|
|
2583
|
+
const parsed = parseFerricUrl2(url);
|
|
2584
|
+
if (next.username == null && parsed.username != null) {
|
|
2585
|
+
next.username = parsed.username;
|
|
2586
|
+
}
|
|
2587
|
+
if (next.password == null && parsed.password != null) {
|
|
2588
|
+
next.password = parsed.password;
|
|
2589
|
+
}
|
|
2590
|
+
if (next.username != null && next.password != null) {
|
|
2591
|
+
break;
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
return next;
|
|
2595
|
+
}
|
|
2596
|
+
function isRetryableRouteError(error) {
|
|
2597
|
+
if (!(error instanceof Error)) {
|
|
2598
|
+
return false;
|
|
2599
|
+
}
|
|
2600
|
+
const message = error.message.toLowerCase();
|
|
2601
|
+
return message.includes("connection closed") || message.includes("connection is closed") || message.includes("shard not available") || message.includes("leader") || message.includes("route");
|
|
2602
|
+
}
|
|
2603
|
+
function normalizedHostSet(hosts) {
|
|
2604
|
+
return new Set(hosts.filter((host) => host != null && host !== "").map((host) => host.toLowerCase()));
|
|
2605
|
+
}
|
|
2606
|
+
function hashTagOrKey(key) {
|
|
2607
|
+
const start = key.indexOf("{");
|
|
2608
|
+
if (start < 0) {
|
|
2609
|
+
return key;
|
|
2610
|
+
}
|
|
2611
|
+
const end = key.indexOf("}", start + 1);
|
|
2612
|
+
return end > start + 1 ? key.slice(start + 1, end) : key;
|
|
2613
|
+
}
|
|
2614
|
+
function flowHashTag(rest, fallbackKey) {
|
|
2615
|
+
const end = rest.indexOf("}");
|
|
2616
|
+
return end > 0 ? rest.slice(0, end) : hashTagOrKey(fallbackKey);
|
|
2617
|
+
}
|
|
2618
|
+
var crc32Table = new Uint32Array(256);
|
|
2619
|
+
for (let index = 0; index < 256; index += 1) {
|
|
2620
|
+
let value = index;
|
|
2621
|
+
for (let bit = 0; bit < 8; bit += 1) {
|
|
2622
|
+
value = (value & 1) !== 0 ? 3988292384 ^ value >>> 1 : value >>> 1;
|
|
2623
|
+
}
|
|
2624
|
+
crc32Table[index] = value >>> 0;
|
|
2625
|
+
}
|
|
2626
|
+
function crc32(buffer) {
|
|
2627
|
+
let value = 4294967295;
|
|
2628
|
+
for (const byte of buffer) {
|
|
2629
|
+
value = value >>> 8 ^ (crc32Table[(value ^ byte) & 255] ?? 0);
|
|
2630
|
+
}
|
|
2631
|
+
return (value ^ 4294967295) >>> 0;
|
|
2632
|
+
}
|
|
2633
|
+
var firstKeyCommands = /* @__PURE__ */ new Set([
|
|
2634
|
+
"BITCOUNT",
|
|
2635
|
+
"BITFIELD",
|
|
2636
|
+
"BITPOS",
|
|
2637
|
+
"CAS",
|
|
2638
|
+
"EXISTS",
|
|
2639
|
+
"EXPIRE",
|
|
2640
|
+
"EXPIREAT",
|
|
2641
|
+
"FETCH_OR_COMPUTE",
|
|
2642
|
+
"FETCH_OR_COMPUTE_ERROR",
|
|
2643
|
+
"FETCH_OR_COMPUTE_RESULT",
|
|
2644
|
+
"FERRICSTORE.KEY_INFO",
|
|
2645
|
+
"GET",
|
|
2646
|
+
"GETBIT",
|
|
2647
|
+
"GETDEL",
|
|
2648
|
+
"GETEX",
|
|
2649
|
+
"HDEL",
|
|
2650
|
+
"HEXISTS",
|
|
2651
|
+
"HGET",
|
|
2652
|
+
"HGETALL",
|
|
2653
|
+
"HINCRBY",
|
|
2654
|
+
"HKEYS",
|
|
2655
|
+
"HLEN",
|
|
2656
|
+
"HMGET",
|
|
2657
|
+
"HMSET",
|
|
2658
|
+
"HSET",
|
|
2659
|
+
"HVALS",
|
|
2660
|
+
"LOCK",
|
|
2661
|
+
"LPOP",
|
|
2662
|
+
"LPUSH",
|
|
2663
|
+
"LRANGE",
|
|
2664
|
+
"LREM",
|
|
2665
|
+
"RATELIMIT.ADD",
|
|
2666
|
+
"RPOP",
|
|
2667
|
+
"RPUSH",
|
|
2668
|
+
"SADD",
|
|
2669
|
+
"SCARD",
|
|
2670
|
+
"SISMEMBER",
|
|
2671
|
+
"SMEMBERS",
|
|
2672
|
+
"SREM",
|
|
2673
|
+
"SET",
|
|
2674
|
+
"SETBIT",
|
|
2675
|
+
"STRLEN",
|
|
2676
|
+
"TTL",
|
|
2677
|
+
"TYPE",
|
|
2678
|
+
"UNLINK",
|
|
2679
|
+
"UNLOCK",
|
|
2680
|
+
"XADD",
|
|
2681
|
+
"XLEN",
|
|
2682
|
+
"XRANGE",
|
|
2683
|
+
"ZADD",
|
|
2684
|
+
"ZCARD",
|
|
2685
|
+
"ZRANGE",
|
|
2686
|
+
"ZREM",
|
|
2687
|
+
"ZSCORE"
|
|
2688
|
+
]);
|
|
2689
|
+
var typeScopedFlowCommands = /* @__PURE__ */ new Set([
|
|
2690
|
+
"FLOW.APPROVAL.LIST",
|
|
2691
|
+
"FLOW.ATTRIBUTE_VALUES",
|
|
2692
|
+
"FLOW.ATTRIBUTES",
|
|
2693
|
+
"FLOW.BUDGET.LIST",
|
|
2694
|
+
"FLOW.FAILURES",
|
|
2695
|
+
"FLOW.GOVERNANCE.OVERVIEW",
|
|
2696
|
+
"FLOW.INFO",
|
|
2697
|
+
"FLOW.LIMIT.LIST",
|
|
2698
|
+
"FLOW.LIST",
|
|
2699
|
+
"FLOW.POLICY.GET",
|
|
2700
|
+
"FLOW.POLICY.SET",
|
|
2701
|
+
"FLOW.RETENTION_CLEANUP",
|
|
2702
|
+
"FLOW.SCHEDULE.FIRE_DUE",
|
|
2703
|
+
"FLOW.SCHEDULE.LIST",
|
|
2704
|
+
"FLOW.SEARCH",
|
|
2705
|
+
"FLOW.STATS",
|
|
2706
|
+
"FLOW.STUCK",
|
|
2707
|
+
"FLOW.TERMINALS"
|
|
2708
|
+
]);
|
|
2709
|
+
|
|
1734
2710
|
// src/codecs.ts
|
|
1735
2711
|
var RawCodec = class {
|
|
1736
2712
|
encode(value) {
|
|
@@ -1944,7 +2920,7 @@ function parseKvResponse(value) {
|
|
|
1944
2920
|
return { value };
|
|
1945
2921
|
}
|
|
1946
2922
|
function autoPartitionKeyForId(id) {
|
|
1947
|
-
return `${AUTO_PARTITION_PREFIX}${
|
|
2923
|
+
return `${AUTO_PARTITION_PREFIX}${crc322(Buffer.from(id)) % AUTO_PARTITION_BUCKETS}`;
|
|
1948
2924
|
}
|
|
1949
2925
|
function expandManyResponse(value, count) {
|
|
1950
2926
|
if (Array.isArray(value) && value.length === count) {
|
|
@@ -2014,7 +2990,7 @@ function coerceDiagnosticValue(value) {
|
|
|
2014
2990
|
}
|
|
2015
2991
|
return value;
|
|
2016
2992
|
}
|
|
2017
|
-
function
|
|
2993
|
+
function crc322(buffer) {
|
|
2018
2994
|
let crc = 4294967295;
|
|
2019
2995
|
for (const byte of buffer) {
|
|
2020
2996
|
crc ^= byte;
|
|
@@ -2940,14 +3916,14 @@ function claimedItemFromResp(value, codec) {
|
|
|
2940
3916
|
const partition = tuple[1] == null ? null : bytes(tuple[1]);
|
|
2941
3917
|
const leaseToken = bytes(tuple[2]);
|
|
2942
3918
|
const fencingToken = integer(tuple[3]);
|
|
2943
|
-
const attrs = tuple[5] ?? (
|
|
3919
|
+
const attrs = tuple[5] ?? (isPlainObject3(tuple[4]) ? tuple[4] : void 0);
|
|
2944
3920
|
const item = {
|
|
2945
3921
|
id: text(id),
|
|
2946
3922
|
partitionKey: optionalString(partition),
|
|
2947
3923
|
leaseToken,
|
|
2948
3924
|
fencingToken,
|
|
2949
3925
|
runState: optionalString(tuple[4]),
|
|
2950
|
-
attributes:
|
|
3926
|
+
attributes: isPlainObject3(attrs) ? attrs : void 0,
|
|
2951
3927
|
type: "",
|
|
2952
3928
|
state: "running"
|
|
2953
3929
|
};
|
|
@@ -3067,9 +4043,9 @@ function decodeValues(value, codec) {
|
|
|
3067
4043
|
}
|
|
3068
4044
|
function plainObjectField(value, key) {
|
|
3069
4045
|
const item = field(value, key);
|
|
3070
|
-
return
|
|
4046
|
+
return isPlainObject3(item) ? item : void 0;
|
|
3071
4047
|
}
|
|
3072
|
-
function
|
|
4048
|
+
function isPlainObject3(value) {
|
|
3073
4049
|
return typeof value === "object" && value != null && !Buffer.isBuffer(value) && !(value instanceof Uint8Array) && !Array.isArray(value);
|
|
3074
4050
|
}
|
|
3075
4051
|
|
|
@@ -3121,7 +4097,18 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3121
4097
|
}
|
|
3122
4098
|
static async fromUrl(url, options = {}) {
|
|
3123
4099
|
const reconnectOptions = options.reconnect ?? options.nativeOptions?.autoReconnect ?? true;
|
|
3124
|
-
const
|
|
4100
|
+
const nativeOptions = options.nativeOptions ?? {};
|
|
4101
|
+
const seeds = nativeOptions.seeds ?? [];
|
|
4102
|
+
const createExecutor = async () => nativeOptions.haRouting === true || seeds.length > 0 ? await TopologyNativeAdapterPool.fromUrls([url, ...seeds], nativeOptions) : await NativeAdapter.fromUrl(url, nativeOptions);
|
|
4103
|
+
const executor = reconnectOptions === false ? await createExecutor() : new ReconnectingExecutor(createExecutor, reconnectOptions === true ? {} : reconnectOptions);
|
|
4104
|
+
return new _FerricStoreClient(executor, options);
|
|
4105
|
+
}
|
|
4106
|
+
static async fromUrls(urls, options = {}) {
|
|
4107
|
+
if (urls.length === 0) {
|
|
4108
|
+
throw new Error("FerricStoreClient.fromUrls requires at least one URL");
|
|
4109
|
+
}
|
|
4110
|
+
const reconnectOptions = options.reconnect ?? options.nativeOptions?.autoReconnect ?? true;
|
|
4111
|
+
const createExecutor = async () => await TopologyNativeAdapterPool.fromUrls(urls, options.nativeOptions);
|
|
3125
4112
|
const executor = reconnectOptions === false ? await createExecutor() : new ReconnectingExecutor(createExecutor, reconnectOptions === true ? {} : reconnectOptions);
|
|
3126
4113
|
return new _FerricStoreClient(executor, options);
|
|
3127
4114
|
}
|
|
@@ -3137,6 +4124,18 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3137
4124
|
async close() {
|
|
3138
4125
|
await this.executor.close?.();
|
|
3139
4126
|
}
|
|
4127
|
+
async refreshTopology() {
|
|
4128
|
+
if (this.executor.refreshTopology == null) {
|
|
4129
|
+
throw new Error("topology refresh requires a topology-aware native executor");
|
|
4130
|
+
}
|
|
4131
|
+
return await this.executor.refreshTopology();
|
|
4132
|
+
}
|
|
4133
|
+
async route(key) {
|
|
4134
|
+
if (this.executor.route == null) {
|
|
4135
|
+
throw new Error("route lookup requires a topology-aware native executor");
|
|
4136
|
+
}
|
|
4137
|
+
return await this.executor.route(key);
|
|
4138
|
+
}
|
|
3140
4139
|
async ping(message) {
|
|
3141
4140
|
return await this.command("PING", ...message == null ? [] : [message]);
|
|
3142
4141
|
}
|
|
@@ -3199,7 +4198,7 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3199
4198
|
return response == null ? null : text(response);
|
|
3200
4199
|
}
|
|
3201
4200
|
async clientInfo() {
|
|
3202
|
-
return
|
|
4201
|
+
return infoText(await this.command("CLIENT", "INFO"));
|
|
3203
4202
|
}
|
|
3204
4203
|
async clientList(options = {}) {
|
|
3205
4204
|
return text(await this.command("CLIENT", "LIST", ...options.type == null ? [] : ["TYPE", options.type]));
|
|
@@ -3254,7 +4253,7 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3254
4253
|
return Number(await this.command("PUBSUB", "NUMPAT"));
|
|
3255
4254
|
}
|
|
3256
4255
|
async aclSetUser(username, rules) {
|
|
3257
|
-
return okResponse(await this.command("ACL", "SETUSER", username, ...rules));
|
|
4256
|
+
return okResponse(await this.command("ACL", "SETUSER", username, ...ruleArgs(rules)));
|
|
3258
4257
|
}
|
|
3259
4258
|
async aclDelUser(...usernames) {
|
|
3260
4259
|
return Number(await this.command("ACL", "DELUSER", ...usernames));
|
|
@@ -3265,6 +4264,9 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3265
4264
|
async aclList() {
|
|
3266
4265
|
return arrayResponse(await this.command("ACL", "LIST"));
|
|
3267
4266
|
}
|
|
4267
|
+
async aclListUsers() {
|
|
4268
|
+
return await this.aclList();
|
|
4269
|
+
}
|
|
3268
4270
|
async aclWhoami() {
|
|
3269
4271
|
return text(await this.command("ACL", "WHOAMI"));
|
|
3270
4272
|
}
|
|
@@ -3360,6 +4362,107 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3360
4362
|
async ferricstoreDoctor(...args) {
|
|
3361
4363
|
return await this.command("FERRICSTORE.DOCTOR", ...args);
|
|
3362
4364
|
}
|
|
4365
|
+
async capabilities() {
|
|
4366
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.CAPABILITIES"));
|
|
4367
|
+
}
|
|
4368
|
+
async ensureNamespace(prefix, attrs = {}) {
|
|
4369
|
+
return normalizeAdminResponse(
|
|
4370
|
+
await this.command("FERRICSTORE.NAMESPACE", "ENSURE", prefix, ...managementPairArgs(attrs))
|
|
4371
|
+
);
|
|
4372
|
+
}
|
|
4373
|
+
async getNamespace(prefix) {
|
|
4374
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.NAMESPACE", "GET", prefix));
|
|
4375
|
+
}
|
|
4376
|
+
async listNamespaces() {
|
|
4377
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.NAMESPACE", "LIST"));
|
|
4378
|
+
}
|
|
4379
|
+
async deleteNamespace(prefix) {
|
|
4380
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.NAMESPACE", "DELETE", prefix));
|
|
4381
|
+
}
|
|
4382
|
+
async setQuota(namespace, quotaSpec = {}) {
|
|
4383
|
+
return normalizeAdminResponse(
|
|
4384
|
+
await this.command("FERRICSTORE.QUOTA", "SET", namespace, ...managementPairArgs(quotaSpec))
|
|
4385
|
+
);
|
|
4386
|
+
}
|
|
4387
|
+
async getQuota(namespace) {
|
|
4388
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.QUOTA", "GET", namespace));
|
|
4389
|
+
}
|
|
4390
|
+
async quotaUsage(namespace) {
|
|
4391
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.QUOTA", "USAGE", namespace));
|
|
4392
|
+
}
|
|
4393
|
+
async clusterInfo() {
|
|
4394
|
+
return normalizeAdminResponse(await this.command("FERRICSTORE.TELEMETRY", "CLUSTER_INFO"));
|
|
4395
|
+
}
|
|
4396
|
+
async namespaceUsage(prefix) {
|
|
4397
|
+
return normalizeAdminResponse(
|
|
4398
|
+
await this.command("FERRICSTORE.TELEMETRY", "NAMESPACE_USAGE", prefix)
|
|
4399
|
+
);
|
|
4400
|
+
}
|
|
4401
|
+
async flowQuery(attrs = {}) {
|
|
4402
|
+
const response = normalizeAdminResponse(
|
|
4403
|
+
await this.command("FERRICSTORE.TELEMETRY", "FLOW_QUERY", ...managementPairArgs(attrs))
|
|
4404
|
+
);
|
|
4405
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4406
|
+
}
|
|
4407
|
+
async flowHistory(id, attrs = {}) {
|
|
4408
|
+
const response = normalizeAdminResponse(
|
|
4409
|
+
await this.command("FERRICSTORE.TELEMETRY", "FLOW_HISTORY", id, ...managementPairArgs(attrs))
|
|
4410
|
+
);
|
|
4411
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4412
|
+
}
|
|
4413
|
+
async invocationDefinitionPut(definition, options = {}) {
|
|
4414
|
+
return normalizeAdminResponse(
|
|
4415
|
+
await this.command(
|
|
4416
|
+
...commandWithRequestContext(
|
|
4417
|
+
"INVOCATION.DEFINITION.PUT",
|
|
4418
|
+
[jsonArg(definition)],
|
|
4419
|
+
options.requestContext
|
|
4420
|
+
)
|
|
4421
|
+
)
|
|
4422
|
+
);
|
|
4423
|
+
}
|
|
4424
|
+
async invocationDefinitionGet(name, options = {}) {
|
|
4425
|
+
return normalizeAdminResponse(
|
|
4426
|
+
await this.command(
|
|
4427
|
+
...commandWithRequestContext("INVOCATION.DEFINITION.GET", [name], options.requestContext)
|
|
4428
|
+
)
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
4431
|
+
async invocationDefinitionList(options = {}) {
|
|
4432
|
+
const response = normalizeAdminResponse(
|
|
4433
|
+
await this.command(
|
|
4434
|
+
...commandWithRequestContext("INVOCATION.DEFINITION.LIST", [], options.requestContext)
|
|
4435
|
+
)
|
|
4436
|
+
);
|
|
4437
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4438
|
+
}
|
|
4439
|
+
async invocationCreate(name, attrs, options = {}) {
|
|
4440
|
+
const envelope = { attrs };
|
|
4441
|
+
if (options.context != null) {
|
|
4442
|
+
envelope.context = options.context;
|
|
4443
|
+
}
|
|
4444
|
+
if (options.idempotencyKey != null) {
|
|
4445
|
+
envelope.idempotency_key = options.idempotencyKey;
|
|
4446
|
+
}
|
|
4447
|
+
return normalizeAdminResponse(
|
|
4448
|
+
await this.command(
|
|
4449
|
+
...commandWithRequestContext("INVOCATION.CREATE", [name, jsonArg(envelope)], options.requestContext)
|
|
4450
|
+
)
|
|
4451
|
+
);
|
|
4452
|
+
}
|
|
4453
|
+
async invocationGet(id, options = {}) {
|
|
4454
|
+
return normalizeAdminResponse(
|
|
4455
|
+
await this.command(...commandWithRequestContext("INVOCATION.GET", [id], options.requestContext))
|
|
4456
|
+
);
|
|
4457
|
+
}
|
|
4458
|
+
async invocationPartitionList(name, options = {}) {
|
|
4459
|
+
const args = [name];
|
|
4460
|
+
append(args, "SCOPE", options.scope);
|
|
4461
|
+
const response = normalizeAdminResponse(
|
|
4462
|
+
await this.command(...commandWithRequestContext("INVOCATION.PARTITION.LIST", args, options.requestContext))
|
|
4463
|
+
);
|
|
4464
|
+
return Array.isArray(response) ? [...response] : [];
|
|
4465
|
+
}
|
|
3363
4466
|
async create(id, options) {
|
|
3364
4467
|
const currentNowMs = options.nowMs ?? nowMs();
|
|
3365
4468
|
const args = [
|
|
@@ -3392,7 +4495,6 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3392
4495
|
async enqueue(id, options) {
|
|
3393
4496
|
return await this.create(id, {
|
|
3394
4497
|
...options,
|
|
3395
|
-
priority: options.priority ?? 0,
|
|
3396
4498
|
state: options.state ?? "queued"
|
|
3397
4499
|
});
|
|
3398
4500
|
}
|
|
@@ -3404,7 +4506,6 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3404
4506
|
return await this.createMany(options.partitionKey, items, {
|
|
3405
4507
|
...options,
|
|
3406
4508
|
independent: options.independent ?? true,
|
|
3407
|
-
priority: options.priority ?? 0,
|
|
3408
4509
|
state: options.state ?? "queued"
|
|
3409
4510
|
});
|
|
3410
4511
|
}
|
|
@@ -3419,7 +4520,6 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3419
4520
|
const response = await this.createMany(bucket, groupItems, {
|
|
3420
4521
|
...options,
|
|
3421
4522
|
independent: options.independent ?? true,
|
|
3422
|
-
priority: options.priority ?? 0,
|
|
3423
4523
|
state: options.state ?? "queued"
|
|
3424
4524
|
});
|
|
3425
4525
|
const expanded = expandManyResponse(response, indexedItems.length);
|
|
@@ -3572,8 +4672,7 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3572
4672
|
...options,
|
|
3573
4673
|
includeState: options.includeState ?? false,
|
|
3574
4674
|
jobOnly: true,
|
|
3575
|
-
limit: options.limit ?? 100
|
|
3576
|
-
priority: options.priority ?? 0
|
|
4675
|
+
limit: options.limit ?? 100
|
|
3577
4676
|
});
|
|
3578
4677
|
}
|
|
3579
4678
|
async reclaim(type, options) {
|
|
@@ -3840,6 +4939,14 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3840
4939
|
async list(type, options = {}) {
|
|
3841
4940
|
return await this.indexQuery("FLOW.LIST", type, options);
|
|
3842
4941
|
}
|
|
4942
|
+
async search(type, options = {}) {
|
|
4943
|
+
const args = ["FLOW.SEARCH", type];
|
|
4944
|
+
appendReadOptions(args, options);
|
|
4945
|
+
appendAttributes(args, options.attributes);
|
|
4946
|
+
appendSearchStateMeta(args, options.state, options.stateMeta);
|
|
4947
|
+
const response = await this.command(...args);
|
|
4948
|
+
return Array.isArray(response) ? this.records(response) : [];
|
|
4949
|
+
}
|
|
3843
4950
|
async terminals(type, options = {}) {
|
|
3844
4951
|
return await this.indexQuery("FLOW.TERMINALS", type, options);
|
|
3845
4952
|
}
|
|
@@ -3916,9 +5023,14 @@ var FerricStoreClient = class _FerricStoreClient {
|
|
|
3916
5023
|
const args = ["FLOW.POLICY.SET", type];
|
|
3917
5024
|
append(args, "INDEXED_STATE_META", options.indexedStateMeta);
|
|
3918
5025
|
append(args, "STATE", options.state);
|
|
5026
|
+
appendPolicyMode(args, options.state, options.mode);
|
|
3919
5027
|
if (options.retry != null) {
|
|
3920
5028
|
appendRetryPolicy(args, options.retry);
|
|
3921
5029
|
}
|
|
5030
|
+
for (const [state, policy] of Object.entries(options.states ?? {})) {
|
|
5031
|
+
args.push("STATE", state);
|
|
5032
|
+
appendFlowStatePolicy(args, policy);
|
|
5033
|
+
}
|
|
3922
5034
|
append(args, "RETENTION_TTL_MS", options.retentionTtlMs);
|
|
3923
5035
|
return await this.command(...args);
|
|
3924
5036
|
}
|
|
@@ -4009,6 +5121,18 @@ var ErrorMappingExecutor = class {
|
|
|
4009
5121
|
throwMapped(error);
|
|
4010
5122
|
}
|
|
4011
5123
|
}
|
|
5124
|
+
async refreshTopology() {
|
|
5125
|
+
if (this.executor.refreshTopology == null) {
|
|
5126
|
+
throw new Error("topology refresh requires a topology-aware native executor");
|
|
5127
|
+
}
|
|
5128
|
+
return await this.executor.refreshTopology();
|
|
5129
|
+
}
|
|
5130
|
+
async route(key) {
|
|
5131
|
+
if (this.executor.route == null) {
|
|
5132
|
+
throw new Error("route lookup requires a topology-aware native executor");
|
|
5133
|
+
}
|
|
5134
|
+
return await this.executor.route(key);
|
|
5135
|
+
}
|
|
4012
5136
|
async close() {
|
|
4013
5137
|
await this.executor.close?.();
|
|
4014
5138
|
}
|
|
@@ -4044,6 +5168,18 @@ var AutoBatchExecutor = class {
|
|
|
4044
5168
|
}
|
|
4045
5169
|
return await Promise.all(commands.map((command) => this.executor.executeCommand(...command)));
|
|
4046
5170
|
}
|
|
5171
|
+
async refreshTopology() {
|
|
5172
|
+
if (this.executor.refreshTopology == null) {
|
|
5173
|
+
throw new Error("topology refresh requires a topology-aware native executor");
|
|
5174
|
+
}
|
|
5175
|
+
return await this.executor.refreshTopology();
|
|
5176
|
+
}
|
|
5177
|
+
async route(key) {
|
|
5178
|
+
if (this.executor.route == null) {
|
|
5179
|
+
throw new Error("route lookup requires a topology-aware native executor");
|
|
5180
|
+
}
|
|
5181
|
+
return await this.executor.route(key);
|
|
5182
|
+
}
|
|
4047
5183
|
async close() {
|
|
4048
5184
|
this.scheduled = false;
|
|
4049
5185
|
if (this.timer != null) {
|
|
@@ -4204,7 +5340,7 @@ var neverAutoBatchCommandPrefixes = /* @__PURE__ */ new Set([
|
|
|
4204
5340
|
]);
|
|
4205
5341
|
var neverAutoBatchCommands = /* @__PURE__ */ new Set(["FLOW.CLAIM_DUE", "FLOW.RECLAIM"]);
|
|
4206
5342
|
function autoBatchCommandAllowed(command, mode) {
|
|
4207
|
-
const name =
|
|
5343
|
+
const name = commandName2(command);
|
|
4208
5344
|
if (name == null || neverAutoBatchCommands.has(name)) {
|
|
4209
5345
|
return false;
|
|
4210
5346
|
}
|
|
@@ -4214,18 +5350,18 @@ function autoBatchCommandAllowed(command, mode) {
|
|
|
4214
5350
|
}
|
|
4215
5351
|
return mode === "all" || safeAutoBatchCommands.has(name);
|
|
4216
5352
|
}
|
|
4217
|
-
function
|
|
4218
|
-
const first =
|
|
5353
|
+
function commandName2(command) {
|
|
5354
|
+
const first = commandPart2(command[0]);
|
|
4219
5355
|
if (first == null) {
|
|
4220
5356
|
return null;
|
|
4221
5357
|
}
|
|
4222
5358
|
if (first === "FLOW" && command.length > 1) {
|
|
4223
|
-
const second =
|
|
5359
|
+
const second = commandPart2(command[1]);
|
|
4224
5360
|
return second == null ? first : `${first}.${second}`;
|
|
4225
5361
|
}
|
|
4226
5362
|
return first;
|
|
4227
5363
|
}
|
|
4228
|
-
function
|
|
5364
|
+
function commandPart2(value) {
|
|
4229
5365
|
if (typeof value === "string") {
|
|
4230
5366
|
return value.toUpperCase();
|
|
4231
5367
|
}
|
|
@@ -4250,6 +5386,90 @@ function appendStateMeta(args, stateMeta) {
|
|
|
4250
5386
|
args.push("STATE_META", name, value);
|
|
4251
5387
|
}
|
|
4252
5388
|
}
|
|
5389
|
+
function appendAttributes(args, attributes) {
|
|
5390
|
+
for (const [name, value] of Object.entries(attributes ?? {})) {
|
|
5391
|
+
args.push("ATTRIBUTE", name, value);
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
function appendSearchStateMeta(args, state, stateMeta) {
|
|
5395
|
+
const entries = Object.entries(stateMeta ?? {});
|
|
5396
|
+
if (entries.length === 0) {
|
|
5397
|
+
return;
|
|
5398
|
+
}
|
|
5399
|
+
if (entries.every(([, value]) => isPlainObject4(value))) {
|
|
5400
|
+
for (const [metaState, values] of entries) {
|
|
5401
|
+
args.push("STATE_META", metaState, values);
|
|
5402
|
+
}
|
|
5403
|
+
return;
|
|
5404
|
+
}
|
|
5405
|
+
if (state == null) {
|
|
5406
|
+
throw new Error("search stateMeta filters require state or nested state metadata");
|
|
5407
|
+
}
|
|
5408
|
+
args.push("STATE_META", state, stateMeta);
|
|
5409
|
+
}
|
|
5410
|
+
function normalizeAdminResponse(value) {
|
|
5411
|
+
return normalizeRefMeta(value);
|
|
5412
|
+
}
|
|
5413
|
+
function jsonArg(value) {
|
|
5414
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
5415
|
+
}
|
|
5416
|
+
function commandWithRequestContext(command, args, requestContext) {
|
|
5417
|
+
const commandArgs = [command, ...args];
|
|
5418
|
+
if (requestContext != null) {
|
|
5419
|
+
commandArgs.push("REQUEST_CONTEXT", requestContext);
|
|
5420
|
+
}
|
|
5421
|
+
return commandArgs;
|
|
5422
|
+
}
|
|
5423
|
+
function infoText(value) {
|
|
5424
|
+
if (typeof value === "string" || Buffer.isBuffer(value)) {
|
|
5425
|
+
return text(value);
|
|
5426
|
+
}
|
|
5427
|
+
const normalized = normalizeRefMeta(value);
|
|
5428
|
+
if (isPlainObject4(normalized)) {
|
|
5429
|
+
return Object.entries(normalized).map(([key, item]) => `${key}=${diagnosticValueText(item)}`).join(" ");
|
|
5430
|
+
}
|
|
5431
|
+
return diagnosticValueText(normalized);
|
|
5432
|
+
}
|
|
5433
|
+
function diagnosticValueText(value) {
|
|
5434
|
+
if (value == null) {
|
|
5435
|
+
return "";
|
|
5436
|
+
}
|
|
5437
|
+
if (Buffer.isBuffer(value)) {
|
|
5438
|
+
return value.toString("utf8");
|
|
5439
|
+
}
|
|
5440
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
5441
|
+
return String(value);
|
|
5442
|
+
}
|
|
5443
|
+
return JSON.stringify(value);
|
|
5444
|
+
}
|
|
5445
|
+
function managementPairArgs(pairs2) {
|
|
5446
|
+
const args = [];
|
|
5447
|
+
for (const [key, value] of Object.entries(pairs2)) {
|
|
5448
|
+
if (value != null) {
|
|
5449
|
+
args.push(key.toUpperCase(), value);
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5452
|
+
return args;
|
|
5453
|
+
}
|
|
5454
|
+
function appendFlowStatePolicy(args, policy) {
|
|
5455
|
+
if (isFlowStatePolicy(policy)) {
|
|
5456
|
+
appendPolicyMode(args, "state", policy.mode);
|
|
5457
|
+
if (policy.retry != null) {
|
|
5458
|
+
appendRetryPolicy(args, policy.retry);
|
|
5459
|
+
}
|
|
5460
|
+
return;
|
|
5461
|
+
}
|
|
5462
|
+
appendRetryPolicy(args, policy);
|
|
5463
|
+
}
|
|
5464
|
+
function isFlowStatePolicy(policy) {
|
|
5465
|
+
return typeof policy === "object" && policy != null && ("mode" in policy || "retry" in policy);
|
|
5466
|
+
}
|
|
5467
|
+
function ruleArgs(rules) {
|
|
5468
|
+
return typeof rules === "string" ? [rules] : [...rules];
|
|
5469
|
+
}
|
|
5470
|
+
function isPlainObject4(value) {
|
|
5471
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && !Buffer.isBuffer(value);
|
|
5472
|
+
}
|
|
4253
5473
|
function sharedCreateManyStateMeta(items, stateMeta) {
|
|
4254
5474
|
const itemMetas = items.map((item) => item.stateMeta).filter((meta) => meta != null);
|
|
4255
5475
|
if (itemMetas.length === 0) {
|
|
@@ -4336,6 +5556,24 @@ function appendRetryPolicy(args, policy) {
|
|
|
4336
5556
|
append(args, "JITTER_PCT", policy.jitterPct);
|
|
4337
5557
|
append(args, "EXHAUSTED_TO", policy.exhaustedTo);
|
|
4338
5558
|
}
|
|
5559
|
+
function appendPolicyMode(args, state, mode) {
|
|
5560
|
+
if (mode == null) {
|
|
5561
|
+
return;
|
|
5562
|
+
}
|
|
5563
|
+
if (state == null) {
|
|
5564
|
+
throw new Error("policy mode requires state");
|
|
5565
|
+
}
|
|
5566
|
+
switch (mode) {
|
|
5567
|
+
case "fifo":
|
|
5568
|
+
args.push("MODE", "FIFO");
|
|
5569
|
+
return;
|
|
5570
|
+
case "parallel":
|
|
5571
|
+
args.push("MODE", "PARALLEL");
|
|
5572
|
+
return;
|
|
5573
|
+
default:
|
|
5574
|
+
throw new Error("policy mode must be 'fifo' or 'parallel'");
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
4339
5577
|
function appendPayloadRead(args, payload, maxBytes) {
|
|
4340
5578
|
if (payload === false) {
|
|
4341
5579
|
args.push("NOPAYLOAD");
|
|
@@ -4800,6 +6038,7 @@ var Workflow = class {
|
|
|
4800
6038
|
exceptionPolicy: normalizeExceptionPolicy(options.exceptionPolicy),
|
|
4801
6039
|
handler,
|
|
4802
6040
|
leaseMs: options.leaseMs ?? 3e4,
|
|
6041
|
+
...options.mode == null ? {} : { mode: normalizeStateMode(options.mode) },
|
|
4803
6042
|
name,
|
|
4804
6043
|
returnRecord: options.returnRecord ?? false,
|
|
4805
6044
|
valueMaxBytes: options.valueMaxBytes ?? this.valueConfig.valueMaxBytes,
|
|
@@ -4834,6 +6073,21 @@ var Workflow = class {
|
|
|
4834
6073
|
worker(options = {}) {
|
|
4835
6074
|
return new WorkflowWorker(this, options);
|
|
4836
6075
|
}
|
|
6076
|
+
async installPolicy(options = {}) {
|
|
6077
|
+
const states = {};
|
|
6078
|
+
for (const registration of this.states.values()) {
|
|
6079
|
+
if (registration.mode != null || registration.retryPolicy != null) {
|
|
6080
|
+
states[registration.name] = {
|
|
6081
|
+
...registration.mode == null ? {} : { mode: registration.mode },
|
|
6082
|
+
...registration.retryPolicy == null ? {} : { retry: registration.retryPolicy }
|
|
6083
|
+
};
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
6086
|
+
return await this.client.installPolicy(this.type, {
|
|
6087
|
+
...options,
|
|
6088
|
+
states
|
|
6089
|
+
});
|
|
6090
|
+
}
|
|
4837
6091
|
stateNames() {
|
|
4838
6092
|
return [...this.states.keys()];
|
|
4839
6093
|
}
|
|
@@ -5094,13 +6348,15 @@ var WorkflowWorker = class {
|
|
|
5094
6348
|
}
|
|
5095
6349
|
async applyJob(job, registration) {
|
|
5096
6350
|
const ctx = new WorkflowContext(this.workflow, job, registration.name);
|
|
6351
|
+
let outcome;
|
|
5097
6352
|
try {
|
|
5098
6353
|
const value = await registration.handler(ctx);
|
|
5099
|
-
|
|
5100
|
-
await applyOutcome(this.workflow.client, ctx, outcome, registration.returnRecord);
|
|
6354
|
+
outcome = isOutcome(value) ? value : complete({ result: value });
|
|
5101
6355
|
} catch (error) {
|
|
5102
6356
|
await this.applyHandlerError(ctx, registration, error);
|
|
6357
|
+
return;
|
|
5103
6358
|
}
|
|
6359
|
+
await applyOutcome(this.workflow.client, ctx, outcome, registration.returnRecord);
|
|
5104
6360
|
}
|
|
5105
6361
|
async applyHandlerError(ctx, registration, error) {
|
|
5106
6362
|
const policy = this.options.exceptionPolicy ?? registration.exceptionPolicy;
|
|
@@ -5131,6 +6387,7 @@ async function applyOutcome(client, ctx, outcome, returnRecord) {
|
|
|
5131
6387
|
}
|
|
5132
6388
|
}
|
|
5133
6389
|
async function applyTransition(client, ctx, outcome, returnRecord) {
|
|
6390
|
+
validateTransitionPolicy(ctx, outcome);
|
|
5134
6391
|
await client.transition(ctx.id, {
|
|
5135
6392
|
dropValues: outcome.dropValues,
|
|
5136
6393
|
fencingToken: ctx.fencingToken,
|
|
@@ -5148,6 +6405,12 @@ async function applyTransition(client, ctx, outcome, returnRecord) {
|
|
|
5148
6405
|
values: outcome.values
|
|
5149
6406
|
});
|
|
5150
6407
|
}
|
|
6408
|
+
function validateTransitionPolicy(ctx, outcome) {
|
|
6409
|
+
const target = ctx.workflow.stateRegistration(outcome.toState);
|
|
6410
|
+
if (target?.mode === "fifo" && outcome.priority != null) {
|
|
6411
|
+
throw new Error("priority is not supported for fifo state");
|
|
6412
|
+
}
|
|
6413
|
+
}
|
|
5151
6414
|
async function applyComplete(client, ctx, outcome, returnRecord) {
|
|
5152
6415
|
await client.complete(ctx.id, {
|
|
5153
6416
|
dropValues: outcome.dropValues,
|
|
@@ -5206,6 +6469,12 @@ function errorToPayload(error) {
|
|
|
5206
6469
|
}
|
|
5207
6470
|
return error;
|
|
5208
6471
|
}
|
|
6472
|
+
function normalizeStateMode(mode) {
|
|
6473
|
+
if (mode === "fifo" || mode === "parallel") {
|
|
6474
|
+
return mode;
|
|
6475
|
+
}
|
|
6476
|
+
throw new Error("state mode must be 'fifo' or 'parallel'");
|
|
6477
|
+
}
|
|
5209
6478
|
function valueRefToString(value) {
|
|
5210
6479
|
if (typeof value === "string") {
|
|
5211
6480
|
return value;
|
|
@@ -5222,6 +6491,7 @@ function valueRefToString(value) {
|
|
|
5222
6491
|
export {
|
|
5223
6492
|
BitmapStore,
|
|
5224
6493
|
BloomFilterStore,
|
|
6494
|
+
COMMAND_OPCODES,
|
|
5225
6495
|
CountMinSketchStore,
|
|
5226
6496
|
CuckooFilterStore,
|
|
5227
6497
|
FerricStoreClient,
|
|
@@ -5246,12 +6516,14 @@ export {
|
|
|
5246
6516
|
QueueWorker,
|
|
5247
6517
|
RawCodec,
|
|
5248
6518
|
ReconnectingExecutor,
|
|
6519
|
+
RoutingTopology,
|
|
5249
6520
|
SetStore,
|
|
5250
6521
|
SortedSetStore,
|
|
5251
6522
|
StaleLeaseError,
|
|
5252
6523
|
StreamStore,
|
|
5253
6524
|
TDigestStore,
|
|
5254
6525
|
TopKStore,
|
|
6526
|
+
TopologyNativeAdapterPool,
|
|
5255
6527
|
Workflow,
|
|
5256
6528
|
WorkflowClient,
|
|
5257
6529
|
WorkflowContext,
|