rivetkit 2.3.11-rc.8 → 2.3.11
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/dist/browser/client.d.ts +96 -14
- package/dist/browser/client.js +12 -2
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.d.ts +139 -139
- package/dist/browser/inspector/client.js +12 -2
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/agent-os/index.cjs +146 -76
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +83 -9
- package/dist/tsup/agent-os/index.d.ts +83 -9
- package/dist/tsup/agent-os/index.js +146 -76
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-JBQ63WSM.js → chunk-3ZR542SK.js} +4 -4
- package/dist/tsup/chunk-3ZR542SK.js.map +1 -0
- package/dist/tsup/{chunk-HNHLBM3Y.cjs → chunk-4KGXFC6M.cjs} +42 -5
- package/dist/tsup/chunk-4KGXFC6M.cjs.map +1 -0
- package/dist/tsup/chunk-5UYWLCRO.js +14 -0
- package/dist/tsup/chunk-5UYWLCRO.js.map +1 -0
- package/dist/tsup/{chunk-QWLJCP3X.js → chunk-6W5VGLFT.js} +42 -5
- package/dist/tsup/chunk-6W5VGLFT.js.map +1 -0
- package/dist/tsup/chunk-6WYATRS4.js +243 -0
- package/dist/tsup/chunk-6WYATRS4.js.map +1 -0
- package/dist/tsup/chunk-B3W74FBB.cjs +14 -0
- package/dist/tsup/chunk-B3W74FBB.cjs.map +1 -0
- package/dist/tsup/{chunk-V6ANE6JM.js → chunk-FWROC5LA.js} +2 -2
- package/dist/tsup/{chunk-ZVM35ICH.cjs → chunk-GLIPKKEC.cjs} +7 -7
- package/dist/tsup/{chunk-ZVM35ICH.cjs.map → chunk-GLIPKKEC.cjs.map} +1 -1
- package/dist/tsup/{chunk-CCUO5OKD.cjs → chunk-GN2EUMEW.cjs} +3 -3
- package/dist/tsup/{chunk-CCUO5OKD.cjs.map → chunk-GN2EUMEW.cjs.map} +1 -1
- package/dist/tsup/{chunk-2ROUKH7W.cjs → chunk-GU7ML3KE.cjs} +13 -3
- package/dist/tsup/chunk-GU7ML3KE.cjs.map +1 -0
- package/dist/tsup/{chunk-WRRB24UY.js → chunk-JQ2AZ5FN.js} +3 -3
- package/dist/tsup/{chunk-7AFZMFPQ.js → chunk-JTHHCZCZ.js} +10 -1
- package/dist/tsup/chunk-JTHHCZCZ.js.map +1 -0
- package/dist/tsup/{chunk-UEULFXUI.cjs → chunk-KVFIONKQ.cjs} +11 -2
- package/dist/tsup/chunk-KVFIONKQ.cjs.map +1 -0
- package/dist/tsup/chunk-LWQFXGKS.cjs +243 -0
- package/dist/tsup/chunk-LWQFXGKS.cjs.map +1 -0
- package/dist/tsup/{chunk-KVD6ZWNM.js → chunk-MO2SSUOR.js} +8 -7
- package/dist/tsup/chunk-MO2SSUOR.js.map +1 -0
- package/dist/tsup/{chunk-AGNBLCNJ.js → chunk-OUENKQHB.js} +13 -3
- package/dist/tsup/chunk-OUENKQHB.js.map +1 -0
- package/dist/tsup/{chunk-E6WB2BLO.cjs → chunk-PUZY2XCD.cjs} +10 -9
- package/dist/tsup/chunk-PUZY2XCD.cjs.map +1 -0
- package/dist/tsup/{chunk-4EDGOGCB.js → chunk-QFJ24MBU.js} +27 -2
- package/dist/tsup/{chunk-4EDGOGCB.js.map → chunk-QFJ24MBU.js.map} +1 -1
- package/dist/tsup/{chunk-A55CGZIV.cjs → chunk-RXXDNJXB.cjs} +140 -140
- package/dist/tsup/{chunk-A55CGZIV.cjs.map → chunk-RXXDNJXB.cjs.map} +1 -1
- package/dist/tsup/{chunk-N6MBTYGX.cjs → chunk-VBJQIBXI.cjs} +30 -5
- package/dist/tsup/chunk-VBJQIBXI.cjs.map +1 -0
- package/dist/tsup/client/mod.cjs +6 -6
- package/dist/tsup/client/mod.d.cts +4 -3
- package/dist/tsup/client/mod.d.ts +4 -3
- package/dist/tsup/client/mod.js +5 -5
- package/dist/tsup/common/log.cjs +2 -2
- package/dist/tsup/common/log.js +1 -1
- package/dist/tsup/common/websocket.cjs +3 -3
- package/dist/tsup/common/websocket.js +2 -2
- package/dist/tsup/{config-CZcjyT5B.d.ts → config-C4OSv0QP.d.ts} +92 -7
- package/dist/tsup/{config-rGWrumlO.d.cts → config-DTGoWdkG.d.cts} +92 -7
- package/dist/tsup/{config-BxOimoGX.d.cts → config-ey2I2zz5.d.cts} +46 -6
- package/dist/tsup/{config-BxOimoGX.d.ts → config-ey2I2zz5.d.ts} +46 -6
- package/dist/tsup/{context-B8W8E8nW.d.cts → context-C6cvDNyk.d.cts} +2 -2
- package/dist/tsup/{context-_UrDZhEh.d.ts → context-CMygeBxS.d.ts} +2 -2
- package/dist/tsup/db/drizzle.cjs +18 -10
- package/dist/tsup/db/drizzle.cjs.map +1 -1
- package/dist/tsup/db/drizzle.d.cts +5 -6
- package/dist/tsup/db/drizzle.d.ts +5 -6
- package/dist/tsup/db/drizzle.js +13 -5
- package/dist/tsup/db/drizzle.js.map +1 -1
- package/dist/tsup/db/mod.cjs +5 -175
- package/dist/tsup/db/mod.cjs.map +1 -1
- package/dist/tsup/db/mod.d.cts +11 -4
- package/dist/tsup/db/mod.d.ts +11 -4
- package/dist/tsup/db/mod.js +4 -174
- package/dist/tsup/db/mod.js.map +1 -1
- package/dist/tsup/dynamic/mod.cjs +2 -2
- package/dist/tsup/dynamic/mod.d.cts +3 -2
- package/dist/tsup/dynamic/mod.d.ts +3 -2
- package/dist/tsup/dynamic/mod.js +1 -1
- package/dist/tsup/inspector/mod.cjs +5 -4
- package/dist/tsup/inspector/mod.cjs.map +1 -1
- package/dist/tsup/inspector/mod.d.cts +12 -146
- package/dist/tsup/inspector/mod.d.ts +12 -146
- package/dist/tsup/inspector/mod.js +4 -3
- package/dist/tsup/inspector/mod.js.map +1 -1
- package/dist/tsup/inspector/workflow.cjs +21 -0
- package/dist/tsup/inspector/workflow.cjs.map +1 -0
- package/dist/tsup/inspector/workflow.d.cts +144 -0
- package/dist/tsup/inspector/workflow.d.ts +144 -0
- package/dist/tsup/inspector/workflow.js +21 -0
- package/dist/tsup/inspector/workflow.js.map +1 -0
- package/dist/tsup/inspector-tab/mod.cjs +2 -2
- package/dist/tsup/inspector-tab/mod.d.cts +4 -3
- package/dist/tsup/inspector-tab/mod.d.ts +4 -3
- package/dist/tsup/inspector-tab/mod.js +1 -1
- package/dist/tsup/mod.cjs +837 -243
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +6 -5
- package/dist/tsup/mod.d.ts +6 -5
- package/dist/tsup/mod.js +766 -172
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +7 -7
- package/dist/tsup/test/mod.d.cts +3 -2
- package/dist/tsup/test/mod.d.ts +3 -2
- package/dist/tsup/test/mod.js +5 -5
- package/dist/tsup/unstable/migrations.d.cts +1 -1
- package/dist/tsup/unstable/migrations.d.ts +1 -1
- package/dist/tsup/utils.cjs +2 -2
- package/dist/tsup/utils.js +1 -1
- package/dist/tsup/workflow/mod.cjs +89 -95
- package/dist/tsup/workflow/mod.cjs.map +1 -1
- package/dist/tsup/workflow/mod.d.cts +5 -4
- package/dist/tsup/workflow/mod.d.ts +5 -4
- package/dist/tsup/workflow/mod.js +86 -92
- package/dist/tsup/workflow/mod.js.map +1 -1
- package/package.json +19 -9
- package/src/actor/config.test.ts +65 -1
- package/src/actor/config.ts +169 -5
- package/src/actor/mod.ts +10 -1
- package/src/client/actor-common.ts +5 -14
- package/src/common/database/config.ts +50 -3
- package/src/common/database/mod.test.ts +142 -4
- package/src/common/database/mod.ts +210 -98
- package/src/common/database/native-database.ts +42 -3
- package/src/common/database/shared.ts +9 -0
- package/src/db/drizzle.test.ts +8 -1
- package/src/db/drizzle.ts +15 -4
- package/src/db/mod.ts +3 -0
- package/src/inspector/workflow.ts +61 -0
- package/src/registry/napi-runtime.ts +69 -1
- package/src/registry/native.ts +505 -155
- package/src/registry/run-handler-coordinator.test.ts +252 -0
- package/src/registry/run-handler-coordinator.ts +219 -0
- package/src/registry/runtime.ts +34 -1
- package/src/registry/wasm-runtime.ts +122 -17
- package/src/registry/write-through-proxy.ts +101 -0
- package/src/utils/node.ts +44 -28
- package/src/workflow/driver.ts +56 -58
- package/src/workflow/inspector.ts +10 -15
- package/src/workflow/mod.ts +48 -70
- package/dist/tsup/chunk-2ROUKH7W.cjs.map +0 -1
- package/dist/tsup/chunk-7AFZMFPQ.js.map +0 -1
- package/dist/tsup/chunk-AGNBLCNJ.js.map +0 -1
- package/dist/tsup/chunk-E6WB2BLO.cjs.map +0 -1
- package/dist/tsup/chunk-HNHLBM3Y.cjs.map +0 -1
- package/dist/tsup/chunk-JBQ63WSM.js.map +0 -1
- package/dist/tsup/chunk-KVD6ZWNM.js.map +0 -1
- package/dist/tsup/chunk-N6MBTYGX.cjs.map +0 -1
- package/dist/tsup/chunk-QWLJCP3X.js.map +0 -1
- package/dist/tsup/chunk-UEULFXUI.cjs.map +0 -1
- /package/dist/tsup/{chunk-V6ANE6JM.js.map → chunk-FWROC5LA.js.map} +0 -0
- /package/dist/tsup/{chunk-WRRB24UY.js.map → chunk-JQ2AZ5FN.js.map} +0 -0
package/src/registry/native.ts
CHANGED
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
disposeRunInspector,
|
|
16
16
|
getRunFunction,
|
|
17
17
|
getRunInspectorConfig,
|
|
18
|
+
getRunInspectorKind,
|
|
19
|
+
hasRunInspectorConfig,
|
|
18
20
|
RAW_STATE_SYMBOL,
|
|
19
21
|
type ScheduledEventInfo,
|
|
20
22
|
type WorkflowInspectorConfig,
|
|
@@ -44,7 +46,15 @@ import {
|
|
|
44
46
|
} from "@/client/client";
|
|
45
47
|
import { convertRegistryConfigToClientConfig } from "@/client/config";
|
|
46
48
|
import { HEADER_CONN_PARAMS } from "@/common/actor-router-consts";
|
|
47
|
-
import type {
|
|
49
|
+
import type {
|
|
50
|
+
AnyDatabaseProvider,
|
|
51
|
+
SqliteProfilingOptions,
|
|
52
|
+
} from "@/common/database/config";
|
|
53
|
+
import {
|
|
54
|
+
bindNativeStateTransactionContext,
|
|
55
|
+
db as defaultDb,
|
|
56
|
+
registerNativeStateTransactionOpener,
|
|
57
|
+
} from "@/common/database/mod";
|
|
48
58
|
import { wrapJsNativeDatabase } from "@/common/database/native-database";
|
|
49
59
|
import { assertJsonCompatValue, type JsonCompatValue } from "@/common/encoding";
|
|
50
60
|
import { isResponseLike, type ResponseLike } from "@/common/fetch-like";
|
|
@@ -83,6 +93,7 @@ import {
|
|
|
83
93
|
validateQueueBody,
|
|
84
94
|
validateQueueComplete,
|
|
85
95
|
} from "./native-validation";
|
|
96
|
+
import { RunHandlerCoordinator } from "./run-handler-coordinator";
|
|
86
97
|
import type {
|
|
87
98
|
ActorContextHandle,
|
|
88
99
|
ActorFactoryHandle,
|
|
@@ -104,7 +115,10 @@ import type {
|
|
|
104
115
|
WebSocketHandle,
|
|
105
116
|
} from "./runtime";
|
|
106
117
|
import { loadWasmRuntime } from "./wasm-runtime";
|
|
107
|
-
import {
|
|
118
|
+
import {
|
|
119
|
+
createWriteThroughProxy,
|
|
120
|
+
unwrapWriteThroughProxy,
|
|
121
|
+
} from "./write-through-proxy";
|
|
108
122
|
|
|
109
123
|
const textEncoder = new TextEncoder();
|
|
110
124
|
const textDecoder = new TextDecoder();
|
|
@@ -128,6 +142,14 @@ type NativePersistConnState = {
|
|
|
128
142
|
state: unknown;
|
|
129
143
|
};
|
|
130
144
|
|
|
145
|
+
type NativeStateTransactionScope = {
|
|
146
|
+
actorContext: ActorContextHandleAdapter;
|
|
147
|
+
actorStateBaseline: unknown;
|
|
148
|
+
connectionStateBaselines: Map<string, Uint8Array>;
|
|
149
|
+
committed: boolean;
|
|
150
|
+
release: () => void;
|
|
151
|
+
};
|
|
152
|
+
|
|
131
153
|
const defaultRuntimeLoaders: RuntimeLoaders = {
|
|
132
154
|
loadNative: loadNapiRuntime,
|
|
133
155
|
loadWasm: loadWasmRuntime,
|
|
@@ -271,14 +293,14 @@ type NativePersistActorState = {
|
|
|
271
293
|
state: unknown;
|
|
272
294
|
isInOnStateChange: boolean;
|
|
273
295
|
connStates: Map<string, NativePersistConnState>;
|
|
274
|
-
// Memoized deep write-through proxy and the state object it wraps. Rebuilt
|
|
275
|
-
// only when the underlying state object identity changes.
|
|
276
|
-
stateProxy?: unknown;
|
|
277
|
-
stateProxyTarget?: unknown;
|
|
278
296
|
// Set when a coalesced save and onStateChange flush is pending for the
|
|
279
297
|
// current event loop tick.
|
|
280
298
|
saveScheduled?: boolean;
|
|
281
299
|
pendingSaveHandle?: ReturnType<typeof setImmediate>;
|
|
300
|
+
activeStateTransactionOwner?: symbol;
|
|
301
|
+
pendingStateTransactionOwners?: Set<symbol>;
|
|
302
|
+
stateTransactionTail?: Promise<void>;
|
|
303
|
+
stateTransactionSaveDeferred?: boolean;
|
|
282
304
|
};
|
|
283
305
|
type NativeDestroyGate = {
|
|
284
306
|
destroyCompletion?: Promise<void>;
|
|
@@ -364,6 +386,15 @@ function stateMutationReentrantError(): RivetError {
|
|
|
364
386
|
);
|
|
365
387
|
}
|
|
366
388
|
|
|
389
|
+
function stateTransactionConflictError(): RivetError {
|
|
390
|
+
return new RivetError(
|
|
391
|
+
"actor",
|
|
392
|
+
"state_transaction_conflict",
|
|
393
|
+
"State cannot be mutated by another action while an experimental state-aware database transaction is active.",
|
|
394
|
+
{ public: true, statusCode: 409 },
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
367
398
|
function databaseNotConfiguredError(): RivetError {
|
|
368
399
|
return new RivetError(
|
|
369
400
|
"actor",
|
|
@@ -381,6 +412,14 @@ function databaseClientNotReadyError(): RivetError {
|
|
|
381
412
|
{ public: true },
|
|
382
413
|
);
|
|
383
414
|
}
|
|
415
|
+
function runHandlerNotConfiguredError(): RivetError {
|
|
416
|
+
return new RivetError(
|
|
417
|
+
"actor",
|
|
418
|
+
"run_handler_unavailable",
|
|
419
|
+
"Cannot schedule a run wake because this actor does not define a run handler.",
|
|
420
|
+
{ public: true, statusCode: 409 },
|
|
421
|
+
);
|
|
422
|
+
}
|
|
384
423
|
|
|
385
424
|
function stateNotEnabledError(): RivetError {
|
|
386
425
|
return new RivetError(
|
|
@@ -533,10 +572,11 @@ function getOrCreateNativeSqlDatabase(
|
|
|
533
572
|
execute: (sql, params) => runtime.actorSqlExecute(ctx, sql, params),
|
|
534
573
|
executeBatch: (statements) =>
|
|
535
574
|
runtime.actorSqlExecuteBatch(ctx, statements),
|
|
536
|
-
beginTransaction: async (timeoutMs) => {
|
|
575
|
+
beginTransaction: async (timeoutMs, name) => {
|
|
537
576
|
const transaction = await runtime.actorSqlBeginTransaction(
|
|
538
577
|
ctx,
|
|
539
578
|
timeoutMs,
|
|
579
|
+
name,
|
|
540
580
|
);
|
|
541
581
|
return {
|
|
542
582
|
exec: (sql) =>
|
|
@@ -552,6 +592,40 @@ function getOrCreateNativeSqlDatabase(
|
|
|
552
592
|
runtime.actorSqlTransactionRollback(transaction),
|
|
553
593
|
};
|
|
554
594
|
},
|
|
595
|
+
beginStateTransaction: async (timeoutMs, context) => {
|
|
596
|
+
const scope = context as NativeStateTransactionScope | undefined;
|
|
597
|
+
if (!scope) {
|
|
598
|
+
throw new Error(
|
|
599
|
+
"actor state transaction context is not configured",
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
const transaction = await runtime.actorBeginStateTransaction(
|
|
603
|
+
ctx,
|
|
604
|
+
timeoutMs,
|
|
605
|
+
);
|
|
606
|
+
return {
|
|
607
|
+
exec: async () => {
|
|
608
|
+
throw new Error(
|
|
609
|
+
"actor state transactions only support single-statement execute calls",
|
|
610
|
+
);
|
|
611
|
+
},
|
|
612
|
+
execute: (sql, params) =>
|
|
613
|
+
runtime.actorStateTransactionExecute(
|
|
614
|
+
transaction,
|
|
615
|
+
sql,
|
|
616
|
+
params,
|
|
617
|
+
),
|
|
618
|
+
commit: async () => {
|
|
619
|
+
await runtime.actorStateTransactionCommit(
|
|
620
|
+
transaction,
|
|
621
|
+
scope.actorContext.serializeForTick("save"),
|
|
622
|
+
);
|
|
623
|
+
scope.committed = true;
|
|
624
|
+
},
|
|
625
|
+
rollback: () =>
|
|
626
|
+
runtime.actorStateTransactionRollback(transaction),
|
|
627
|
+
};
|
|
628
|
+
},
|
|
555
629
|
query: (sql, params) => runtime.actorSqlQuery(ctx, sql, params),
|
|
556
630
|
run: (sql, params) => runtime.actorSqlRun(ctx, sql, params),
|
|
557
631
|
metrics: () => runtime.actorSqlMetrics(ctx),
|
|
@@ -1227,6 +1301,9 @@ class NativeConnAdapter {
|
|
|
1227
1301
|
#schemas: NativeValidationConfig;
|
|
1228
1302
|
#ctx?: ActorContextHandle;
|
|
1229
1303
|
#queueHibernationRemoval?: (connId: string) => void;
|
|
1304
|
+
#assertCanMutateState?: () => void;
|
|
1305
|
+
#stateProxy?: unknown;
|
|
1306
|
+
#stateProxyTarget?: unknown;
|
|
1230
1307
|
|
|
1231
1308
|
constructor(
|
|
1232
1309
|
runtime: CoreRuntime,
|
|
@@ -1234,12 +1311,14 @@ class NativeConnAdapter {
|
|
|
1234
1311
|
schemas: NativeValidationConfig = {},
|
|
1235
1312
|
ctx?: ActorContextHandle,
|
|
1236
1313
|
queueHibernationRemoval?: (connId: string) => void,
|
|
1314
|
+
assertCanMutateState?: () => void,
|
|
1237
1315
|
) {
|
|
1238
1316
|
this.#runtime = runtime;
|
|
1239
1317
|
this.#conn = conn;
|
|
1240
1318
|
this.#schemas = schemas;
|
|
1241
1319
|
this.#ctx = ctx;
|
|
1242
1320
|
this.#queueHibernationRemoval = queueHibernationRemoval;
|
|
1321
|
+
this.#assertCanMutateState = assertCanMutateState;
|
|
1243
1322
|
(
|
|
1244
1323
|
this as NativeConnAdapter & {
|
|
1245
1324
|
[CONN_STATE_MANAGER_SYMBOL]?: unknown;
|
|
@@ -1270,24 +1349,55 @@ class NativeConnAdapter {
|
|
|
1270
1349
|
|
|
1271
1350
|
get state(): unknown {
|
|
1272
1351
|
const nextState = this.#readState();
|
|
1352
|
+
if (!this.#ctx) {
|
|
1353
|
+
return this.#createStateProxy(nextState);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// Reading `conn.state` rebuilds the deep write-through proxy, which
|
|
1357
|
+
// allocates fresh on-change caches and rewraps the whole tree. Memoize
|
|
1358
|
+
// the proxy keyed on the underlying state object so repeated reads and
|
|
1359
|
+
// deep read cascades reuse a single proxy.
|
|
1360
|
+
if (
|
|
1361
|
+
this.#stateProxy === undefined ||
|
|
1362
|
+
this.#stateProxyTarget !== nextState
|
|
1363
|
+
) {
|
|
1364
|
+
this.#stateProxyTarget = nextState;
|
|
1365
|
+
this.#stateProxy = this.#createStateProxy(nextState);
|
|
1366
|
+
}
|
|
1367
|
+
return this.#stateProxy;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
#createStateProxy(state: unknown): unknown {
|
|
1371
|
+
const assertCurrentState = () => {
|
|
1372
|
+
this.#assertCanMutateState?.();
|
|
1373
|
+
if (this.#ctx && this.#readState() !== state) {
|
|
1374
|
+
throw stateTransactionConflictError();
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1273
1377
|
return createWriteThroughProxy(
|
|
1274
|
-
|
|
1378
|
+
state,
|
|
1275
1379
|
(nextValue) => {
|
|
1380
|
+
assertCurrentState();
|
|
1276
1381
|
this.#writeState(nextValue, { writeNative: true });
|
|
1277
1382
|
},
|
|
1278
1383
|
(newValue) => {
|
|
1384
|
+
assertCurrentState();
|
|
1279
1385
|
assertJsonCompatValue(newValue);
|
|
1280
1386
|
},
|
|
1281
1387
|
);
|
|
1282
1388
|
}
|
|
1283
1389
|
|
|
1284
1390
|
set state(value: unknown) {
|
|
1285
|
-
|
|
1286
|
-
|
|
1391
|
+
this.#assertCanMutateState?.();
|
|
1392
|
+
const nextValue = unwrapWriteThroughProxy(value);
|
|
1393
|
+
assertJsonCompatValue(nextValue);
|
|
1394
|
+
this.#writeState(nextValue, { writeNative: true });
|
|
1287
1395
|
}
|
|
1288
1396
|
|
|
1289
1397
|
initializeState(value: unknown): void {
|
|
1290
|
-
this.#writeState(value, {
|
|
1398
|
+
this.#writeState(unwrapWriteThroughProxy(value), {
|
|
1399
|
+
writeNative: false,
|
|
1400
|
+
});
|
|
1291
1401
|
}
|
|
1292
1402
|
|
|
1293
1403
|
get isHibernatable(): boolean {
|
|
@@ -1700,8 +1810,9 @@ function wrapQueueMessage(
|
|
|
1700
1810
|
schemas: NativeValidationConfig["queues"],
|
|
1701
1811
|
) {
|
|
1702
1812
|
const name = callNativeSync(() => message.name());
|
|
1813
|
+
const id = callNativeSync(() => message.id());
|
|
1703
1814
|
return {
|
|
1704
|
-
id: Number(
|
|
1815
|
+
id: id <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(id) : id,
|
|
1705
1816
|
name,
|
|
1706
1817
|
body: validateQueueBody(
|
|
1707
1818
|
schemas,
|
|
@@ -1885,6 +1996,32 @@ class NativeQueueAdapter {
|
|
|
1885
1996
|
cleanup?.();
|
|
1886
1997
|
}
|
|
1887
1998
|
}
|
|
1999
|
+
async waitForAvailable(
|
|
2000
|
+
names?: readonly string[],
|
|
2001
|
+
options?: { timeout?: number; signal?: AbortSignal },
|
|
2002
|
+
): Promise<void> {
|
|
2003
|
+
await this.waitForNamesAvailable(names ?? [], options);
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
async complete(
|
|
2007
|
+
message: { id: number | bigint; name: string },
|
|
2008
|
+
response?: unknown,
|
|
2009
|
+
): Promise<void> {
|
|
2010
|
+
const validatedResponse = validateQueueComplete(
|
|
2011
|
+
this.#schemas,
|
|
2012
|
+
message.name,
|
|
2013
|
+
response,
|
|
2014
|
+
);
|
|
2015
|
+
await callNative(() =>
|
|
2016
|
+
this.#runtime.actorQueueCompletePersisted(
|
|
2017
|
+
this.#ctx,
|
|
2018
|
+
BigInt(message.id),
|
|
2019
|
+
message.name,
|
|
2020
|
+
encodeValue(validatedResponse),
|
|
2021
|
+
),
|
|
2022
|
+
);
|
|
2023
|
+
this.#pendingCompletableMessageIds.delete(message.id.toString());
|
|
2024
|
+
}
|
|
1888
2025
|
|
|
1889
2026
|
async enqueueAndWait(
|
|
1890
2027
|
name: string,
|
|
@@ -2464,15 +2601,18 @@ class NativeConnectionMap implements ReadonlyMap<string, NativeConnAdapter> {
|
|
|
2464
2601
|
#runtime: CoreRuntime;
|
|
2465
2602
|
#ctx: ActorContextHandle;
|
|
2466
2603
|
#schemas: NativeValidationConfig;
|
|
2604
|
+
#assertCanMutateState: () => void;
|
|
2467
2605
|
|
|
2468
2606
|
constructor(
|
|
2469
2607
|
runtime: CoreRuntime,
|
|
2470
2608
|
ctx: ActorContextHandle,
|
|
2471
2609
|
schemas: NativeValidationConfig,
|
|
2610
|
+
assertCanMutateState: () => void,
|
|
2472
2611
|
) {
|
|
2473
2612
|
this.#runtime = runtime;
|
|
2474
2613
|
this.#ctx = ctx;
|
|
2475
2614
|
this.#schemas = schemas;
|
|
2615
|
+
this.#assertCanMutateState = assertCanMutateState;
|
|
2476
2616
|
}
|
|
2477
2617
|
|
|
2478
2618
|
#connToAdapter(conn: ConnHandle): NativeConnAdapter {
|
|
@@ -2488,6 +2628,7 @@ class NativeConnectionMap implements ReadonlyMap<string, NativeConnAdapter> {
|
|
|
2488
2628
|
connId,
|
|
2489
2629
|
),
|
|
2490
2630
|
),
|
|
2631
|
+
this.#assertCanMutateState,
|
|
2491
2632
|
);
|
|
2492
2633
|
}
|
|
2493
2634
|
|
|
@@ -2575,10 +2716,13 @@ export class ActorContextHandleAdapter {
|
|
|
2575
2716
|
#queue?: NativeQueueAdapter;
|
|
2576
2717
|
#request?: Request;
|
|
2577
2718
|
#schedule?: NativeScheduleAdapter;
|
|
2578
|
-
#
|
|
2579
|
-
#
|
|
2719
|
+
#run?: { setWakeAt(timestamp: number | null): Promise<void> };
|
|
2720
|
+
#runHandlerConfigured: boolean;
|
|
2580
2721
|
#onStateChange?: NativeOnStateChangeHandler;
|
|
2581
2722
|
#stateEnabled: boolean;
|
|
2723
|
+
#stateProxy?: unknown;
|
|
2724
|
+
#stateProxyTarget?: unknown;
|
|
2725
|
+
readonly #stateTransactionOwner = Symbol("actor-state-transaction-owner");
|
|
2582
2726
|
|
|
2583
2727
|
constructor(
|
|
2584
2728
|
runtime: CoreRuntime,
|
|
@@ -2588,16 +2732,16 @@ export class ActorContextHandleAdapter {
|
|
|
2588
2732
|
databaseProvider?: AnyDatabaseProvider,
|
|
2589
2733
|
request?: Request,
|
|
2590
2734
|
stateEnabled = true,
|
|
2591
|
-
runHandlerActiveProvider?: () => boolean,
|
|
2592
2735
|
onStateChange?: NativeOnStateChangeHandler,
|
|
2593
2736
|
dispatchCancelToken?: CancellationTokenHandle,
|
|
2737
|
+
runHandlerConfigured = false,
|
|
2594
2738
|
) {
|
|
2595
2739
|
this.#runtime = runtime;
|
|
2596
2740
|
this.#ctx = ctx;
|
|
2597
2741
|
this.#clientFactory = clientFactory;
|
|
2598
2742
|
this.#schemas = schemas;
|
|
2599
2743
|
this.#dispatchCancelToken = dispatchCancelToken;
|
|
2600
|
-
this.#
|
|
2744
|
+
this.#runHandlerConfigured = runHandlerConfigured;
|
|
2601
2745
|
this.#onStateChange = onStateChange;
|
|
2602
2746
|
this.#stateEnabled = stateEnabled;
|
|
2603
2747
|
if (databaseProvider) {
|
|
@@ -2620,13 +2764,6 @@ export class ActorContextHandleAdapter {
|
|
|
2620
2764
|
return this.#kv;
|
|
2621
2765
|
}
|
|
2622
2766
|
|
|
2623
|
-
get sql() {
|
|
2624
|
-
if (!this.#sql) {
|
|
2625
|
-
this.#sql = getOrCreateNativeSqlDatabase(this.#runtime, this.#ctx);
|
|
2626
|
-
}
|
|
2627
|
-
return this.#sql;
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
2767
|
async actorRuntimeSocket(): Promise<{ path: string }> {
|
|
2631
2768
|
return await callNative(() =>
|
|
2632
2769
|
this.#runtime.actorRuntimeSocketProvision(this.#ctx),
|
|
@@ -2645,7 +2782,7 @@ export class ActorContextHandleAdapter {
|
|
|
2645
2782
|
const runtimeState = getNativeRuntimeState(this.#runtime, this.#ctx);
|
|
2646
2783
|
const cachedClient = runtimeState.databaseClient;
|
|
2647
2784
|
if (cachedClient) {
|
|
2648
|
-
this.#db = cachedClient.client;
|
|
2785
|
+
this.#db = this.#bindDatabaseClient(cachedClient.client);
|
|
2649
2786
|
return this.#db;
|
|
2650
2787
|
}
|
|
2651
2788
|
|
|
@@ -2663,29 +2800,35 @@ export class ActorContextHandleAdapter {
|
|
|
2663
2800
|
if (!this.#stateEnabled) {
|
|
2664
2801
|
throw stateNotEnabledError();
|
|
2665
2802
|
}
|
|
2666
|
-
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
2667
2803
|
const nextState = this.#readState();
|
|
2668
2804
|
// Reading `c.state` rebuilds the deep write-through proxy, which
|
|
2669
2805
|
// allocates fresh on-change caches and rewraps the whole tree. Memoize
|
|
2670
2806
|
// the proxy keyed on the underlying state object so repeated reads and
|
|
2671
2807
|
// deep read cascades reuse a single proxy.
|
|
2672
2808
|
if (
|
|
2673
|
-
|
|
2674
|
-
|
|
2809
|
+
this.#stateProxy === undefined ||
|
|
2810
|
+
this.#stateProxyTarget !== nextState
|
|
2675
2811
|
) {
|
|
2676
|
-
|
|
2677
|
-
|
|
2812
|
+
const assertCurrentState = () => {
|
|
2813
|
+
this.#assertCanMutateState();
|
|
2814
|
+
if (this.#readState() !== nextState) {
|
|
2815
|
+
throw stateTransactionConflictError();
|
|
2816
|
+
}
|
|
2817
|
+
};
|
|
2818
|
+
this.#stateProxyTarget = nextState;
|
|
2819
|
+
this.#stateProxy = createWriteThroughProxy(
|
|
2678
2820
|
nextState,
|
|
2679
2821
|
(nextValue) => {
|
|
2822
|
+
assertCurrentState();
|
|
2680
2823
|
this.#writeState(nextValue, { scheduleSave: true });
|
|
2681
2824
|
},
|
|
2682
2825
|
(newValue) => {
|
|
2683
|
-
|
|
2826
|
+
assertCurrentState();
|
|
2684
2827
|
assertJsonCompatValue(newValue);
|
|
2685
2828
|
},
|
|
2686
2829
|
);
|
|
2687
2830
|
}
|
|
2688
|
-
return
|
|
2831
|
+
return this.#stateProxy;
|
|
2689
2832
|
}
|
|
2690
2833
|
|
|
2691
2834
|
set state(value: unknown) {
|
|
@@ -2693,15 +2836,18 @@ export class ActorContextHandleAdapter {
|
|
|
2693
2836
|
throw stateNotEnabledError();
|
|
2694
2837
|
}
|
|
2695
2838
|
this.#assertCanMutateState();
|
|
2696
|
-
|
|
2697
|
-
|
|
2839
|
+
const nextValue = unwrapWriteThroughProxy(value);
|
|
2840
|
+
assertJsonCompatValue(nextValue);
|
|
2841
|
+
this.#writeState(nextValue, { scheduleSave: true });
|
|
2698
2842
|
}
|
|
2699
2843
|
|
|
2700
2844
|
initializeState(value: unknown): void {
|
|
2701
2845
|
if (!this.#stateEnabled) {
|
|
2702
2846
|
return;
|
|
2703
2847
|
}
|
|
2704
|
-
this.#writeState(value, {
|
|
2848
|
+
this.#writeState(unwrapWriteThroughProxy(value), {
|
|
2849
|
+
scheduleSave: false,
|
|
2850
|
+
});
|
|
2705
2851
|
}
|
|
2706
2852
|
|
|
2707
2853
|
get vars(): unknown {
|
|
@@ -2732,6 +2878,30 @@ export class ActorContextHandleAdapter {
|
|
|
2732
2878
|
return this.#queue;
|
|
2733
2879
|
}
|
|
2734
2880
|
|
|
2881
|
+
get run() {
|
|
2882
|
+
if (!this.#run) {
|
|
2883
|
+
this.#run = {
|
|
2884
|
+
setWakeAt: async (timestamp: number | null) => {
|
|
2885
|
+
if (timestamp !== null && !this.#runHandlerConfigured) {
|
|
2886
|
+
throw runHandlerNotConfiguredError();
|
|
2887
|
+
}
|
|
2888
|
+
if (
|
|
2889
|
+
timestamp !== null &&
|
|
2890
|
+
(!Number.isSafeInteger(timestamp) || timestamp < 0)
|
|
2891
|
+
) {
|
|
2892
|
+
throw new TypeError(
|
|
2893
|
+
"Run wake timestamp must be a non-negative safe integer or null",
|
|
2894
|
+
);
|
|
2895
|
+
}
|
|
2896
|
+
await callNative(() =>
|
|
2897
|
+
this.#runtime.actorSetRunWakeAt(this.#ctx, timestamp),
|
|
2898
|
+
);
|
|
2899
|
+
},
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
return this.#run;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2735
2905
|
get schedule(): NativeScheduleAdapter {
|
|
2736
2906
|
if (!this.#schedule) {
|
|
2737
2907
|
this.#schedule = new NativeScheduleAdapter(
|
|
@@ -2773,6 +2943,7 @@ export class ActorContextHandleAdapter {
|
|
|
2773
2943
|
this.#runtime,
|
|
2774
2944
|
this.#ctx,
|
|
2775
2945
|
this.#schemas,
|
|
2946
|
+
() => this.#assertCanMutateState(),
|
|
2776
2947
|
);
|
|
2777
2948
|
}
|
|
2778
2949
|
return this.#connMap;
|
|
@@ -2853,12 +3024,12 @@ export class ActorContextHandleAdapter {
|
|
|
2853
3024
|
const runtimeState = getNativeRuntimeState(this.#runtime, this.#ctx);
|
|
2854
3025
|
const cachedClient = runtimeState.databaseClient;
|
|
2855
3026
|
if (cachedClient) {
|
|
2856
|
-
this.#db = cachedClient.client;
|
|
3027
|
+
this.#db = this.#bindDatabaseClient(cachedClient.client);
|
|
2857
3028
|
return this.#db;
|
|
2858
3029
|
}
|
|
2859
3030
|
|
|
2860
3031
|
const actorId = this.actorId;
|
|
2861
|
-
const
|
|
3032
|
+
const createdClient = await this.#databaseProvider.createClient({
|
|
2862
3033
|
actorId,
|
|
2863
3034
|
kv: {
|
|
2864
3035
|
batchPut: async (entries) => {
|
|
@@ -2879,21 +3050,147 @@ export class ActorContextHandleAdapter {
|
|
|
2879
3050
|
log: {
|
|
2880
3051
|
debug: (obj) => logger().debug(obj),
|
|
2881
3052
|
},
|
|
2882
|
-
nativeDatabaseProvider:
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
3053
|
+
nativeDatabaseProvider: registerNativeStateTransactionOpener(
|
|
3054
|
+
{
|
|
3055
|
+
open: async (requestedActorId) => {
|
|
3056
|
+
void requestedActorId;
|
|
3057
|
+
return getOrCreateNativeSqlDatabase(
|
|
3058
|
+
this.#runtime,
|
|
3059
|
+
this.#ctx,
|
|
3060
|
+
);
|
|
3061
|
+
},
|
|
3062
|
+
},
|
|
3063
|
+
async (timeoutMs, context) =>
|
|
3064
|
+
await getOrCreateNativeSqlDatabase(
|
|
2886
3065
|
this.#runtime,
|
|
2887
3066
|
this.#ctx,
|
|
2888
|
-
)
|
|
2889
|
-
|
|
2890
|
-
},
|
|
3067
|
+
).beginStateTransaction(timeoutMs, context),
|
|
3068
|
+
),
|
|
2891
3069
|
});
|
|
2892
3070
|
runtimeState.databaseClient = {
|
|
2893
|
-
client,
|
|
3071
|
+
client: createdClient,
|
|
2894
3072
|
};
|
|
2895
|
-
this.#db =
|
|
2896
|
-
return
|
|
3073
|
+
this.#db = this.#bindDatabaseClient(createdClient);
|
|
3074
|
+
return this.#db;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
#bindDatabaseClient(client: unknown): unknown {
|
|
3078
|
+
return bindNativeStateTransactionContext(client, {
|
|
3079
|
+
enter: async () => await this.#enterStateTransaction(),
|
|
3080
|
+
exit: (scope) =>
|
|
3081
|
+
this.#exitStateTransaction(
|
|
3082
|
+
scope as NativeStateTransactionScope,
|
|
3083
|
+
),
|
|
3084
|
+
});
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
async #enterStateTransaction(): Promise<NativeStateTransactionScope> {
|
|
3088
|
+
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
3089
|
+
let pendingOwners = actorState.pendingStateTransactionOwners;
|
|
3090
|
+
if (!pendingOwners) {
|
|
3091
|
+
pendingOwners = new Set();
|
|
3092
|
+
actorState.pendingStateTransactionOwners = pendingOwners;
|
|
3093
|
+
}
|
|
3094
|
+
if (
|
|
3095
|
+
actorState.activeStateTransactionOwner ===
|
|
3096
|
+
this.#stateTransactionOwner ||
|
|
3097
|
+
pendingOwners.has(this.#stateTransactionOwner)
|
|
3098
|
+
) {
|
|
3099
|
+
throw stateTransactionConflictError();
|
|
3100
|
+
}
|
|
3101
|
+
pendingOwners.add(this.#stateTransactionOwner);
|
|
3102
|
+
const predecessor =
|
|
3103
|
+
actorState.stateTransactionTail ?? Promise.resolve();
|
|
3104
|
+
let release!: () => void;
|
|
3105
|
+
const hold = new Promise<void>((resolve) => {
|
|
3106
|
+
release = resolve;
|
|
3107
|
+
});
|
|
3108
|
+
actorState.stateTransactionTail = predecessor.then(
|
|
3109
|
+
async () => await hold,
|
|
3110
|
+
);
|
|
3111
|
+
try {
|
|
3112
|
+
await predecessor;
|
|
3113
|
+
pendingOwners.delete(this.#stateTransactionOwner);
|
|
3114
|
+
actorState.activeStateTransactionOwner =
|
|
3115
|
+
this.#stateTransactionOwner;
|
|
3116
|
+
return {
|
|
3117
|
+
actorContext: this,
|
|
3118
|
+
actorStateBaseline: this.#stateEnabled
|
|
3119
|
+
? structuredClone(this.#readState())
|
|
3120
|
+
: undefined,
|
|
3121
|
+
connectionStateBaselines: new Map(
|
|
3122
|
+
callNativeSync(() =>
|
|
3123
|
+
this.#runtime.actorConns(this.#ctx),
|
|
3124
|
+
).map((conn) => [
|
|
3125
|
+
callNativeSync(() => this.#runtime.connId(conn)),
|
|
3126
|
+
new Uint8Array(
|
|
3127
|
+
callNativeSync(() => this.#runtime.connState(conn)),
|
|
3128
|
+
),
|
|
3129
|
+
]),
|
|
3130
|
+
),
|
|
3131
|
+
committed: false,
|
|
3132
|
+
release,
|
|
3133
|
+
};
|
|
3134
|
+
} catch (error) {
|
|
3135
|
+
pendingOwners.delete(this.#stateTransactionOwner);
|
|
3136
|
+
if (
|
|
3137
|
+
actorState.activeStateTransactionOwner ===
|
|
3138
|
+
this.#stateTransactionOwner
|
|
3139
|
+
) {
|
|
3140
|
+
actorState.activeStateTransactionOwner = undefined;
|
|
3141
|
+
}
|
|
3142
|
+
release();
|
|
3143
|
+
throw error;
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
#exitStateTransaction(scope: NativeStateTransactionScope): void {
|
|
3148
|
+
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
3149
|
+
try {
|
|
3150
|
+
if (!scope.committed) {
|
|
3151
|
+
this.#restoreStateTransactionBaseline(scope);
|
|
3152
|
+
}
|
|
3153
|
+
} finally {
|
|
3154
|
+
if (
|
|
3155
|
+
actorState.activeStateTransactionOwner ===
|
|
3156
|
+
this.#stateTransactionOwner
|
|
3157
|
+
) {
|
|
3158
|
+
actorState.activeStateTransactionOwner = undefined;
|
|
3159
|
+
}
|
|
3160
|
+
if (actorState.stateTransactionSaveDeferred) {
|
|
3161
|
+
actorState.stateTransactionSaveDeferred = false;
|
|
3162
|
+
this.#scheduleSave();
|
|
3163
|
+
}
|
|
3164
|
+
scope.release();
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
#restoreStateTransactionBaseline(scope: NativeStateTransactionScope): void {
|
|
3169
|
+
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
3170
|
+
if (actorState.pendingSaveHandle !== undefined) {
|
|
3171
|
+
clearImmediate(actorState.pendingSaveHandle);
|
|
3172
|
+
}
|
|
3173
|
+
actorState.pendingSaveHandle = undefined;
|
|
3174
|
+
actorState.saveScheduled = false;
|
|
3175
|
+
|
|
3176
|
+
if (this.#stateEnabled) {
|
|
3177
|
+
actorState.state = structuredClone(scope.actorStateBaseline);
|
|
3178
|
+
}
|
|
3179
|
+
for (const conn of callNativeSync(() =>
|
|
3180
|
+
this.#runtime.actorConns(this.#ctx),
|
|
3181
|
+
)) {
|
|
3182
|
+
const connId = callNativeSync(() => this.#runtime.connId(conn));
|
|
3183
|
+
const baseline = scope.connectionStateBaselines.get(connId);
|
|
3184
|
+
if (baseline === undefined) {
|
|
3185
|
+
continue;
|
|
3186
|
+
}
|
|
3187
|
+
callNativeSync(() => this.#runtime.connSetState(conn, baseline));
|
|
3188
|
+
const cached = actorState.connStates.get(connId);
|
|
3189
|
+
if (cached) {
|
|
3190
|
+
cached.state = decodeValue(baseline);
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
this.#scheduleSave();
|
|
2897
3194
|
}
|
|
2898
3195
|
|
|
2899
3196
|
async prepare(): Promise<void> {
|
|
@@ -2916,7 +3213,6 @@ export class ActorContextHandleAdapter {
|
|
|
2916
3213
|
|
|
2917
3214
|
async closeDatabase(): Promise<void> {
|
|
2918
3215
|
this.#db = undefined;
|
|
2919
|
-
this.#sql = undefined;
|
|
2920
3216
|
await closeNativeDatabaseClient(this.#runtime, this.#ctx);
|
|
2921
3217
|
await closeNativeSqlDatabase(this.#runtime, this.#ctx);
|
|
2922
3218
|
}
|
|
@@ -2941,6 +3237,7 @@ export class ActorContextHandleAdapter {
|
|
|
2941
3237
|
maxWait?: number;
|
|
2942
3238
|
}): Promise<void> {
|
|
2943
3239
|
if (opts?.immediate) {
|
|
3240
|
+
this.#assertCanAwaitStateSave();
|
|
2944
3241
|
await callNative(() =>
|
|
2945
3242
|
this.#runtime.actorRequestSaveAndWait(this.#ctx, {
|
|
2946
3243
|
immediate: true,
|
|
@@ -2966,11 +3263,22 @@ export class ActorContextHandleAdapter {
|
|
|
2966
3263
|
async saveStateAndWorkflowBatch(
|
|
2967
3264
|
writes: Array<{ key: Uint8Array; value: Uint8Array }>,
|
|
2968
3265
|
): Promise<void> {
|
|
3266
|
+
this.#assertCanAwaitStateSave();
|
|
2969
3267
|
await callNative(() =>
|
|
2970
3268
|
this.#runtime.actorSaveStateAndWorkflowBatch(this.#ctx, writes),
|
|
2971
3269
|
);
|
|
2972
3270
|
}
|
|
2973
3271
|
|
|
3272
|
+
#assertCanAwaitStateSave(): void {
|
|
3273
|
+
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
3274
|
+
if (
|
|
3275
|
+
actorState.activeStateTransactionOwner ===
|
|
3276
|
+
this.#stateTransactionOwner
|
|
3277
|
+
) {
|
|
3278
|
+
throw stateTransactionConflictError();
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
|
|
2974
3282
|
serializeForTick(reason: SerializeStateReason): RuntimeStateDeltaPayload {
|
|
2975
3283
|
void reason;
|
|
2976
3284
|
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
@@ -3034,10 +3342,6 @@ export class ActorContextHandleAdapter {
|
|
|
3034
3342
|
return promise;
|
|
3035
3343
|
}
|
|
3036
3344
|
|
|
3037
|
-
runHandlerActive(): boolean {
|
|
3038
|
-
return this.#runHandlerActiveProvider?.() ?? false;
|
|
3039
|
-
}
|
|
3040
|
-
|
|
3041
3345
|
internalKeepAwake<T>(run: Promise<T> | (() => Promise<T>)): Promise<T> {
|
|
3042
3346
|
const promise = typeof run === "function" ? run() : run;
|
|
3043
3347
|
// Track only completion, swallowing the outcome. The real result/error
|
|
@@ -3138,7 +3442,6 @@ export class ActorContextHandleAdapter {
|
|
|
3138
3442
|
// down so the request-save and onStateChange always run.
|
|
3139
3443
|
this.#flushStateChange();
|
|
3140
3444
|
this.#abortSignalCleanup?.();
|
|
3141
|
-
this.#sql = undefined;
|
|
3142
3445
|
}
|
|
3143
3446
|
|
|
3144
3447
|
#createActorAbortSignal(): AbortSignal {
|
|
@@ -3185,6 +3488,19 @@ export class ActorContextHandleAdapter {
|
|
|
3185
3488
|
if (actorState.isInOnStateChange) {
|
|
3186
3489
|
throw stateMutationReentrantError();
|
|
3187
3490
|
}
|
|
3491
|
+
if (
|
|
3492
|
+
actorState.activeStateTransactionOwner !==
|
|
3493
|
+
this.#stateTransactionOwner &&
|
|
3494
|
+
(actorState.activeStateTransactionOwner !== undefined ||
|
|
3495
|
+
(actorState.pendingStateTransactionOwners?.size ?? 0) > 0)
|
|
3496
|
+
) {
|
|
3497
|
+
throw stateTransactionConflictError();
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
|
|
3501
|
+
/** @internal */
|
|
3502
|
+
assertCanMutateState(): void {
|
|
3503
|
+
this.#assertCanMutateState();
|
|
3188
3504
|
}
|
|
3189
3505
|
|
|
3190
3506
|
// Coalesce the request-save and onStateChange work to once per event loop
|
|
@@ -3208,6 +3524,15 @@ export class ActorContextHandleAdapter {
|
|
|
3208
3524
|
if (!actorState.saveScheduled) {
|
|
3209
3525
|
return;
|
|
3210
3526
|
}
|
|
3527
|
+
if (actorState.activeStateTransactionOwner !== undefined) {
|
|
3528
|
+
actorState.saveScheduled = false;
|
|
3529
|
+
if (actorState.pendingSaveHandle !== undefined) {
|
|
3530
|
+
clearImmediate(actorState.pendingSaveHandle);
|
|
3531
|
+
actorState.pendingSaveHandle = undefined;
|
|
3532
|
+
}
|
|
3533
|
+
actorState.stateTransactionSaveDeferred = true;
|
|
3534
|
+
return;
|
|
3535
|
+
}
|
|
3211
3536
|
actorState.saveScheduled = false;
|
|
3212
3537
|
if (actorState.pendingSaveHandle !== undefined) {
|
|
3213
3538
|
clearImmediate(actorState.pendingSaveHandle);
|
|
@@ -3409,10 +3734,6 @@ class NativeWorkflowRuntimeAdapter {
|
|
|
3409
3734
|
};
|
|
3410
3735
|
}
|
|
3411
3736
|
|
|
3412
|
-
isRunHandlerActive(): boolean {
|
|
3413
|
-
return this.#ctx.runHandlerActive();
|
|
3414
|
-
}
|
|
3415
|
-
|
|
3416
3737
|
async restartRunHandler(): Promise<void> {
|
|
3417
3738
|
await this.#ctx.restartRunHandler();
|
|
3418
3739
|
}
|
|
@@ -3460,28 +3781,33 @@ function withConnContext(
|
|
|
3460
3781
|
stateEnabled = true,
|
|
3461
3782
|
onStateChange?: NativeOnStateChangeHandler,
|
|
3462
3783
|
dispatchCancelToken?: CancellationTokenHandle,
|
|
3784
|
+
runHandlerConfigured = false,
|
|
3463
3785
|
) {
|
|
3464
|
-
|
|
3465
|
-
|
|
3786
|
+
const actorContext = new ActorContextHandleAdapter(
|
|
3787
|
+
runtime,
|
|
3788
|
+
ctx,
|
|
3789
|
+
clientFactory,
|
|
3790
|
+
schemas,
|
|
3791
|
+
databaseProvider,
|
|
3792
|
+
request,
|
|
3793
|
+
stateEnabled,
|
|
3794
|
+
onStateChange,
|
|
3795
|
+
dispatchCancelToken,
|
|
3796
|
+
runHandlerConfigured,
|
|
3797
|
+
);
|
|
3798
|
+
return Object.assign(actorContext, {
|
|
3799
|
+
conn: new NativeConnAdapter(
|
|
3466
3800
|
runtime,
|
|
3467
|
-
|
|
3468
|
-
clientFactory,
|
|
3801
|
+
conn,
|
|
3469
3802
|
schemas,
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
stateEnabled,
|
|
3473
|
-
undefined,
|
|
3474
|
-
onStateChange,
|
|
3475
|
-
dispatchCancelToken,
|
|
3476
|
-
),
|
|
3477
|
-
{
|
|
3478
|
-
conn: new NativeConnAdapter(runtime, conn, schemas, ctx, (connId) =>
|
|
3803
|
+
ctx,
|
|
3804
|
+
(connId) =>
|
|
3479
3805
|
callNativeSync(() =>
|
|
3480
3806
|
runtime.actorQueueHibernationRemoval(ctx, connId),
|
|
3481
3807
|
),
|
|
3482
|
-
),
|
|
3483
|
-
|
|
3484
|
-
);
|
|
3808
|
+
() => actorContext.assertCanMutateState(),
|
|
3809
|
+
),
|
|
3810
|
+
});
|
|
3485
3811
|
}
|
|
3486
3812
|
|
|
3487
3813
|
function buildActorConfig(
|
|
@@ -3494,12 +3820,16 @@ function buildActorConfig(
|
|
|
3494
3820
|
const canHibernate = options.canHibernateWebSocket;
|
|
3495
3821
|
const usesRemoteSqlite =
|
|
3496
3822
|
sqliteBackendForConfig(registryConfig) === "remote";
|
|
3823
|
+
const sqliteProfiling = (
|
|
3824
|
+
config.db as { sqliteProfiling?: SqliteProfilingOptions } | undefined
|
|
3825
|
+
)?.sqliteProfiling;
|
|
3497
3826
|
|
|
3498
3827
|
return {
|
|
3499
3828
|
name: options.name as string | undefined,
|
|
3500
3829
|
icon: options.icon as string | undefined,
|
|
3501
|
-
hasDatabase:
|
|
3830
|
+
hasDatabase: true,
|
|
3502
3831
|
remoteSqlite: usesRemoteSqlite,
|
|
3832
|
+
sqliteProfiling,
|
|
3503
3833
|
enableActorRuntimeSocket: options.enableActorRuntimeSocket === true,
|
|
3504
3834
|
hasState:
|
|
3505
3835
|
config.state !== undefined ||
|
|
@@ -3644,7 +3974,10 @@ export function buildNativeFactory(
|
|
|
3644
3974
|
definition: AnyActorDefinition,
|
|
3645
3975
|
): ActorFactoryHandle {
|
|
3646
3976
|
const config = definition.config as Record<string, any>;
|
|
3647
|
-
const databaseProvider = config.db as
|
|
3977
|
+
const databaseProvider = (config.db ?? defaultDb()) as Exclude<
|
|
3978
|
+
AnyDatabaseProvider,
|
|
3979
|
+
undefined
|
|
3980
|
+
>;
|
|
3648
3981
|
const actionHandlers = flattenActionHandlers(config.actions);
|
|
3649
3982
|
const schemaConfig: NativeValidationConfig = {
|
|
3650
3983
|
actionInputSchemas: flattenActionInputSchemas(
|
|
@@ -3662,16 +3995,21 @@ export function buildNativeFactory(
|
|
|
3662
3995
|
),
|
|
3663
3996
|
{ encoding: "bare" },
|
|
3664
3997
|
);
|
|
3665
|
-
const
|
|
3666
|
-
const
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
const getNativeWorkflowInspector = (ctx: ActorContextHandle) =>
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
callNativeSync(() => runtime.
|
|
3674
|
-
|
|
3998
|
+
const run = getRunFunction(config.run);
|
|
3999
|
+
const runHandlerCoordinator =
|
|
4000
|
+
getRunInspectorKind(config.run) === "workflow"
|
|
4001
|
+
? new RunHandlerCoordinator(config.run)
|
|
4002
|
+
: undefined;
|
|
4003
|
+
const getNativeWorkflowInspector = (ctx: ActorContextHandle) => {
|
|
4004
|
+
const actorId = callNativeSync(() => runtime.actorId(ctx));
|
|
4005
|
+
const restart = () =>
|
|
4006
|
+
callNativeSync(() => runtime.actorRestartRunHandler(ctx));
|
|
4007
|
+
return (runHandlerCoordinator?.getInspector(actorId, restart)
|
|
4008
|
+
?.workflow ??
|
|
4009
|
+
getRunInspectorConfig(config.run, actorId)?.workflow) as
|
|
4010
|
+
| NativeWorkflowInspectorConfig
|
|
4011
|
+
| undefined;
|
|
4012
|
+
};
|
|
3675
4013
|
const onStateChange =
|
|
3676
4014
|
typeof config.onStateChange === "function"
|
|
3677
4015
|
? (actorCtx: ActorContextHandleAdapter, nextState: unknown) => {
|
|
@@ -3704,9 +4042,9 @@ export function buildNativeFactory(
|
|
|
3704
4042
|
databaseProvider,
|
|
3705
4043
|
request,
|
|
3706
4044
|
stateEnabled,
|
|
3707
|
-
() => isNativeRunHandlerActive(ctx),
|
|
3708
4045
|
onStateChange,
|
|
3709
4046
|
cancelToken,
|
|
4047
|
+
run !== undefined,
|
|
3710
4048
|
);
|
|
3711
4049
|
const makeConnCtx = (
|
|
3712
4050
|
ctx: ActorContextHandle,
|
|
@@ -3725,6 +4063,7 @@ export function buildNativeFactory(
|
|
|
3725
4063
|
stateEnabled,
|
|
3726
4064
|
onStateChange,
|
|
3727
4065
|
cancelToken,
|
|
4066
|
+
run !== undefined,
|
|
3728
4067
|
);
|
|
3729
4068
|
const maybeHandleNativeInspectorRequest = async (
|
|
3730
4069
|
ctx: ActorContextHandle,
|
|
@@ -3793,6 +4132,7 @@ export function buildNativeFactory(
|
|
|
3793
4132
|
const workflowState = async () =>
|
|
3794
4133
|
(await getNativeWorkflowInspector(ctx)?.getState?.()) ?? null;
|
|
3795
4134
|
const actorCtx = makeActorCtx(ctx, jsRequest);
|
|
4135
|
+
const sql = getOrCreateNativeSqlDatabase(runtime, ctx);
|
|
3796
4136
|
try {
|
|
3797
4137
|
if (
|
|
3798
4138
|
url.pathname === "/inspector/state" &&
|
|
@@ -3964,7 +4304,7 @@ export function buildNativeFactory(
|
|
|
3964
4304
|
url.pathname === "/inspector/database/schema" &&
|
|
3965
4305
|
jsRequest.method === "GET"
|
|
3966
4306
|
) {
|
|
3967
|
-
const db =
|
|
4307
|
+
const db = sql;
|
|
3968
4308
|
const tables = queryRows(
|
|
3969
4309
|
await db.query(
|
|
3970
4310
|
"SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name",
|
|
@@ -4018,7 +4358,7 @@ export function buildNativeFactory(
|
|
|
4018
4358
|
);
|
|
4019
4359
|
const quoted = `"${table.replace(/"/g, '""')}"`;
|
|
4020
4360
|
const rows = queryRows(
|
|
4021
|
-
await
|
|
4361
|
+
await sql.query(
|
|
4022
4362
|
`SELECT * FROM ${quoted} LIMIT ? OFFSET ?`,
|
|
4023
4363
|
[
|
|
4024
4364
|
Math.max(0, Math.min(limit, 500)),
|
|
@@ -4061,15 +4401,11 @@ export function buildNativeFactory(
|
|
|
4061
4401
|
const bindings = normalizeSqlitePropertyBindings(
|
|
4062
4402
|
body.properties as Record<string, unknown>,
|
|
4063
4403
|
);
|
|
4064
|
-
const rows = queryRows(
|
|
4065
|
-
await actorCtx.sql.query(body.sql, bindings),
|
|
4066
|
-
);
|
|
4404
|
+
const rows = queryRows(await sql.query(body.sql, bindings));
|
|
4067
4405
|
return jsonResponse({ rows: jsonSafe(rows) });
|
|
4068
4406
|
}
|
|
4069
4407
|
const args = Array.isArray(body.args) ? body.args : [];
|
|
4070
|
-
const rows = queryRows(
|
|
4071
|
-
await actorCtx.sql.query(body.sql, args),
|
|
4072
|
-
);
|
|
4408
|
+
const rows = queryRows(await sql.query(body.sql, args));
|
|
4073
4409
|
return jsonResponse({ rows: jsonSafe(rows) });
|
|
4074
4410
|
}
|
|
4075
4411
|
if (
|
|
@@ -4098,7 +4434,7 @@ export function buildNativeFactory(
|
|
|
4098
4434
|
rpcs: Object.keys(actionHandlers).sort(),
|
|
4099
4435
|
queueSize: inspectorSnapshot.queueSize,
|
|
4100
4436
|
isStateEnabled: stateEnabled,
|
|
4101
|
-
isDatabaseEnabled:
|
|
4437
|
+
isDatabaseEnabled: true,
|
|
4102
4438
|
isWorkflowEnabled:
|
|
4103
4439
|
getNativeWorkflowInspector(ctx) !== undefined,
|
|
4104
4440
|
workflowState: await workflowState(),
|
|
@@ -4354,6 +4690,7 @@ export function buildNativeFactory(
|
|
|
4354
4690
|
async (error: unknown, payload: { ctx: ActorContextHandle }) => {
|
|
4355
4691
|
const { ctx } = unwrapTsfnPayload(error, payload);
|
|
4356
4692
|
const actorCtx = makeActorCtx(ctx);
|
|
4693
|
+
const actorId = callNativeSync(() => runtime.actorId(ctx));
|
|
4357
4694
|
// TODO: Move this save hook into cleanupNativeSleepRuntimeState
|
|
4358
4695
|
// so immediate and deferred sleep cleanup share one save-state
|
|
4359
4696
|
// path instead of passing a callback through cleanup.
|
|
@@ -4384,6 +4721,8 @@ export function buildNativeFactory(
|
|
|
4384
4721
|
saveActorState,
|
|
4385
4722
|
);
|
|
4386
4723
|
} finally {
|
|
4724
|
+
runHandlerCoordinator?.destroy(actorId);
|
|
4725
|
+
disposeRunInspector(config.run, actorId);
|
|
4387
4726
|
await actorCtx.dispose();
|
|
4388
4727
|
}
|
|
4389
4728
|
}
|
|
@@ -4393,16 +4732,16 @@ export function buildNativeFactory(
|
|
|
4393
4732
|
async (error: unknown, payload: { ctx: ActorContextHandle }) => {
|
|
4394
4733
|
const { ctx } = unwrapTsfnPayload(error, payload);
|
|
4395
4734
|
const actorCtx = makeActorCtx(ctx);
|
|
4735
|
+
const actorId = callNativeSync(() => runtime.actorId(ctx));
|
|
4736
|
+
// Close run control before user cleanup so replay cannot race actor
|
|
4737
|
+
// destruction. Recreating this actor id receives a fresh controller.
|
|
4738
|
+
runHandlerCoordinator?.destroy(actorId);
|
|
4739
|
+
disposeRunInspector(config.run, actorId);
|
|
4396
4740
|
try {
|
|
4397
4741
|
if (typeof config.onDestroy === "function") {
|
|
4398
4742
|
await config.onDestroy(actorCtx);
|
|
4399
4743
|
}
|
|
4400
4744
|
} finally {
|
|
4401
|
-
const actorId = callNativeSync(() => runtime.actorId(ctx));
|
|
4402
|
-
// Release actorId-keyed state so it does not accumulate per
|
|
4403
|
-
// destroyed actor.
|
|
4404
|
-
nativeRunHandlerActiveByActorId.delete(actorId);
|
|
4405
|
-
disposeRunInspector(config.run, actorId);
|
|
4406
4745
|
resolveNativeDestroy(runtime, ctx);
|
|
4407
4746
|
await actorCtx.closeDatabase();
|
|
4408
4747
|
clearNativeRuntimeState(runtime, ctx);
|
|
@@ -4483,6 +4822,7 @@ export function buildNativeFactory(
|
|
|
4483
4822
|
connId,
|
|
4484
4823
|
),
|
|
4485
4824
|
),
|
|
4825
|
+
() => actorCtx.assertCanMutateState(),
|
|
4486
4826
|
);
|
|
4487
4827
|
try {
|
|
4488
4828
|
const nextConnState = hasStaticConnState
|
|
@@ -4538,6 +4878,7 @@ export function buildNativeFactory(
|
|
|
4538
4878
|
connId,
|
|
4539
4879
|
),
|
|
4540
4880
|
),
|
|
4881
|
+
() => actorCtx.assertCanMutateState(),
|
|
4541
4882
|
);
|
|
4542
4883
|
try {
|
|
4543
4884
|
await config.onConnect(
|
|
@@ -4581,6 +4922,7 @@ export function buildNativeFactory(
|
|
|
4581
4922
|
connId,
|
|
4582
4923
|
),
|
|
4583
4924
|
),
|
|
4925
|
+
() => actorCtx.assertCanMutateState(),
|
|
4584
4926
|
),
|
|
4585
4927
|
);
|
|
4586
4928
|
}
|
|
@@ -4789,7 +5131,6 @@ export function buildNativeFactory(
|
|
|
4789
5131
|
)
|
|
4790
5132
|
: undefined,
|
|
4791
5133
|
run: (() => {
|
|
4792
|
-
const run = getRunFunction(config.run);
|
|
4793
5134
|
if (!run) {
|
|
4794
5135
|
return undefined;
|
|
4795
5136
|
}
|
|
@@ -4801,67 +5142,75 @@ export function buildNativeFactory(
|
|
|
4801
5142
|
) => {
|
|
4802
5143
|
const { ctx } = unwrapTsfnPayload(error, payload);
|
|
4803
5144
|
const actorId = callNativeSync(() => runtime.actorId(ctx));
|
|
4804
|
-
const
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
5145
|
+
const executeRun = async () => {
|
|
5146
|
+
const actorCtx = makeActorCtx(ctx);
|
|
5147
|
+
try {
|
|
5148
|
+
await run(actorCtx);
|
|
5149
|
+
} finally {
|
|
5150
|
+
await actorCtx.dispose();
|
|
5151
|
+
}
|
|
5152
|
+
};
|
|
5153
|
+
if (runHandlerCoordinator) {
|
|
5154
|
+
const outcome = await runHandlerCoordinator.run(
|
|
5155
|
+
actorId,
|
|
5156
|
+
() =>
|
|
5157
|
+
callNativeSync(() =>
|
|
5158
|
+
runtime.actorRestartRunHandler(ctx),
|
|
5159
|
+
),
|
|
5160
|
+
executeRun,
|
|
5161
|
+
);
|
|
5162
|
+
// Only a start suppressed behind a failed replay must preserve a
|
|
5163
|
+
// consumed durable wake. Closed actors must remain closed.
|
|
5164
|
+
return outcome !== "suppressed";
|
|
4815
5165
|
}
|
|
5166
|
+
await executeRun();
|
|
5167
|
+
return true;
|
|
4816
5168
|
},
|
|
4817
5169
|
);
|
|
4818
5170
|
})(),
|
|
4819
|
-
getWorkflowHistory:
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
5171
|
+
getWorkflowHistory: hasRunInspectorConfig(config.run)
|
|
5172
|
+
? wrapNativeCallback(
|
|
5173
|
+
async (
|
|
5174
|
+
error: unknown,
|
|
5175
|
+
payload: { ctx: ActorContextHandle },
|
|
5176
|
+
) => {
|
|
5177
|
+
const { ctx } = unwrapTsfnPayload(error, payload);
|
|
5178
|
+
const history =
|
|
5179
|
+
getNativeWorkflowInspector(ctx)?.getHistory();
|
|
5180
|
+
return history == null
|
|
5181
|
+
? undefined
|
|
5182
|
+
: toUint8Array(history);
|
|
5183
|
+
},
|
|
5184
|
+
)
|
|
5185
|
+
: undefined,
|
|
5186
|
+
replayWorkflow: hasRunInspectorConfig(config.run)
|
|
5187
|
+
? wrapNativeCallback(
|
|
5188
|
+
async (
|
|
5189
|
+
error: unknown,
|
|
5190
|
+
payload: {
|
|
5191
|
+
ctx: ActorContextHandle;
|
|
5192
|
+
entryId?: string;
|
|
4832
5193
|
},
|
|
4833
|
-
)
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
},
|
|
4844
|
-
) => {
|
|
4845
|
-
const { ctx, entryId } = unwrapTsfnPayload(
|
|
4846
|
-
error,
|
|
4847
|
-
payload,
|
|
4848
|
-
);
|
|
4849
|
-
const workflowInspector =
|
|
4850
|
-
getNativeWorkflowInspector(ctx);
|
|
4851
|
-
if (!workflowInspector?.replayFromStep) {
|
|
4852
|
-
return undefined;
|
|
4853
|
-
}
|
|
5194
|
+
) => {
|
|
5195
|
+
const { ctx, entryId } = unwrapTsfnPayload(
|
|
5196
|
+
error,
|
|
5197
|
+
payload,
|
|
5198
|
+
);
|
|
5199
|
+
const workflowInspector =
|
|
5200
|
+
getNativeWorkflowInspector(ctx);
|
|
5201
|
+
if (!workflowInspector?.replayFromStep) {
|
|
5202
|
+
return undefined;
|
|
5203
|
+
}
|
|
4854
5204
|
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
: undefined,
|
|
5205
|
+
const history =
|
|
5206
|
+
(await workflowInspector.replayFromStep(entryId)) ??
|
|
5207
|
+
null;
|
|
5208
|
+
return history == null
|
|
5209
|
+
? undefined
|
|
5210
|
+
: toUint8Array(history);
|
|
5211
|
+
},
|
|
5212
|
+
)
|
|
5213
|
+
: undefined,
|
|
4865
5214
|
actions: Object.fromEntries(
|
|
4866
5215
|
Object.entries(actionHandlers).map(([name, handler]) => [
|
|
4867
5216
|
name,
|
|
@@ -4943,6 +5292,7 @@ export function buildNativeFactory(
|
|
|
4943
5292
|
stateEnabled,
|
|
4944
5293
|
onStateChange,
|
|
4945
5294
|
cancelToken,
|
|
5295
|
+
run !== undefined,
|
|
4946
5296
|
);
|
|
4947
5297
|
try {
|
|
4948
5298
|
if (
|