rivetkit 2.0.6 → 2.0.7-rc.1
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/schemas/actor-persist/v1.ts +0 -6
- package/dist/tsup/actor-router-consts-B3Lu87yJ.d.cts +28 -0
- package/dist/tsup/actor-router-consts-B3Lu87yJ.d.ts +28 -0
- package/dist/tsup/{chunk-MRRT2CZD.cjs → chunk-3MBP4WNC.cjs} +7 -7
- package/dist/tsup/{chunk-MRRT2CZD.cjs.map → chunk-3MBP4WNC.cjs.map} +1 -1
- package/dist/tsup/{chunk-TWGATZ3X.cjs → chunk-3Y45CIF4.cjs} +922 -872
- package/dist/tsup/chunk-3Y45CIF4.cjs.map +1 -0
- package/dist/tsup/chunk-4GP7BZSR.js +102 -0
- package/dist/tsup/chunk-4GP7BZSR.js.map +1 -0
- package/dist/tsup/{chunk-UFWAK3X2.cjs → chunk-5ZOHIKWG.cjs} +660 -385
- package/dist/tsup/chunk-5ZOHIKWG.cjs.map +1 -0
- package/dist/tsup/{chunk-5JBFVV4C.cjs → chunk-6EUWRXLT.cjs} +21 -7
- package/dist/tsup/chunk-6EUWRXLT.cjs.map +1 -0
- package/dist/tsup/{chunk-UTI5NCES.cjs → chunk-6OVKCDSH.cjs} +6 -6
- package/dist/tsup/{chunk-UTI5NCES.cjs.map → chunk-6OVKCDSH.cjs.map} +1 -1
- package/dist/tsup/{chunk-VPV4MWXR.js → chunk-7N56ZUC7.js} +3 -3
- package/dist/tsup/{chunk-DIAYNQTE.cjs → chunk-B3TLRM4Q.cjs} +12 -12
- package/dist/tsup/{chunk-DIAYNQTE.cjs.map → chunk-B3TLRM4Q.cjs.map} +1 -1
- package/dist/tsup/{chunk-4CKHQRXG.js → chunk-BW5DPM6Z.js} +515 -240
- package/dist/tsup/chunk-BW5DPM6Z.js.map +1 -0
- package/dist/tsup/{chunk-NTCUGYSD.cjs → chunk-DFS77KAA.cjs} +34 -31
- package/dist/tsup/chunk-DFS77KAA.cjs.map +1 -0
- package/dist/tsup/{chunk-VCEHU56K.js → chunk-E4UVJKSV.js} +2 -2
- package/dist/tsup/chunk-G4ABMAQY.cjs +102 -0
- package/dist/tsup/chunk-G4ABMAQY.cjs.map +1 -0
- package/dist/tsup/{chunk-ZYLTS2EM.js → chunk-GZVBFXBI.js} +2 -2
- package/dist/tsup/{chunk-W6LN7AF5.js → chunk-HPT3I7UU.js} +866 -816
- package/dist/tsup/chunk-HPT3I7UU.js.map +1 -0
- package/dist/tsup/{chunk-7OUKNSTU.js → chunk-JD54PXWP.js} +17 -14
- package/dist/tsup/chunk-JD54PXWP.js.map +1 -0
- package/dist/tsup/{chunk-KG3C7MKR.cjs → chunk-K4ENQCC4.cjs} +3 -3
- package/dist/tsup/{chunk-KG3C7MKR.cjs.map → chunk-K4ENQCC4.cjs.map} +1 -1
- package/dist/tsup/{chunk-WC2PSJWN.js → chunk-PUSQNDJG.js} +2 -2
- package/dist/tsup/{chunk-RGQR2J7S.js → chunk-RVP5RUSC.js} +20 -6
- package/dist/tsup/chunk-RVP5RUSC.js.map +1 -0
- package/dist/tsup/{chunk-TCUI5JFE.cjs → chunk-SAZCNSVY.cjs} +45 -18
- package/dist/tsup/chunk-SAZCNSVY.cjs.map +1 -0
- package/dist/tsup/{chunk-G75SVQON.js → chunk-SBKRVQS2.js} +9 -5
- package/dist/tsup/chunk-SBKRVQS2.js.map +1 -0
- package/dist/tsup/{chunk-6P6RA47N.cjs → chunk-TZGUSEIJ.cjs} +14 -10
- package/dist/tsup/chunk-TZGUSEIJ.cjs.map +1 -0
- package/dist/tsup/{chunk-2K3JMDAN.js → chunk-YQ4XQYPM.js} +40 -13
- package/dist/tsup/chunk-YQ4XQYPM.js.map +1 -0
- package/dist/tsup/client/mod.cjs +9 -9
- package/dist/tsup/client/mod.d.cts +7 -8
- package/dist/tsup/client/mod.d.ts +7 -8
- package/dist/tsup/client/mod.js +8 -8
- package/dist/tsup/common/log.cjs +3 -3
- package/dist/tsup/common/log.js +2 -2
- package/dist/tsup/common/websocket.cjs +4 -4
- package/dist/tsup/common/websocket.js +3 -3
- package/dist/tsup/{connection-BLemxi4f.d.ts → conn-DCSQgIlw.d.ts} +1605 -1353
- package/dist/tsup/{connection-CpDIydXf.d.cts → conn-DdzHTm2E.d.cts} +1605 -1353
- package/dist/tsup/driver-helpers/mod.cjs +31 -5
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
- package/dist/tsup/driver-helpers/mod.d.cts +7 -8
- package/dist/tsup/driver-helpers/mod.d.ts +7 -8
- package/dist/tsup/driver-helpers/mod.js +33 -7
- package/dist/tsup/driver-test-suite/mod.cjs +317 -222
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
- package/dist/tsup/driver-test-suite/mod.d.cts +7 -7
- package/dist/tsup/driver-test-suite/mod.d.ts +7 -7
- package/dist/tsup/driver-test-suite/mod.js +582 -487
- package/dist/tsup/driver-test-suite/mod.js.map +1 -1
- package/dist/tsup/inspector/mod.cjs +16 -6
- package/dist/tsup/inspector/mod.cjs.map +1 -1
- package/dist/tsup/inspector/mod.d.cts +34 -7
- package/dist/tsup/inspector/mod.d.ts +34 -7
- package/dist/tsup/inspector/mod.js +17 -7
- package/dist/tsup/mod.cjs +10 -20
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +9 -7
- package/dist/tsup/mod.d.ts +9 -7
- package/dist/tsup/mod.js +9 -19
- package/dist/tsup/test/mod.cjs +11 -11
- package/dist/tsup/test/mod.d.cts +6 -7
- package/dist/tsup/test/mod.d.ts +6 -7
- package/dist/tsup/test/mod.js +10 -10
- package/dist/tsup/utils.cjs +4 -2
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +11 -1
- package/dist/tsup/utils.d.ts +11 -1
- package/dist/tsup/utils.js +3 -1
- package/package.json +8 -4
- package/src/actor/action.ts +1 -1
- package/src/actor/config.ts +1 -1
- package/src/actor/conn-drivers.ts +205 -0
- package/src/actor/conn-socket.ts +6 -0
- package/src/actor/{connection.ts → conn.ts} +78 -84
- package/src/actor/context.ts +1 -1
- package/src/actor/driver.ts +4 -43
- package/src/actor/instance.ts +162 -86
- package/src/actor/mod.ts +1 -11
- package/src/actor/persisted.ts +2 -5
- package/src/actor/protocol/old.ts +1 -1
- package/src/actor/router-endpoints.ts +142 -106
- package/src/actor/router.ts +81 -45
- package/src/actor/utils.ts +5 -1
- package/src/client/actor-conn.ts +154 -23
- package/src/client/client.ts +1 -1
- package/src/client/config.ts +7 -0
- package/src/common/actor-router-consts.ts +29 -8
- package/src/common/router.ts +2 -1
- package/src/common/versioned-data.ts +5 -5
- package/src/driver-helpers/mod.ts +14 -1
- package/src/driver-test-suite/mod.ts +11 -2
- package/src/driver-test-suite/test-inline-client-driver.ts +36 -18
- package/src/driver-test-suite/tests/actor-conn-state.ts +66 -22
- package/src/driver-test-suite/tests/actor-conn.ts +65 -126
- package/src/driver-test-suite/tests/actor-reconnect.ts +160 -0
- package/src/driver-test-suite/tests/actor-sleep.ts +0 -1
- package/src/driver-test-suite/tests/raw-websocket.ts +0 -35
- package/src/driver-test-suite/utils.ts +3 -3
- package/src/drivers/default.ts +8 -7
- package/src/drivers/engine/actor-driver.ts +53 -31
- package/src/drivers/engine/config.ts +4 -0
- package/src/drivers/file-system/actor.ts +0 -6
- package/src/drivers/file-system/global-state.ts +3 -14
- package/src/drivers/file-system/manager.ts +12 -8
- package/src/inspector/actor.ts +4 -3
- package/src/inspector/config.ts +10 -1
- package/src/inspector/mod.ts +1 -0
- package/src/inspector/utils.ts +23 -4
- package/src/manager/driver.ts +11 -1
- package/src/manager/gateway.ts +407 -0
- package/src/manager/router.ts +269 -468
- package/src/manager-api/actors.ts +61 -0
- package/src/manager-api/common.ts +4 -0
- package/src/mod.ts +1 -1
- package/src/registry/mod.ts +119 -10
- package/src/remote-manager-driver/actor-http-client.ts +30 -19
- package/src/remote-manager-driver/actor-websocket-client.ts +43 -16
- package/src/remote-manager-driver/api-endpoints.ts +19 -21
- package/src/remote-manager-driver/api-utils.ts +10 -1
- package/src/remote-manager-driver/mod.ts +51 -48
- package/src/remote-manager-driver/ws-proxy.ts +2 -9
- package/src/test/mod.ts +6 -2
- package/src/utils.ts +21 -2
- package/dist/tsup/actor-router-consts-BK6arfy8.d.cts +0 -17
- package/dist/tsup/actor-router-consts-BK6arfy8.d.ts +0 -17
- package/dist/tsup/chunk-2K3JMDAN.js.map +0 -1
- package/dist/tsup/chunk-42I3OZ3Q.js +0 -15
- package/dist/tsup/chunk-42I3OZ3Q.js.map +0 -1
- package/dist/tsup/chunk-4CKHQRXG.js.map +0 -1
- package/dist/tsup/chunk-5JBFVV4C.cjs.map +0 -1
- package/dist/tsup/chunk-6P6RA47N.cjs.map +0 -1
- package/dist/tsup/chunk-7OUKNSTU.js.map +0 -1
- package/dist/tsup/chunk-G75SVQON.js.map +0 -1
- package/dist/tsup/chunk-KUPQZYUQ.cjs +0 -15
- package/dist/tsup/chunk-KUPQZYUQ.cjs.map +0 -1
- package/dist/tsup/chunk-NTCUGYSD.cjs.map +0 -1
- package/dist/tsup/chunk-RGQR2J7S.js.map +0 -1
- package/dist/tsup/chunk-TCUI5JFE.cjs.map +0 -1
- package/dist/tsup/chunk-TWGATZ3X.cjs.map +0 -1
- package/dist/tsup/chunk-UFWAK3X2.cjs.map +0 -1
- package/dist/tsup/chunk-W6LN7AF5.js.map +0 -1
- package/dist/tsup/common-CXCe7s6i.d.cts +0 -218
- package/dist/tsup/common-CXCe7s6i.d.ts +0 -218
- package/src/actor/generic-conn-driver.ts +0 -246
- package/src/common/fake-event-source.ts +0 -267
- package/src/manager-api/routes/actors-create.ts +0 -16
- package/src/manager-api/routes/actors-delete.ts +0 -4
- package/src/manager-api/routes/actors-get-by-id.ts +0 -7
- package/src/manager-api/routes/actors-get-or-create-by-id.ts +0 -29
- package/src/manager-api/routes/actors-get.ts +0 -7
- package/src/manager-api/routes/common.ts +0 -18
- /package/dist/tsup/{chunk-VPV4MWXR.js.map → chunk-7N56ZUC7.js.map} +0 -0
- /package/dist/tsup/{chunk-VCEHU56K.js.map → chunk-E4UVJKSV.js.map} +0 -0
- /package/dist/tsup/{chunk-ZYLTS2EM.js.map → chunk-GZVBFXBI.js.map} +0 -0
- /package/dist/tsup/{chunk-WC2PSJWN.js.map → chunk-PUSQNDJG.js.map} +0 -0
package/src/actor/instance.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as cbor from "cbor-x";
|
|
2
|
+
import type { SSEStreamingApi } from "hono/streaming";
|
|
3
|
+
import type { WSContext } from "hono/ws";
|
|
2
4
|
import invariant from "invariant";
|
|
3
5
|
import onChange from "on-change";
|
|
4
|
-
import type { ActorKey } from "@/actor/mod";
|
|
6
|
+
import type { ActorKey, Encoding } from "@/actor/mod";
|
|
5
7
|
import type { Client } from "@/client/client";
|
|
6
8
|
import { getBaseLogger, getIncludeTarget, type Logger } from "@/common/log";
|
|
7
9
|
import { isCborSerializable, stringifyError } from "@/common/utils";
|
|
@@ -15,22 +17,24 @@ import { TO_CLIENT_VERSIONED } from "@/schemas/client-protocol/versioned";
|
|
|
15
17
|
import {
|
|
16
18
|
bufferToArrayBuffer,
|
|
17
19
|
getEnvUniversal,
|
|
20
|
+
promiseWithResolvers,
|
|
18
21
|
SinglePromiseQueue,
|
|
19
22
|
} from "@/utils";
|
|
20
23
|
import type { ActionContext } from "./action";
|
|
21
24
|
import type { ActorConfig, OnConnectOptions } from "./config";
|
|
25
|
+
import { Conn, type ConnId, generateConnId, generateConnToken } from "./conn";
|
|
22
26
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
type
|
|
26
|
-
|
|
27
|
-
} from "./
|
|
27
|
+
CONN_DRIVERS,
|
|
28
|
+
type ConnDriver,
|
|
29
|
+
type ConnDriverState,
|
|
30
|
+
getConnDriverKindFromState,
|
|
31
|
+
} from "./conn-drivers";
|
|
32
|
+
import type { ConnSocket } from "./conn-socket";
|
|
28
33
|
import { ActorContext } from "./context";
|
|
29
34
|
import type { AnyDatabaseProvider, InferDatabaseClient } from "./database";
|
|
30
|
-
import type { ActorDriver
|
|
35
|
+
import type { ActorDriver } from "./driver";
|
|
31
36
|
import * as errors from "./errors";
|
|
32
37
|
import { serializeActorKey } from "./keys";
|
|
33
|
-
import { loggerWithoutContext } from "./log";
|
|
34
38
|
import type {
|
|
35
39
|
PersistedActor,
|
|
36
40
|
PersistedConn,
|
|
@@ -161,7 +165,6 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
161
165
|
#backgroundPromises: Promise<void>[] = [];
|
|
162
166
|
#abortController = new AbortController();
|
|
163
167
|
#config: ActorConfig<S, CP, CS, V, I, DB>;
|
|
164
|
-
#connectionDrivers!: ConnectionDriversMap;
|
|
165
168
|
#actorDriver!: ActorDriver;
|
|
166
169
|
#inlineClient!: Client<Registry<any>>;
|
|
167
170
|
#actorId!: string;
|
|
@@ -206,9 +209,9 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
206
209
|
getConnections: async () => {
|
|
207
210
|
return Array.from(this.#connections.entries()).map(([id, conn]) => ({
|
|
208
211
|
id,
|
|
209
|
-
stateEnabled: conn.
|
|
210
|
-
params: conn.params as
|
|
211
|
-
state: conn.
|
|
212
|
+
stateEnabled: conn.__stateEnabled,
|
|
213
|
+
params: conn.params as any,
|
|
214
|
+
state: conn.__stateEnabled ? conn.state : undefined,
|
|
212
215
|
}));
|
|
213
216
|
},
|
|
214
217
|
setState: async (state: unknown) => {
|
|
@@ -254,7 +257,6 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
async start(
|
|
257
|
-
connectionDrivers: ConnectionDriversMap,
|
|
258
260
|
actorDriver: ActorDriver,
|
|
259
261
|
inlineClient: Client<Registry<any>>,
|
|
260
262
|
actorId: string,
|
|
@@ -278,7 +280,6 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
278
280
|
),
|
|
279
281
|
);
|
|
280
282
|
|
|
281
|
-
this.#connectionDrivers = connectionDrivers;
|
|
282
283
|
this.#actorDriver = actorDriver;
|
|
283
284
|
this.#inlineClient = inlineClient;
|
|
284
285
|
this.#actorId = actorId;
|
|
@@ -528,7 +529,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
528
529
|
}
|
|
529
530
|
}
|
|
530
531
|
|
|
531
|
-
get
|
|
532
|
+
get connStateEnabled() {
|
|
532
533
|
return "createConnState" in this.#config || "connState" in this.#config;
|
|
533
534
|
}
|
|
534
535
|
|
|
@@ -543,7 +544,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
543
544
|
}
|
|
544
545
|
|
|
545
546
|
/** Promise used to wait for a save to complete. This is required since you cannot await `#saveStateThrottled`. */
|
|
546
|
-
#onPersistSavedPromise?:
|
|
547
|
+
#onPersistSavedPromise?: ReturnType<typeof promiseWithResolvers<void>>;
|
|
547
548
|
|
|
548
549
|
/** Throttled save state method. Used to write to KV at a reasonable cadence. */
|
|
549
550
|
#savePersistThrottled() {
|
|
@@ -719,13 +720,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
719
720
|
// Load connections
|
|
720
721
|
for (const connPersist of this.#persist.connections) {
|
|
721
722
|
// Create connections
|
|
722
|
-
const
|
|
723
|
-
const conn = new Conn<S, CP, CS, V, I, DB>(
|
|
724
|
-
this,
|
|
725
|
-
connPersist,
|
|
726
|
-
driver,
|
|
727
|
-
this.#connStateEnabled,
|
|
728
|
-
);
|
|
723
|
+
const conn = new Conn<S, CP, CS, V, I, DB>(this, connPersist);
|
|
729
724
|
this.#connections.set(conn.id, conn);
|
|
730
725
|
|
|
731
726
|
// Register event subscriptions
|
|
@@ -791,14 +786,52 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
791
786
|
}
|
|
792
787
|
|
|
793
788
|
/**
|
|
794
|
-
*
|
|
789
|
+
* Connection disconnected.
|
|
790
|
+
*
|
|
791
|
+
* If a clean diconnect, will be removed immediately.
|
|
792
|
+
*
|
|
793
|
+
* If not a clean disconnect, will keep the connection alive for a given interval to wait for reconnect.
|
|
795
794
|
*/
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
795
|
+
__connDisconnected(
|
|
796
|
+
conn: Conn<S, CP, CS, V, I, DB>,
|
|
797
|
+
wasClean: boolean,
|
|
798
|
+
socketId: string,
|
|
799
|
+
) {
|
|
800
|
+
// If socket ID is provided, check if it matches the current socket ID
|
|
801
|
+
// If it doesn't match, this is a stale disconnect event from an old socket
|
|
802
|
+
if (socketId && conn.__socket && socketId !== conn.__socket.socketId) {
|
|
803
|
+
this.rLog.debug({
|
|
804
|
+
msg: "ignoring stale disconnect event",
|
|
805
|
+
connId: conn.id,
|
|
806
|
+
eventSocketId: socketId,
|
|
807
|
+
currentSocketId: conn.__socket.socketId,
|
|
808
|
+
});
|
|
799
809
|
return;
|
|
800
810
|
}
|
|
801
811
|
|
|
812
|
+
if (wasClean) {
|
|
813
|
+
// Disconnected cleanly, remove the conn
|
|
814
|
+
|
|
815
|
+
this.#removeConn(conn);
|
|
816
|
+
} else {
|
|
817
|
+
// Disconnected uncleanly, allow reconnection
|
|
818
|
+
|
|
819
|
+
if (!conn.__driverState) {
|
|
820
|
+
this.rLog.warn("called conn disconnected without driver state");
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Update last seen so we know when to clean it up
|
|
824
|
+
conn.__persist.lastSeen = Date.now();
|
|
825
|
+
|
|
826
|
+
// Remove socket
|
|
827
|
+
conn.__socket = undefined;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Removes a connection and cleans up its resources.
|
|
833
|
+
*/
|
|
834
|
+
#removeConn(conn: Conn<S, CP, CS, V, I, DB>) {
|
|
802
835
|
// Remove from persist & save immediately
|
|
803
836
|
const connIdx = this.#persist.connections.findIndex(
|
|
804
837
|
(c) => c.connId === conn.id,
|
|
@@ -846,12 +879,96 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
846
879
|
this.#resetSleepTimer();
|
|
847
880
|
}
|
|
848
881
|
|
|
849
|
-
|
|
882
|
+
/**
|
|
883
|
+
* Called to create a new connection or reconnect an existing one.
|
|
884
|
+
*/
|
|
885
|
+
async createConn(
|
|
886
|
+
socket: ConnSocket,
|
|
850
887
|
// biome-ignore lint/suspicious/noExplicitAny: TypeScript bug with ExtractActorConnParams<this>,
|
|
851
888
|
params: any,
|
|
852
889
|
request?: Request,
|
|
853
|
-
|
|
854
|
-
|
|
890
|
+
connectionId?: string,
|
|
891
|
+
connectionToken?: string,
|
|
892
|
+
): Promise<Conn<S, CP, CS, V, I, DB>> {
|
|
893
|
+
this.#assertReady();
|
|
894
|
+
|
|
895
|
+
// If connection ID and token are provided, try to reconnect
|
|
896
|
+
if (connectionId && connectionToken) {
|
|
897
|
+
this.rLog.debug({
|
|
898
|
+
msg: "checking for existing connection",
|
|
899
|
+
connectionId,
|
|
900
|
+
});
|
|
901
|
+
const existingConn = this.#connections.get(connectionId);
|
|
902
|
+
if (existingConn && existingConn._token === connectionToken) {
|
|
903
|
+
// This is a valid reconnection
|
|
904
|
+
this.rLog.debug({
|
|
905
|
+
msg: "reconnecting existing connection",
|
|
906
|
+
connectionId,
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
// If there's an existing driver state, clean it up without marking as clean disconnect
|
|
910
|
+
if (existingConn.__driverState) {
|
|
911
|
+
const driverKind = getConnDriverKindFromState(
|
|
912
|
+
existingConn.__driverState,
|
|
913
|
+
);
|
|
914
|
+
const driver = CONN_DRIVERS[driverKind];
|
|
915
|
+
if (driver.disconnect) {
|
|
916
|
+
// Call driver disconnect to clean up directly. Don't use Conn.disconnect since that will remove the connection entirely.
|
|
917
|
+
driver.disconnect(
|
|
918
|
+
this,
|
|
919
|
+
existingConn,
|
|
920
|
+
(existingConn.__driverState as any)[driverKind],
|
|
921
|
+
"Reconnecting with new driver state",
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Update with new driver state
|
|
927
|
+
existingConn.__socket = socket;
|
|
928
|
+
existingConn.__persist.lastSeen = Date.now();
|
|
929
|
+
|
|
930
|
+
// Update sleep timer since connection is now active
|
|
931
|
+
this.#resetSleepTimer();
|
|
932
|
+
|
|
933
|
+
this.inspector.emitter.emit("connectionUpdated");
|
|
934
|
+
|
|
935
|
+
// Send init message for reconnection
|
|
936
|
+
existingConn._sendMessage(
|
|
937
|
+
new CachedSerializer<protocol.ToClient>(
|
|
938
|
+
{
|
|
939
|
+
body: {
|
|
940
|
+
tag: "Init",
|
|
941
|
+
val: {
|
|
942
|
+
actorId: this.id,
|
|
943
|
+
connectionId: existingConn.id,
|
|
944
|
+
connectionToken: existingConn._token,
|
|
945
|
+
},
|
|
946
|
+
},
|
|
947
|
+
},
|
|
948
|
+
TO_CLIENT_VERSIONED,
|
|
949
|
+
),
|
|
950
|
+
);
|
|
951
|
+
|
|
952
|
+
return existingConn;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// If we get here, either connection doesn't exist or token doesn't match
|
|
956
|
+
// Fall through to create new connection with new IDs
|
|
957
|
+
this.rLog.debug({
|
|
958
|
+
msg: "connection not found or token mismatch, creating new connection",
|
|
959
|
+
connectionId,
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// Generate new connection ID and token if not provided or if reconnection failed
|
|
964
|
+
const newConnId = generateConnId();
|
|
965
|
+
const newConnToken = generateConnToken();
|
|
966
|
+
|
|
967
|
+
if (this.#connections.has(newConnId)) {
|
|
968
|
+
throw new Error(`Connection already exists: ${newConnId}`);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// Prepare connection state
|
|
855
972
|
let connState: CS | undefined;
|
|
856
973
|
|
|
857
974
|
const onBeforeConnectOpts = {
|
|
@@ -866,7 +983,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
866
983
|
);
|
|
867
984
|
}
|
|
868
985
|
|
|
869
|
-
if (this
|
|
986
|
+
if (this.connStateEnabled) {
|
|
870
987
|
if ("createConnState" in this.#config) {
|
|
871
988
|
const dataOrPromise = this.#config.createConnState(
|
|
872
989
|
this.actorContext as unknown as ActorContext<
|
|
@@ -897,53 +1014,17 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
897
1014
|
}
|
|
898
1015
|
}
|
|
899
1016
|
|
|
900
|
-
return connState as CS;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
__getConnDriver(driverId: ConnectionDriver): ConnDriver {
|
|
904
|
-
// Get driver
|
|
905
|
-
const driver = this.#connectionDrivers[driverId];
|
|
906
|
-
if (!driver) throw new Error(`No connection driver: ${driverId}`);
|
|
907
|
-
return driver;
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
/**
|
|
911
|
-
* Called after establishing a connection handshake.
|
|
912
|
-
*/
|
|
913
|
-
async createConn(
|
|
914
|
-
connectionId: string,
|
|
915
|
-
connectionToken: string,
|
|
916
|
-
params: CP,
|
|
917
|
-
state: CS,
|
|
918
|
-
driverId: ConnectionDriver,
|
|
919
|
-
driverState: unknown,
|
|
920
|
-
authData: unknown,
|
|
921
|
-
): Promise<Conn<S, CP, CS, V, I, DB>> {
|
|
922
|
-
this.#assertReady();
|
|
923
|
-
|
|
924
|
-
if (this.#connections.has(connectionId)) {
|
|
925
|
-
throw new Error(`Connection already exists: ${connectionId}`);
|
|
926
|
-
}
|
|
927
|
-
|
|
928
1017
|
// Create connection
|
|
929
|
-
const driver = this.__getConnDriver(driverId);
|
|
930
1018
|
const persist: PersistedConn<CP, CS> = {
|
|
931
|
-
connId:
|
|
932
|
-
token:
|
|
933
|
-
connDriver: driverId,
|
|
934
|
-
connDriverState: driverState,
|
|
1019
|
+
connId: newConnId,
|
|
1020
|
+
token: newConnToken,
|
|
935
1021
|
params: params,
|
|
936
|
-
state:
|
|
937
|
-
authData: authData,
|
|
1022
|
+
state: connState as CS,
|
|
938
1023
|
lastSeen: Date.now(),
|
|
939
1024
|
subscriptions: [],
|
|
940
1025
|
};
|
|
941
|
-
const conn = new Conn<S, CP, CS, V, I, DB>(
|
|
942
|
-
|
|
943
|
-
persist,
|
|
944
|
-
driver,
|
|
945
|
-
this.#connStateEnabled,
|
|
946
|
-
);
|
|
1026
|
+
const conn = new Conn<S, CP, CS, V, I, DB>(this, persist);
|
|
1027
|
+
conn.__socket = socket;
|
|
947
1028
|
this.#connections.set(conn.id, conn);
|
|
948
1029
|
|
|
949
1030
|
// Update sleep
|
|
@@ -1129,11 +1210,10 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1129
1210
|
this.#rLog.debug({ msg: "checking connections liveness" });
|
|
1130
1211
|
|
|
1131
1212
|
for (const conn of this.#connections.values()) {
|
|
1132
|
-
|
|
1133
|
-
if (liveness.status === "connected") {
|
|
1213
|
+
if (conn.__status === "connected") {
|
|
1134
1214
|
this.#rLog.debug({ msg: "connection is alive", connId: conn.id });
|
|
1135
1215
|
} else {
|
|
1136
|
-
const lastSeen =
|
|
1216
|
+
const lastSeen = conn.__persist.lastSeen;
|
|
1137
1217
|
const sinceLastSeen = Date.now() - lastSeen;
|
|
1138
1218
|
if (sinceLastSeen < this.#config.options.connectionLivenessTimeout) {
|
|
1139
1219
|
this.#rLog.debug({
|
|
@@ -1152,9 +1232,8 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1152
1232
|
lastSeen,
|
|
1153
1233
|
});
|
|
1154
1234
|
|
|
1155
|
-
//
|
|
1156
|
-
|
|
1157
|
-
this.__removeConn(conn);
|
|
1235
|
+
// Assume that the connection is dead here, no need to disconnect anything
|
|
1236
|
+
this.#removeConn(conn);
|
|
1158
1237
|
}
|
|
1159
1238
|
}
|
|
1160
1239
|
}
|
|
@@ -1309,7 +1388,10 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1309
1388
|
/**
|
|
1310
1389
|
* Handles raw HTTP requests to the actor.
|
|
1311
1390
|
*/
|
|
1312
|
-
async handleFetch(
|
|
1391
|
+
async handleFetch(
|
|
1392
|
+
request: Request,
|
|
1393
|
+
opts: Record<never, never>,
|
|
1394
|
+
): Promise<Response> {
|
|
1313
1395
|
this.#assertReady();
|
|
1314
1396
|
|
|
1315
1397
|
if (!this.#config.onFetch) {
|
|
@@ -1562,7 +1644,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1562
1644
|
} else {
|
|
1563
1645
|
// Create callback
|
|
1564
1646
|
if (!this.#onPersistSavedPromise) {
|
|
1565
|
-
this.#onPersistSavedPromise =
|
|
1647
|
+
this.#onPersistSavedPromise = promiseWithResolvers();
|
|
1566
1648
|
}
|
|
1567
1649
|
|
|
1568
1650
|
// Save state throttled
|
|
@@ -1783,10 +1865,6 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1783
1865
|
connections: persist.connections.map((conn) => ({
|
|
1784
1866
|
id: conn.connId,
|
|
1785
1867
|
token: conn.token,
|
|
1786
|
-
driver: conn.connDriver as string,
|
|
1787
|
-
driverState: bufferToArrayBuffer(
|
|
1788
|
-
cbor.encode(conn.connDriverState || {}),
|
|
1789
|
-
),
|
|
1790
1868
|
parameters: bufferToArrayBuffer(cbor.encode(conn.params || {})),
|
|
1791
1869
|
state: bufferToArrayBuffer(cbor.encode(conn.state || {})),
|
|
1792
1870
|
subscriptions: conn.subscriptions.map((sub) => ({
|
|
@@ -1820,8 +1898,6 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1820
1898
|
connections: bareData.connections.map((conn) => ({
|
|
1821
1899
|
connId: conn.id,
|
|
1822
1900
|
token: conn.token,
|
|
1823
|
-
connDriver: conn.driver as ConnectionDriver,
|
|
1824
|
-
connDriverState: cbor.decode(new Uint8Array(conn.driverState)),
|
|
1825
1901
|
params: cbor.decode(new Uint8Array(conn.parameters)),
|
|
1826
1902
|
state: cbor.decode(new Uint8Array(conn.state)),
|
|
1827
1903
|
subscriptions: conn.subscriptions.map((sub) => ({
|
package/src/actor/mod.ts
CHANGED
|
@@ -76,16 +76,10 @@ export type { ActionContext } from "./action";
|
|
|
76
76
|
export type * from "./config";
|
|
77
77
|
export type {
|
|
78
78
|
Conn,
|
|
79
|
-
ConnectionDriver,
|
|
80
79
|
ConnectionStatus,
|
|
81
80
|
generateConnId,
|
|
82
81
|
generateConnToken,
|
|
83
|
-
} from "./
|
|
84
|
-
export {
|
|
85
|
-
CONNECTION_DRIVER_HTTP,
|
|
86
|
-
CONNECTION_DRIVER_SSE,
|
|
87
|
-
CONNECTION_DRIVER_WEBSOCKET,
|
|
88
|
-
} from "./connection";
|
|
82
|
+
} from "./conn";
|
|
89
83
|
export type { ActorContext } from "./context";
|
|
90
84
|
export type {
|
|
91
85
|
ActionContextOf,
|
|
@@ -95,10 +89,6 @@ export type {
|
|
|
95
89
|
} from "./definition";
|
|
96
90
|
export { lookupInRegistry } from "./definition";
|
|
97
91
|
export { UserError, type UserErrorOptions } from "./errors";
|
|
98
|
-
export {
|
|
99
|
-
createGenericConnDrivers,
|
|
100
|
-
GenericConnGlobalState,
|
|
101
|
-
} from "./generic-conn-driver";
|
|
102
92
|
export type { AnyActorInstance } from "./instance";
|
|
103
93
|
export {
|
|
104
94
|
type ActorRouter,
|
package/src/actor/persisted.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { ConnectionDriver } from "./connection";
|
|
2
|
-
|
|
3
1
|
/** State object that gets automatically persisted to storage. */
|
|
4
2
|
export interface PersistedActor<S, CP, CS, I> {
|
|
5
3
|
input?: I;
|
|
@@ -13,12 +11,11 @@ export interface PersistedActor<S, CP, CS, I> {
|
|
|
13
11
|
export interface PersistedConn<CP, CS> {
|
|
14
12
|
connId: string;
|
|
15
13
|
token: string;
|
|
16
|
-
connDriver: ConnectionDriver;
|
|
17
|
-
connDriverState: unknown;
|
|
18
14
|
params: CP;
|
|
19
15
|
state: CS;
|
|
20
|
-
authData?: unknown;
|
|
21
16
|
subscriptions: PersistedSubscription[];
|
|
17
|
+
|
|
18
|
+
/** Last time the socket was seen. This is set when disconencted so we can determine when we need to clean this up. */
|
|
22
19
|
lastSeen: number;
|
|
23
20
|
}
|
|
24
21
|
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import { deserializeWithEncoding } from "@/serde";
|
|
17
17
|
import { assertUnreachable, bufferToArrayBuffer } from "../../utils";
|
|
18
18
|
import { ActionContext } from "../action";
|
|
19
|
-
import type { Conn } from "../
|
|
19
|
+
import type { Conn } from "../conn";
|
|
20
20
|
import type { ActorInstance } from "../instance";
|
|
21
21
|
|
|
22
22
|
export const TransportSchema = z.enum(["websocket", "sse"]);
|