@rivetkit/framework-base 2.0.29 → 2.0.31

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 CHANGED
@@ -6,6 +6,81 @@ _Library to build and scale stateful workloads_
6
6
 
7
7
  [Discord](https://rivet.dev/discord) — [Documentation](https://rivetkit.org) — [Issues](https://github.com/rivet-dev/rivetkit/issues)
8
8
 
9
+ ## Lifecycle
10
+
11
+ ### Mount
12
+
13
+ ```
14
+ 1. useActor(opts) called in React component
15
+
16
+ 2. getOrCreateActor(opts)
17
+ - hash opts to get key
18
+ - sync opts to store (create or update actor entry)
19
+ - if not in cache:
20
+ - create Derived (subscribes to store)
21
+ - create Effect (handles connection logic)
22
+ - add to cache with refCount=0
23
+ - return { mount, state }
24
+
25
+ 3. useEffect runs mount()
26
+ - cancel any pending cleanup timeout
27
+ - refCount++
28
+ - if refCount == 1:
29
+ - mount derived and effect
30
+ - if enabled and idle: call create() directly
31
+ (Effect only runs on state changes, not on mount)
32
+
33
+ 4. Effect triggers (on state changes)
34
+ - if disabled and connected: dispose connection, reset to idle
35
+ - if enabled and idle: call create()
36
+
37
+ 5. create()
38
+ - set connStatus = Connecting
39
+ - handle = client.getOrCreate(name, key)
40
+ - connection = handle.connect()
41
+ - subscribe to connection status/error events
42
+ - store handle and connection in store
43
+
44
+ 6. Connection established
45
+ - connStatus updates, Derived updates, React re-renders
46
+ ```
47
+
48
+ ### Unmount
49
+
50
+ ```
51
+ 1. Component unmounts
52
+ 2. useEffect cleanup runs
53
+ 3. refCount--
54
+ 4. if refCount == 0: setTimeout(cleanup, 0)
55
+ 5. When timeout fires:
56
+ - if refCount > 0: skip (was remounted)
57
+ - else: dispose connection, remove from store/cache
58
+ ```
59
+
60
+ ### React Strict Mode
61
+
62
+ Why `setTimeout` matters:
63
+
64
+ ```
65
+ - render
66
+ - mount: refCount = 1
67
+ - unmount: refCount = 0, schedule timeout
68
+ - remount: refCount = 1, cancel timeout
69
+ - timeout fires: refCount > 0, cleanup skipped
70
+ ```
71
+
72
+ ### Shared Actor
73
+
74
+ Two components using the same actor opts:
75
+
76
+ ```
77
+ - Component A mounts: refCount = 1, connection created
78
+ - Component B mounts: refCount = 2, reuses connection
79
+ - Component A unmounts: refCount = 1, no cleanup
80
+ - Component B unmounts: refCount = 0, cleanup scheduled
81
+ - Timeout fires: connection disposed, removed from cache
82
+ ```
83
+
9
84
  ## License
10
85
 
11
86
  Apache 2.0
package/dist/mod.d.mts ADDED
@@ -0,0 +1,120 @@
1
+ import { Derived, Store } from '@tanstack/store';
2
+ import { Registry, AnyActorDefinition } from 'rivetkit';
3
+ import { ExtractActorsFromRegistry, ActorHandle, ActorConn, ActorConnStatus, Client } from 'rivetkit/client';
4
+ export { ActorConnStatus } from 'rivetkit/client';
5
+
6
+ type AnyActorRegistry = Registry<any>;
7
+
8
+ interface ActorStateReference<AD extends AnyActorDefinition> {
9
+ /**
10
+ * The unique identifier for the actor.
11
+ * This is a hash generated from the actor's options.
12
+ * It is used to identify the actor instance in the store.
13
+ * @internal
14
+ */
15
+ hash: string;
16
+ /**
17
+ * The state of the actor, derived from the store.
18
+ * This includes the actor's connection and handle.
19
+ */
20
+ handle: ActorHandle<AD> | null;
21
+ /**
22
+ * The connection to the actor.
23
+ * This is used to communicate with the actor in realtime.
24
+ */
25
+ connection: ActorConn<AD> | null;
26
+ /**
27
+ * The connection status of the actor.
28
+ */
29
+ connStatus: ActorConnStatus;
30
+ /**
31
+ * The error that occurred while trying to connect to the actor, if any.
32
+ */
33
+ error: Error | null;
34
+ /**
35
+ * Options for the actor, including its name, key, parameters, and whether it is enabled.
36
+ */
37
+ opts: {
38
+ name: keyof AD;
39
+ /**
40
+ * Unique key for the actor instance.
41
+ * This can be a string or an array of strings to create multiple instances.
42
+ * @example "abc" or ["abc", "def"]
43
+ */
44
+ key: string | string[];
45
+ /**
46
+ * Parameters for the actor.
47
+ * These are additional options that can be passed to the actor.
48
+ */
49
+ params?: Record<string, string>;
50
+ /** Region to create the actor in if it doesn't exist. */
51
+ createInRegion?: string;
52
+ /** Input data to pass to the actor. */
53
+ createWithInput?: unknown;
54
+ /**
55
+ * Whether the actor is enabled.
56
+ * Defaults to true.
57
+ */
58
+ enabled?: boolean;
59
+ };
60
+ }
61
+ interface InternalRivetKitStore<Registry extends AnyActorRegistry, Actors extends ExtractActorsFromRegistry<Registry>> {
62
+ actors: Record<string, ActorStateReference<Actors>>;
63
+ }
64
+ /**
65
+ * Options for configuring a actor in RivetKit.
66
+ */
67
+ interface ActorOptions<Registry extends AnyActorRegistry, ActorName extends keyof ExtractActorsFromRegistry<Registry>> {
68
+ /**
69
+ * Typesafe name of the actor.
70
+ * This should match the actor's name in the app's actor definitions.
71
+ * @example "chatRoom"
72
+ */
73
+ name: ActorName;
74
+ /**
75
+ * Unique key for the actor instance.
76
+ * This can be a string or an array of strings to create multiple instances.
77
+ * @example "abc" or ["abc", "def"]
78
+ */
79
+ key: string | string[];
80
+ /**
81
+ * Parameters for the actor.
82
+ */
83
+ params?: Registry[ExtractActorsFromRegistry<Registry>]["params"];
84
+ /** Region to create the actor in if it doesn't exist. */
85
+ createInRegion?: string;
86
+ /** Input data to pass to the actor. */
87
+ createWithInput?: unknown;
88
+ /**
89
+ * Whether the actor is enabled.
90
+ * Defaults to true.
91
+ */
92
+ enabled?: boolean;
93
+ }
94
+ type ActorsStateDerived<Registry extends AnyActorRegistry, WorkerName extends keyof ExtractActorsFromRegistry<Registry>> = Derived<Omit<InternalRivetKitStore<Registry, ExtractActorsFromRegistry<Registry>>["actors"][string], "handle" | "connection"> & {
95
+ handle: ActorHandle<ExtractActorsFromRegistry<Registry>[WorkerName]> | null;
96
+ connection: ActorConn<ExtractActorsFromRegistry<Registry>[WorkerName]> | null;
97
+ /** @deprecated Use `connStatus === "connected"` instead */
98
+ isConnected: boolean;
99
+ }>;
100
+ type AnyActorOptions = ActorOptions<AnyActorRegistry, any>;
101
+ interface CreateRivetKitOptions<Registry extends AnyActorRegistry> {
102
+ hashFunction?: (opts: ActorOptions<Registry, any>) => string;
103
+ }
104
+ declare function createRivetKit<Registry extends AnyActorRegistry, Actors extends ExtractActorsFromRegistry<Registry>>(client: Client<Registry>, createOpts?: CreateRivetKitOptions<Registry>): {
105
+ getOrCreateActor: <ActorName extends keyof Actors>(actorOpts: ActorOptions<Registry, ActorName>) => {
106
+ state: ActorsStateDerived<Registry, ActorName>;
107
+ key: string;
108
+ mount: () => () => void;
109
+ create: () => void;
110
+ refCount: number;
111
+ cleanupTimeout: ReturnType<typeof setTimeout> | null;
112
+ } | {
113
+ mount: () => () => void;
114
+ state: ActorsStateDerived<Registry, ActorName>;
115
+ key: string;
116
+ };
117
+ store: Store<InternalRivetKitStore<Registry, Actors>, (cb: InternalRivetKitStore<Registry, Actors>) => InternalRivetKitStore<Registry, Actors>>;
118
+ };
119
+
120
+ export { type ActorOptions, type ActorsStateDerived, type AnyActorOptions, type AnyActorRegistry, type CreateRivetKitOptions, createRivetKit };
package/dist/mod.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- import { Derived, Store, Updater } from '@tanstack/store';
2
- import { AnyActorDefinition, Registry } from 'rivetkit';
3
- import { ActorConn, ActorHandle, Client, ExtractActorsFromRegistry } from 'rivetkit/client';
4
- export type AnyActorRegistry = Registry<any>;
1
+ import { Derived, Store } from '@tanstack/store';
2
+ import { Registry, AnyActorDefinition } from 'rivetkit';
3
+ import { ExtractActorsFromRegistry, ActorHandle, ActorConn, ActorConnStatus, Client } from 'rivetkit/client';
4
+ export { ActorConnStatus } from 'rivetkit/client';
5
+
6
+ type AnyActorRegistry = Registry<any>;
7
+
5
8
  interface ActorStateReference<AD extends AnyActorDefinition> {
6
9
  /**
7
10
  * The unique identifier for the actor.
@@ -21,17 +24,9 @@ interface ActorStateReference<AD extends AnyActorDefinition> {
21
24
  */
22
25
  connection: ActorConn<AD> | null;
23
26
  /**
24
- * Whether the actor is enabled.
25
- */
26
- isConnected?: boolean;
27
- /**
28
- * Whether the actor is currently connecting, indicating that a connection attempt is in progress.
27
+ * The connection status of the actor.
29
28
  */
30
- isConnecting?: boolean;
31
- /**
32
- * Whether there was an error connecting to the actor.
33
- */
34
- isError?: boolean;
29
+ connStatus: ActorConnStatus;
35
30
  /**
36
31
  * The error that occurred while trying to connect to the actor, if any.
37
32
  */
@@ -69,7 +64,7 @@ interface InternalRivetKitStore<Registry extends AnyActorRegistry, Actors extend
69
64
  /**
70
65
  * Options for configuring a actor in RivetKit.
71
66
  */
72
- export interface ActorOptions<Registry extends AnyActorRegistry, ActorName extends keyof ExtractActorsFromRegistry<Registry>> {
67
+ interface ActorOptions<Registry extends AnyActorRegistry, ActorName extends keyof ExtractActorsFromRegistry<Registry>> {
73
68
  /**
74
69
  * Typesafe name of the actor.
75
70
  * This should match the actor's name in the app's actor definitions.
@@ -96,22 +91,30 @@ export interface ActorOptions<Registry extends AnyActorRegistry, ActorName exten
96
91
  */
97
92
  enabled?: boolean;
98
93
  }
99
- export type ActorsStateDerived<Registry extends AnyActorRegistry, WorkerName extends keyof ExtractActorsFromRegistry<Registry>> = Derived<Omit<InternalRivetKitStore<Registry, ExtractActorsFromRegistry<Registry>>["actors"][string], "handle" | "connection"> & {
94
+ type ActorsStateDerived<Registry extends AnyActorRegistry, WorkerName extends keyof ExtractActorsFromRegistry<Registry>> = Derived<Omit<InternalRivetKitStore<Registry, ExtractActorsFromRegistry<Registry>>["actors"][string], "handle" | "connection"> & {
100
95
  handle: ActorHandle<ExtractActorsFromRegistry<Registry>[WorkerName]> | null;
101
96
  connection: ActorConn<ExtractActorsFromRegistry<Registry>[WorkerName]> | null;
97
+ /** @deprecated Use `connStatus === "connected"` instead */
98
+ isConnected: boolean;
102
99
  }>;
103
- export type AnyActorOptions = ActorOptions<AnyActorRegistry, any>;
104
- export interface CreateRivetKitOptions<Registry extends AnyActorRegistry> {
100
+ type AnyActorOptions = ActorOptions<AnyActorRegistry, any>;
101
+ interface CreateRivetKitOptions<Registry extends AnyActorRegistry> {
105
102
  hashFunction?: (opts: ActorOptions<Registry, any>) => string;
106
103
  }
107
- export declare function createRivetKit<Registry extends AnyActorRegistry, Actors extends ExtractActorsFromRegistry<Registry>, ActorNames extends keyof Actors>(client: Client<Registry>, opts?: CreateRivetKitOptions<Registry>): {
108
- getOrCreateActor: <ActorName extends ActorNames>(opts: ActorOptions<Registry, ActorName>) => {
104
+ declare function createRivetKit<Registry extends AnyActorRegistry, Actors extends ExtractActorsFromRegistry<Registry>>(client: Client<Registry>, createOpts?: CreateRivetKitOptions<Registry>): {
105
+ getOrCreateActor: <ActorName extends keyof Actors>(actorOpts: ActorOptions<Registry, ActorName>) => {
109
106
  state: ActorsStateDerived<Registry, ActorName>;
110
107
  key: string;
111
- mount: () => void;
112
- setState: (set: Updater<ActorStateReference<Actors>>) => void;
108
+ mount: () => () => void;
113
109
  create: () => void;
110
+ refCount: number;
111
+ cleanupTimeout: ReturnType<typeof setTimeout> | null;
112
+ } | {
113
+ mount: () => () => void;
114
+ state: ActorsStateDerived<Registry, ActorName>;
115
+ key: string;
114
116
  };
115
117
  store: Store<InternalRivetKitStore<Registry, Actors>, (cb: InternalRivetKitStore<Registry, Actors>) => InternalRivetKitStore<Registry, Actors>>;
116
118
  };
117
- export {};
119
+
120
+ export { type ActorOptions, type ActorsStateDerived, type AnyActorOptions, type AnyActorRegistry, type CreateRivetKitOptions, createRivetKit };
package/dist/mod.js CHANGED
@@ -1,325 +1,235 @@
1
- const d = /* @__PURE__ */ new WeakMap(), _ = /* @__PURE__ */ new WeakMap(), V = {
2
- current: []
3
- };
4
- let m = !1;
5
- const v = /* @__PURE__ */ new Set(), k = /* @__PURE__ */ new Map();
6
- function E(i) {
7
- const n = Array.from(i).sort((t, e) => t instanceof h && t.options.deps.includes(e) ? 1 : e instanceof h && e.options.deps.includes(t) ? -1 : 0);
8
- for (const t of n) {
9
- if (V.current.includes(t))
10
- continue;
11
- V.current.push(t), t.recompute();
12
- const e = _.get(t);
13
- if (e)
14
- for (const s of e) {
15
- const r = d.get(s);
16
- r && E(r);
17
- }
18
- }
19
- }
20
- function F(i) {
21
- i.listeners.forEach(
22
- (n) => n({
23
- prevVal: i.prevState,
24
- currentVal: i.state
25
- })
26
- );
27
- }
28
- function G(i) {
29
- i.listeners.forEach(
30
- (n) => n({
31
- prevVal: i.prevState,
32
- currentVal: i.state
33
- })
34
- );
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/mod.ts
2
+ var _store = require('@tanstack/store');
3
+ var _fastdeepequal = require('fast-deep-equal'); var _fastdeepequal2 = _interopRequireDefault(_fastdeepequal);
4
+ require('rivetkit/client');
5
+ function createRivetKit(client, createOpts = {}) {
6
+ const store = new (0, _store.Store)({
7
+ actors: {}
8
+ });
9
+ const cache = /* @__PURE__ */ new Map();
10
+ return {
11
+ getOrCreateActor: (actorOpts) => getOrCreateActor(client, createOpts, store, cache, actorOpts),
12
+ store
13
+ };
35
14
  }
36
- function I(i) {
37
- if (v.add(i), !m)
38
- try {
39
- for (m = !0; v.size > 0; ) {
40
- const n = Array.from(v);
41
- v.clear();
42
- for (const t of n) {
43
- const e = k.get(t) ?? t.prevState;
44
- t.prevState = e, F(t);
45
- }
46
- for (const t of n) {
47
- const e = d.get(t);
48
- e && (V.current.push(t), E(e));
49
- }
50
- for (const t of n) {
51
- const e = d.get(t);
52
- if (e)
53
- for (const s of e)
54
- G(s);
55
- }
56
- }
57
- } finally {
58
- m = !1, V.current = [], k.clear();
15
+ function updateActor(store, key, updates) {
16
+ store.setState((prev) => ({
17
+ ...prev,
18
+ actors: {
19
+ ...prev.actors,
20
+ [key]: { ...prev.actors[key], ...updates }
59
21
  }
22
+ }));
60
23
  }
61
- function R(i) {
62
- return typeof i == "function";
63
- }
64
- class w {
65
- constructor(n, t) {
66
- this.listeners = /* @__PURE__ */ new Set(), this.subscribe = (e) => {
67
- var s, r;
68
- this.listeners.add(e);
69
- const p = (r = (s = this.options) == null ? void 0 : s.onSubscribe) == null ? void 0 : r.call(s, e, this);
70
- return () => {
71
- this.listeners.delete(e), p == null || p();
72
- };
73
- }, this.prevState = n, this.state = n, this.options = t;
74
- }
75
- setState(n) {
76
- var t, e, s;
77
- this.prevState = this.state, (t = this.options) != null && t.updateFn ? this.state = this.options.updateFn(this.prevState)(n) : R(n) ? this.state = n(this.prevState) : this.state = n, (s = (e = this.options) == null ? void 0 : e.onUpdate) == null || s.call(e), I(this);
78
- }
79
- }
80
- class h {
81
- constructor(n) {
82
- this.listeners = /* @__PURE__ */ new Set(), this._subscriptions = [], this.lastSeenDepValues = [], this.getDepVals = () => {
83
- const t = [], e = [];
84
- for (const s of this.options.deps)
85
- t.push(s.prevState), e.push(s.state);
86
- return this.lastSeenDepValues = e, {
87
- prevDepVals: t,
88
- currDepVals: e,
89
- prevVal: this.prevState ?? void 0
90
- };
91
- }, this.recompute = () => {
92
- var t, e;
93
- this.prevState = this.state;
94
- const { prevDepVals: s, currDepVals: r, prevVal: p } = this.getDepVals();
95
- this.state = this.options.fn({
96
- prevDepVals: s,
97
- currDepVals: r,
98
- prevVal: p
99
- }), (e = (t = this.options).onUpdate) == null || e.call(t);
100
- }, this.checkIfRecalculationNeededDeeply = () => {
101
- for (const r of this.options.deps)
102
- r instanceof h && r.checkIfRecalculationNeededDeeply();
103
- let t = !1;
104
- const e = this.lastSeenDepValues, { currDepVals: s } = this.getDepVals();
105
- for (let r = 0; r < s.length; r++)
106
- if (s[r] !== e[r]) {
107
- t = !0;
108
- break;
24
+ function getOrCreateActor(client, createOpts, store, cache, actorOpts) {
25
+ const hash = createOpts.hashFunction || defaultHashFunction;
26
+ const normalizedOpts = {
27
+ ...actorOpts,
28
+ enabled: _nullishCoalesce(actorOpts.enabled, () => ( true))
29
+ };
30
+ const key = hash(normalizedOpts);
31
+ const existing = store.state.actors[key];
32
+ if (!existing) {
33
+ store.setState((prev) => ({
34
+ ...prev,
35
+ actors: {
36
+ ...prev.actors,
37
+ [key]: {
38
+ hash: key,
39
+ connStatus: "idle",
40
+ connection: null,
41
+ handle: null,
42
+ error: null,
43
+ opts: normalizedOpts
109
44
  }
110
- t && this.recompute();
111
- }, this.mount = () => (this.registerOnGraph(), this.checkIfRecalculationNeededDeeply(), () => {
112
- this.unregisterFromGraph();
113
- for (const t of this._subscriptions)
114
- t();
115
- }), this.subscribe = (t) => {
116
- var e, s;
117
- this.listeners.add(t);
118
- const r = (s = (e = this.options).onSubscribe) == null ? void 0 : s.call(e, t, this);
119
- return () => {
120
- this.listeners.delete(t), r == null || r();
121
- };
122
- }, this.options = n, this.state = n.fn({
123
- prevDepVals: void 0,
124
- prevVal: void 0,
125
- currDepVals: this.getDepVals().currDepVals
126
- });
127
- }
128
- registerOnGraph(n = this.options.deps) {
129
- for (const t of n)
130
- if (t instanceof h)
131
- t.registerOnGraph(), this.registerOnGraph(t.options.deps);
132
- else if (t instanceof w) {
133
- let e = d.get(t);
134
- e || (e = /* @__PURE__ */ new Set(), d.set(t, e)), e.add(this);
135
- let s = _.get(this);
136
- s || (s = /* @__PURE__ */ new Set(), _.set(this, s)), s.add(t);
137
- }
138
- }
139
- unregisterFromGraph(n = this.options.deps) {
140
- for (const t of n)
141
- if (t instanceof h)
142
- this.unregisterFromGraph(t.options.deps);
143
- else if (t instanceof w) {
144
- const e = d.get(t);
145
- e && e.delete(this);
146
- const s = _.get(this);
147
- s && s.delete(t);
148
45
  }
46
+ }));
47
+ } else if (!optsEqual(existing.opts, normalizedOpts)) {
48
+ queueMicrotask(() => {
49
+ updateActor(store, key, { opts: normalizedOpts });
50
+ });
149
51
  }
150
- }
151
- class N {
152
- constructor(n) {
153
- const { eager: t, fn: e, ...s } = n;
154
- this._derived = new h({
155
- ...s,
156
- fn: () => {
157
- },
158
- onUpdate() {
159
- e();
160
- }
161
- }), t && e();
162
- }
163
- mount() {
164
- return this._derived.mount();
52
+ const cached = cache.get(key);
53
+ if (cached) {
54
+ return {
55
+ ...cached,
56
+ state: cached.state
57
+ };
165
58
  }
166
- }
167
- function L(i, n = {}) {
168
- const t = new w({
169
- actors: {}
170
- }), e = n.hashFunction || A, s = /* @__PURE__ */ new Map();
171
- function r(p) {
172
- const o = e(p), D = s.get(o);
173
- if (D)
59
+ const derived = new (0, _store.Derived)({
60
+ fn: ({ currDepVals: [store2] }) => {
61
+ const actor = store2.actors[key];
174
62
  return {
175
- ...D,
176
- state: D.state
63
+ ...actor,
64
+ /** @deprecated Use `connStatus === "connected"` instead */
65
+ isConnected: actor.connStatus === "connected"
177
66
  };
178
- const g = new h({
179
- fn: ({ currDepVals: [a] }) => a.actors[o],
180
- deps: [t]
181
- });
182
- function b() {
183
- async function a() {
184
- const c = t.state.actors[o];
185
- try {
186
- const f = i.getOrCreate(
187
- c.opts.name,
188
- c.opts.key,
189
- {
190
- params: c.opts.params,
191
- createInRegion: c.opts.createInRegion,
192
- createWithInput: c.opts.createWithInput
193
- }
194
- ), u = f.connect();
195
- u.onOpen(() => {
196
- t.setState((l) => {
197
- var S;
198
- return ((S = l.actors[o]) == null ? void 0 : S.connection) !== u ? l : {
199
- ...l,
200
- actors: {
201
- ...l.actors,
202
- [o]: {
203
- ...l.actors[o],
204
- isConnected: !0
205
- }
206
- }
207
- };
208
- });
209
- }), u.onClose(() => {
210
- t.setState((l) => {
211
- var S;
212
- return ((S = l.actors[o]) == null ? void 0 : S.connection) !== u ? l : {
213
- ...l,
214
- actors: {
215
- ...l.actors,
216
- [o]: {
217
- ...l.actors[o],
218
- isConnected: !1
219
- }
220
- }
221
- };
222
- });
223
- }), await f.resolve(
224
- /*{ signal: AbortSignal.timeout(0) }*/
225
- ), t.setState((l) => ({
226
- ...l,
227
- actors: {
228
- ...l.actors,
229
- [o]: {
230
- ...l.actors[o],
231
- isConnected: u.isConnected,
232
- isConnecting: !1,
233
- handle: f,
234
- connection: u,
235
- isError: !1,
236
- error: null
237
- }
238
- }
239
- }));
240
- } catch (f) {
241
- t.setState((u) => ({
242
- ...u,
243
- actors: {
244
- ...u.actors,
245
- [o]: {
246
- ...u.actors[o],
247
- isError: !0,
248
- isConnecting: !1,
249
- error: f
250
- }
251
- }
252
- }));
253
- }
67
+ },
68
+ deps: [store]
69
+ });
70
+ const effect = new (0, _store.Effect)({
71
+ fn: () => {
72
+ const actor = store.state.actors[key];
73
+ if (!actor) {
74
+ throw new Error(
75
+ `Actor with key "${key}" not found in store. This indicates a bug in cleanup logic.`
76
+ );
254
77
  }
255
- t.setState((c) => (c.actors[o].isConnecting = !0, c.actors[o].isError = !1, c.actors[o].error = null, a(), c));
256
- }
257
- const O = new N({
258
- fn: () => {
259
- const a = t.state.actors[o];
260
- JSON.stringify(t.prevState.actors[o].opts) === JSON.stringify(t.state.actors[o].opts) && !a.isConnected && !a.isConnecting && !a.isError && a.opts.enabled && b();
261
- },
262
- deps: [g]
263
- });
264
- t.setState((a) => a.actors[o] ? a : {
265
- ...a,
266
- actors: {
267
- ...a.actors,
268
- [o]: {
269
- hash: o,
270
- isConnected: !1,
271
- isConnecting: !1,
78
+ if (!actor.opts.enabled && actor.connection) {
79
+ actor.connection.dispose();
80
+ updateActor(store, key, {
272
81
  connection: null,
273
82
  handle: null,
274
- isError: !1,
275
- error: null,
276
- opts: p
277
- }
83
+ connStatus: "idle"
84
+ });
85
+ return;
86
+ }
87
+ if (actor.connStatus === "idle" && actor.opts.enabled) {
88
+ queueMicrotask(() => {
89
+ const currentActor = store.state.actors[key];
90
+ if (currentActor && currentActor.connStatus === "idle" && currentActor.opts.enabled) {
91
+ create(client, store, key);
92
+ }
93
+ });
278
94
  }
95
+ },
96
+ deps: [derived]
97
+ });
98
+ let unsubscribeDerived = null;
99
+ let unsubscribeEffect = null;
100
+ const mount = () => {
101
+ const cached2 = cache.get(key);
102
+ if (!cached2) {
103
+ throw new Error(
104
+ `Actor with key "${key}" not found in cache. This indicates a bug in cleanup logic.`
105
+ );
106
+ }
107
+ if (cached2.cleanupTimeout !== null) {
108
+ clearTimeout(cached2.cleanupTimeout);
109
+ cached2.cleanupTimeout = null;
110
+ }
111
+ cached2.refCount++;
112
+ if (cached2.refCount === 1) {
113
+ unsubscribeDerived = derived.mount();
114
+ unsubscribeEffect = effect.mount();
115
+ const actor = store.state.actors[key];
116
+ if (actor && actor.opts.enabled && actor.connStatus === "idle") {
117
+ create(client, store, key);
118
+ }
119
+ }
120
+ return () => {
121
+ cached2.refCount--;
122
+ if (cached2.refCount === 0) {
123
+ cached2.cleanupTimeout = setTimeout(() => {
124
+ cached2.cleanupTimeout = null;
125
+ if (cached2.refCount > 0) return;
126
+ unsubscribeDerived == null ? void 0 : unsubscribeDerived();
127
+ unsubscribeEffect == null ? void 0 : unsubscribeEffect();
128
+ unsubscribeDerived = null;
129
+ unsubscribeEffect = null;
130
+ const actor = store.state.actors[key];
131
+ if (actor == null ? void 0 : actor.connection) {
132
+ actor.connection.dispose();
133
+ }
134
+ store.setState((prev) => {
135
+ const { [key]: _, ...rest } = prev.actors;
136
+ return { ...prev, actors: rest };
137
+ });
138
+ cache.delete(key);
139
+ }, 0);
140
+ }
141
+ };
142
+ };
143
+ cache.set(key, {
144
+ state: derived,
145
+ key,
146
+ mount,
147
+ create: create.bind(void 0, client, store, key),
148
+ refCount: 0,
149
+ cleanupTimeout: null
150
+ });
151
+ return {
152
+ mount,
153
+ state: derived,
154
+ key
155
+ };
156
+ }
157
+ function create(client, store, key) {
158
+ const actor = store.state.actors[key];
159
+ if (!actor) {
160
+ throw new Error(
161
+ `Actor with key "${key}" not found in store. This indicates a bug in cleanup logic.`
162
+ );
163
+ }
164
+ updateActor(store, key, {
165
+ connStatus: "connecting",
166
+ error: null
167
+ });
168
+ try {
169
+ const handle = client.getOrCreate(
170
+ actor.opts.name,
171
+ actor.opts.key,
172
+ {
173
+ params: actor.opts.params,
174
+ createInRegion: actor.opts.createInRegion,
175
+ createWithInput: actor.opts.createWithInput
176
+ }
177
+ );
178
+ const connection = handle.connect();
179
+ updateActor(store, key, {
180
+ handle,
181
+ connection
279
182
  });
280
- function y(a) {
281
- t.setState((c) => {
282
- const f = c.actors[o];
283
- if (!f)
284
- throw new Error(`Actor with key "${o}" does not exist.`);
285
- let u;
286
- return typeof a == "function" ? u = a(f) : u = a, {
287
- ...c,
183
+ connection.onStatusChange((status) => {
184
+ store.setState((prev) => {
185
+ var _a;
186
+ const isActiveConnection = ((_a = prev.actors[key]) == null ? void 0 : _a.connection) === connection;
187
+ if (!isActiveConnection) return prev;
188
+ return {
189
+ ...prev,
288
190
  actors: {
289
- ...c.actors,
290
- [o]: u
191
+ ...prev.actors,
192
+ [key]: {
193
+ ...prev.actors[key],
194
+ connStatus: status,
195
+ // Only clear error when successfully connected
196
+ ...status === "connected" ? { error: null } : {}
197
+ }
291
198
  }
292
199
  };
293
200
  });
294
- }
295
- const C = () => {
296
- const a = g.mount(), c = O.mount();
297
- return () => {
298
- a(), c();
299
- };
300
- };
301
- return s.set(o, {
302
- state: g,
303
- key: o,
304
- mount: C,
305
- setState: y,
306
- create: b
307
- }), {
308
- mount: C,
309
- setState: y,
310
- state: g,
311
- create: b,
312
- key: o
313
- };
201
+ });
202
+ connection.onError((error) => {
203
+ store.setState((prev) => {
204
+ var _a;
205
+ if (((_a = prev.actors[key]) == null ? void 0 : _a.connection) !== connection) return prev;
206
+ return {
207
+ ...prev,
208
+ actors: {
209
+ ...prev.actors,
210
+ [key]: {
211
+ ...prev.actors[key],
212
+ error
213
+ }
214
+ }
215
+ };
216
+ });
217
+ });
218
+ } catch (error) {
219
+ console.error("Failed to create actor connection", error);
220
+ updateActor(store, key, {
221
+ connStatus: "disconnected",
222
+ error
223
+ });
314
224
  }
315
- return {
316
- getOrCreateActor: r,
317
- store: t
318
- };
319
225
  }
320
- function A({ name: i, key: n, params: t }) {
321
- return JSON.stringify({ name: i, key: n, params: t });
226
+ function defaultHashFunction({ name, key, params }) {
227
+ return JSON.stringify({ name, key, params });
228
+ }
229
+ function optsEqual(a, b) {
230
+ return _fastdeepequal2.default.call(void 0, a, b);
322
231
  }
323
- export {
324
- L as createRivetKit
325
- };
232
+
233
+
234
+ exports.createRivetKit = createRivetKit;
235
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/framework-base/dist/mod.js","../src/mod.ts"],"names":["store","cached"],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/framework-base/dist/mod.js","sourcesContent":[null,"import { Derived, Effect, Store } from \"@tanstack/store\";\nimport equal from \"fast-deep-equal\";\nimport type { AnyActorDefinition, Registry } from \"rivetkit\";\nimport {\n\ttype ActorConn,\n\ttype ActorConnStatus,\n\ttype ActorHandle,\n\ttype Client,\n\ttype ExtractActorsFromRegistry,\n} from \"rivetkit/client\";\n\nexport type AnyActorRegistry = Registry<any>;\n\nexport type { ActorConnStatus };\n\ninterface ActorStateReference<AD extends AnyActorDefinition> {\n\t/**\n\t * The unique identifier for the actor.\n\t * This is a hash generated from the actor's options.\n\t * It is used to identify the actor instance in the store.\n\t * @internal\n\t */\n\thash: string;\n\t/**\n\t * The state of the actor, derived from the store.\n\t * This includes the actor's connection and handle.\n\t */\n\thandle: ActorHandle<AD> | null;\n\t/**\n\t * The connection to the actor.\n\t * This is used to communicate with the actor in realtime.\n\t */\n\tconnection: ActorConn<AD> | null;\n\t/**\n\t * The connection status of the actor.\n\t */\n\tconnStatus: ActorConnStatus;\n\t/**\n\t * The error that occurred while trying to connect to the actor, if any.\n\t */\n\terror: Error | null;\n\t/**\n\t * Options for the actor, including its name, key, parameters, and whether it is enabled.\n\t */\n\topts: {\n\t\tname: keyof AD;\n\t\t/**\n\t\t * Unique key for the actor instance.\n\t\t * This can be a string or an array of strings to create multiple instances.\n\t\t * @example \"abc\" or [\"abc\", \"def\"]\n\t\t */\n\t\tkey: string | string[];\n\t\t/**\n\t\t * Parameters for the actor.\n\t\t * These are additional options that can be passed to the actor.\n\t\t */\n\t\tparams?: Record<string, string>;\n\t\t/** Region to create the actor in if it doesn't exist. */\n\t\tcreateInRegion?: string;\n\t\t/** Input data to pass to the actor. */\n\t\tcreateWithInput?: unknown;\n\t\t/**\n\t\t * Whether the actor is enabled.\n\t\t * Defaults to true.\n\t\t */\n\t\tenabled?: boolean;\n\t};\n}\n\ninterface InternalRivetKitStore<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> {\n\tactors: Record<string, ActorStateReference<Actors>>;\n}\n\n/**\n * Options for configuring a actor in RivetKit.\n */\nexport interface ActorOptions<\n\tRegistry extends AnyActorRegistry,\n\tActorName extends keyof ExtractActorsFromRegistry<Registry>,\n> {\n\t/**\n\t * Typesafe name of the actor.\n\t * This should match the actor's name in the app's actor definitions.\n\t * @example \"chatRoom\"\n\t */\n\tname: ActorName;\n\t/**\n\t * Unique key for the actor instance.\n\t * This can be a string or an array of strings to create multiple instances.\n\t * @example \"abc\" or [\"abc\", \"def\"]\n\t */\n\tkey: string | string[];\n\t/**\n\t * Parameters for the actor.\n\t */\n\tparams?: Registry[ExtractActorsFromRegistry<Registry>][\"params\"];\n\t/** Region to create the actor in if it doesn't exist. */\n\tcreateInRegion?: string;\n\t/** Input data to pass to the actor. */\n\tcreateWithInput?: unknown;\n\t/**\n\t * Whether the actor is enabled.\n\t * Defaults to true.\n\t */\n\tenabled?: boolean;\n}\n\nexport type ActorsStateDerived<\n\tRegistry extends AnyActorRegistry,\n\tWorkerName extends keyof ExtractActorsFromRegistry<Registry>,\n> = Derived<\n\tOmit<\n\t\tInternalRivetKitStore<\n\t\t\tRegistry,\n\t\t\tExtractActorsFromRegistry<Registry>\n\t\t>[\"actors\"][string],\n\t\t\"handle\" | \"connection\"\n\t> & {\n\t\thandle: ActorHandle<\n\t\t\tExtractActorsFromRegistry<Registry>[WorkerName]\n\t\t> | null;\n\t\tconnection: ActorConn<\n\t\t\tExtractActorsFromRegistry<Registry>[WorkerName]\n\t\t> | null;\n\t\t/** @deprecated Use `connStatus === \"connected\"` instead */\n\t\tisConnected: boolean;\n\t}\n>;\n\nexport type AnyActorOptions = ActorOptions<AnyActorRegistry, any>;\n\nexport interface CreateRivetKitOptions<Registry extends AnyActorRegistry> {\n\thashFunction?: (opts: ActorOptions<Registry, any>) => string;\n}\n\ntype ComputedActorState<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> = InternalRivetKitStore<Registry, Actors>[\"actors\"][string] & {\n\t/** @deprecated Use `connStatus === \"connected\"` instead */\n\tisConnected: boolean;\n};\n\ntype ActorCache<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> = Map<\n\tstring,\n\t{\n\t\tstate: Derived<ComputedActorState<Registry, Actors>>;\n\t\tkey: string;\n\t\tmount: () => () => void;\n\t\tcreate: () => void;\n\t\trefCount: number;\n\t\tcleanupTimeout: ReturnType<typeof setTimeout> | null;\n\t}\n>;\n\nexport function createRivetKit<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n>(client: Client<Registry>, createOpts: CreateRivetKitOptions<Registry> = {}) {\n\tconst store = new Store<InternalRivetKitStore<Registry, Actors>>({\n\t\tactors: {},\n\t});\n\n\tconst cache: ActorCache<Registry, Actors> = new Map();\n\n\treturn {\n\t\tgetOrCreateActor: <ActorName extends keyof Actors>(\n\t\t\tactorOpts: ActorOptions<Registry, ActorName>,\n\t\t) => getOrCreateActor(client, createOpts, store, cache, actorOpts),\n\t\tstore,\n\t};\n}\n\ntype ActorUpdates<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> = Partial<InternalRivetKitStore<Registry, Actors>[\"actors\"][string]>;\n\nfunction updateActor<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n>(\n\tstore: Store<InternalRivetKitStore<Registry, Actors>>,\n\tkey: string,\n\tupdates: ActorUpdates<Registry, Actors>,\n) {\n\tstore.setState((prev) => ({\n\t\t...prev,\n\t\tactors: {\n\t\t\t...prev.actors,\n\t\t\t[key]: { ...prev.actors[key], ...updates },\n\t\t},\n\t}));\n}\n\n// See README.md for lifecycle documentation.\nfunction getOrCreateActor<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n\tActorName extends keyof Actors,\n>(\n\tclient: Client<Registry>,\n\tcreateOpts: CreateRivetKitOptions<Registry>,\n\tstore: Store<InternalRivetKitStore<Registry, Actors>>,\n\tcache: ActorCache<Registry, Actors>,\n\tactorOpts: ActorOptions<Registry, ActorName>,\n) {\n\tconst hash = createOpts.hashFunction || defaultHashFunction;\n\n\tconst normalizedOpts = {\n\t\t...actorOpts,\n\t\tenabled: actorOpts.enabled ?? true,\n\t};\n\n\tconst key = hash(normalizedOpts);\n\n\t// Sync opts to store on every call (even for cached entries)\n\t// Use queueMicrotask for updates to avoid \"Cannot update a component while rendering\" React error\n\tconst existing = store.state.actors[key];\n\tif (!existing) {\n\t\tstore.setState((prev) => ({\n\t\t\t...prev,\n\t\t\tactors: {\n\t\t\t\t...prev.actors,\n\t\t\t\t[key]: {\n\t\t\t\t\thash: key,\n\t\t\t\t\tconnStatus: \"idle\",\n\t\t\t\t\tconnection: null,\n\t\t\t\t\thandle: null,\n\t\t\t\t\terror: null,\n\t\t\t\t\topts: normalizedOpts,\n\t\t\t\t},\n\t\t\t},\n\t\t}));\n\t} else if (!optsEqual(existing.opts, normalizedOpts)) {\n\t\t// Defer opts update to avoid triggering re-render during render\n\t\tqueueMicrotask(() => {\n\t\t\tupdateActor(store, key, { opts: normalizedOpts });\n\t\t});\n\t}\n\n\tconst cached = cache.get(key);\n\tif (cached) {\n\t\treturn {\n\t\t\t...cached,\n\t\t\tstate: cached.state as ActorsStateDerived<Registry, ActorName>,\n\t\t};\n\t}\n\n\tconst derived = new Derived({\n\t\tfn: ({ currDepVals: [store] }) => {\n\t\t\tconst actor = store.actors[key];\n\t\t\treturn {\n\t\t\t\t...actor,\n\t\t\t\t/** @deprecated Use `connStatus === \"connected\"` instead */\n\t\t\t\tisConnected: actor.connStatus === \"connected\",\n\t\t\t};\n\t\t},\n\t\tdeps: [store],\n\t});\n\n\t// Handle enabled/disabled state changes.\n\t// Initial connection is triggered directly in mount() since Effect\n\t// only runs on state changes, not on mount.\n\tconst effect = new Effect({\n\t\tfn: () => {\n\t\t\tconst actor = store.state.actors[key];\n\t\t\tif (!actor) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Actor with key \"${key}\" not found in store. This indicates a bug in cleanup logic.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Dispose connection if disabled\n\t\t\tif (!actor.opts.enabled && actor.connection) {\n\t\t\t\tactor.connection.dispose();\n\n\t\t\t\t// Reset state so re-enabling will reconnect\n\t\t\t\tupdateActor(store, key, {\n\t\t\t\t\tconnection: null,\n\t\t\t\t\thandle: null,\n\t\t\t\t\tconnStatus: \"idle\",\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Reconnect when re-enabled after being disabled\n\t\t\t// Defer to avoid \"Cannot update a component while rendering\" React error\n\t\t\tif (\n\t\t\t\tactor.connStatus === \"idle\" &&\n\t\t\t\tactor.opts.enabled\n\t\t\t) {\n\t\t\t\tqueueMicrotask(() => {\n\t\t\t\t\t// Re-check state after microtask in case it changed\n\t\t\t\t\tconst currentActor = store.state.actors[key];\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrentActor &&\n\t\t\t\t\t\tcurrentActor.connStatus === \"idle\" &&\n\t\t\t\t\t\tcurrentActor.opts.enabled\n\t\t\t\t\t) {\n\t\t\t\t\t\tcreate<Registry, Actors, ActorName>(client, store, key);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tdeps: [derived],\n\t});\n\n\t// Track subscriptions for ref counting\n\tlet unsubscribeDerived: (() => void) | null = null;\n\tlet unsubscribeEffect: (() => void) | null = null;\n\n\tconst mount = () => {\n\t\tconst cached = cache.get(key);\n\t\tif (!cached) {\n\t\t\tthrow new Error(\n\t\t\t\t`Actor with key \"${key}\" not found in cache. This indicates a bug in cleanup logic.`,\n\t\t\t);\n\t\t}\n\n\t\t// Cancel pending cleanup\n\t\tif (cached.cleanupTimeout !== null) {\n\t\t\tclearTimeout(cached.cleanupTimeout);\n\t\t\tcached.cleanupTimeout = null;\n\t\t}\n\n\t\t// Increment ref count\n\t\tcached.refCount++;\n\n\t\t// Mount derived/effect on first reference (or re-mount after cleanup)\n\t\tif (cached.refCount === 1) {\n\t\t\tunsubscribeDerived = derived.mount();\n\t\t\tunsubscribeEffect = effect.mount();\n\n\t\t\t// Effect doesn't run immediately on mount, only on state changes.\n\t\t\t// Trigger initial connection if actor is enabled and idle.\n\t\t\tconst actor = store.state.actors[key];\n\t\t\tif (\n\t\t\t\tactor &&\n\t\t\t\tactor.opts.enabled &&\n\t\t\t\tactor.connStatus === \"idle\"\n\t\t\t) {\n\t\t\t\tcreate<Registry, Actors, ActorName>(client, store, key);\n\t\t\t}\n\t\t}\n\n\t\treturn () => {\n\t\t\t// Decrement ref count\n\t\t\tcached.refCount--;\n\n\t\t\tif (cached.refCount === 0) {\n\t\t\t\t// Deferred cleanup prevents needless reconnection when:\n\t\t\t\t// - React Strict Mode's unmount/remount cycle\n\t\t\t\t// - useActor hook moves between components in the same render cycle\n\t\t\t\tcached.cleanupTimeout = setTimeout(() => {\n\t\t\t\t\tcached.cleanupTimeout = null;\n\t\t\t\t\tif (cached.refCount > 0) return;\n\n\t\t\t\t\t// Unsubscribe from derived/effect\n\t\t\t\t\tunsubscribeDerived?.();\n\t\t\t\t\tunsubscribeEffect?.();\n\t\t\t\t\tunsubscribeDerived = null;\n\t\t\t\t\tunsubscribeEffect = null;\n\n\t\t\t\t\t// Dispose connection\n\t\t\t\t\tconst actor = store.state.actors[key];\n\t\t\t\t\tif (actor?.connection) {\n\t\t\t\t\t\tactor.connection.dispose();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove from store and cache\n\t\t\t\t\tstore.setState((prev) => {\n\t\t\t\t\t\tconst { [key]: _, ...rest } = prev.actors;\n\t\t\t\t\t\treturn { ...prev, actors: rest };\n\t\t\t\t\t});\n\t\t\t\t\tcache.delete(key);\n\t\t\t\t}, 0);\n\t\t\t}\n\t\t};\n\t};\n\n\tcache.set(key, {\n\t\tstate: derived,\n\t\tkey,\n\t\tmount,\n\t\tcreate: create.bind(undefined, client, store, key),\n\t\trefCount: 0,\n\t\tcleanupTimeout: null,\n\t});\n\n\treturn {\n\t\tmount,\n\t\tstate: derived as ActorsStateDerived<Registry, ActorName>,\n\t\tkey,\n\t};\n}\n\nfunction create<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n\tActorName extends keyof Actors,\n>(\n\tclient: Client<Registry>,\n\tstore: Store<InternalRivetKitStore<Registry, Actors>>,\n\tkey: string,\n) {\n\tconst actor = store.state.actors[key];\n\tif (!actor) {\n\t\tthrow new Error(\n\t\t\t`Actor with key \"${key}\" not found in store. This indicates a bug in cleanup logic.`,\n\t\t);\n\t}\n\n\t// Save actor to map\n\tupdateActor(store, key, {\n\t\tconnStatus: \"connecting\",\n\t\terror: null,\n\t});\n\n\ttry {\n\t\tconst handle = client.getOrCreate(\n\t\t\tactor.opts.name as string,\n\t\t\tactor.opts.key,\n\t\t\t{\n\t\t\t\tparams: actor.opts.params,\n\t\t\t\tcreateInRegion: actor.opts.createInRegion,\n\t\t\t\tcreateWithInput: actor.opts.createWithInput,\n\t\t\t},\n\t\t);\n\n\t\tconst connection = handle.connect();\n\n\t\t// Store connection BEFORE registering callbacks to avoid race condition\n\t\t// where status change fires before connection is stored\n\t\tupdateActor(store, key, {\n\t\t\thandle: handle as ActorHandle<Actors[ActorName]>,\n\t\t\tconnection: connection as ActorConn<Actors[ActorName]>,\n\t\t});\n\n\t\t// Subscribe to connection state changes\n\t\tconnection.onStatusChange((status) => {\n\t\t\tstore.setState((prev) => {\n\t\t\t\t// Only update if this is still the active connection\n\t\t\t\tconst isActiveConnection = prev.actors[key]?.connection === connection;\n\t\t\t\tif (!isActiveConnection) return prev;\n\t\t\t\treturn {\n\t\t\t\t\t...prev,\n\t\t\t\t\tactors: {\n\t\t\t\t\t\t...prev.actors,\n\t\t\t\t\t\t[key]: {\n\t\t\t\t\t\t\t...prev.actors[key],\n\t\t\t\t\t\t\tconnStatus: status,\n\t\t\t\t\t\t\t// Only clear error when successfully connected\n\t\t\t\t\t\t\t...(status === \"connected\"\n\t\t\t\t\t\t\t\t? { error: null }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\n\t\t// onError is followed by onClose which will set connStatus to Disconnected\n\t\tconnection.onError((error) => {\n\t\t\tstore.setState((prev) => {\n\t\t\t\t// Only update if this is still the active connection\n\t\t\t\tif (prev.actors[key]?.connection !== connection) return prev;\n\t\t\t\treturn {\n\t\t\t\t\t...prev,\n\t\t\t\t\tactors: {\n\t\t\t\t\t\t...prev.actors,\n\t\t\t\t\t\t[key]: {\n\t\t\t\t\t\t\t...prev.actors[key],\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\t} catch (error) {\n\t\tconsole.error(\"Failed to create actor connection\", error);\n\t\t// Use Disconnected so Effect won't auto-retry\n\t\t// User must re-enable or take action to retry\n\t\tupdateActor(store, key, {\n\t\t\tconnStatus: \"disconnected\",\n\t\t\terror: error as Error,\n\t\t});\n\t}\n}\n\nfunction defaultHashFunction({ name, key, params }: AnyActorOptions) {\n\treturn JSON.stringify({ name, key, params });\n}\n\nfunction optsEqual(a: AnyActorOptions, b: AnyActorOptions) {\n\treturn equal(a, b);\n}\n"]}
package/dist/mod.mjs ADDED
@@ -0,0 +1,235 @@
1
+ // src/mod.ts
2
+ import { Derived, Effect, Store } from "@tanstack/store";
3
+ import equal from "fast-deep-equal";
4
+ import "rivetkit/client";
5
+ function createRivetKit(client, createOpts = {}) {
6
+ const store = new Store({
7
+ actors: {}
8
+ });
9
+ const cache = /* @__PURE__ */ new Map();
10
+ return {
11
+ getOrCreateActor: (actorOpts) => getOrCreateActor(client, createOpts, store, cache, actorOpts),
12
+ store
13
+ };
14
+ }
15
+ function updateActor(store, key, updates) {
16
+ store.setState((prev) => ({
17
+ ...prev,
18
+ actors: {
19
+ ...prev.actors,
20
+ [key]: { ...prev.actors[key], ...updates }
21
+ }
22
+ }));
23
+ }
24
+ function getOrCreateActor(client, createOpts, store, cache, actorOpts) {
25
+ const hash = createOpts.hashFunction || defaultHashFunction;
26
+ const normalizedOpts = {
27
+ ...actorOpts,
28
+ enabled: actorOpts.enabled ?? true
29
+ };
30
+ const key = hash(normalizedOpts);
31
+ const existing = store.state.actors[key];
32
+ if (!existing) {
33
+ store.setState((prev) => ({
34
+ ...prev,
35
+ actors: {
36
+ ...prev.actors,
37
+ [key]: {
38
+ hash: key,
39
+ connStatus: "idle",
40
+ connection: null,
41
+ handle: null,
42
+ error: null,
43
+ opts: normalizedOpts
44
+ }
45
+ }
46
+ }));
47
+ } else if (!optsEqual(existing.opts, normalizedOpts)) {
48
+ queueMicrotask(() => {
49
+ updateActor(store, key, { opts: normalizedOpts });
50
+ });
51
+ }
52
+ const cached = cache.get(key);
53
+ if (cached) {
54
+ return {
55
+ ...cached,
56
+ state: cached.state
57
+ };
58
+ }
59
+ const derived = new Derived({
60
+ fn: ({ currDepVals: [store2] }) => {
61
+ const actor = store2.actors[key];
62
+ return {
63
+ ...actor,
64
+ /** @deprecated Use `connStatus === "connected"` instead */
65
+ isConnected: actor.connStatus === "connected"
66
+ };
67
+ },
68
+ deps: [store]
69
+ });
70
+ const effect = new Effect({
71
+ fn: () => {
72
+ const actor = store.state.actors[key];
73
+ if (!actor) {
74
+ throw new Error(
75
+ `Actor with key "${key}" not found in store. This indicates a bug in cleanup logic.`
76
+ );
77
+ }
78
+ if (!actor.opts.enabled && actor.connection) {
79
+ actor.connection.dispose();
80
+ updateActor(store, key, {
81
+ connection: null,
82
+ handle: null,
83
+ connStatus: "idle"
84
+ });
85
+ return;
86
+ }
87
+ if (actor.connStatus === "idle" && actor.opts.enabled) {
88
+ queueMicrotask(() => {
89
+ const currentActor = store.state.actors[key];
90
+ if (currentActor && currentActor.connStatus === "idle" && currentActor.opts.enabled) {
91
+ create(client, store, key);
92
+ }
93
+ });
94
+ }
95
+ },
96
+ deps: [derived]
97
+ });
98
+ let unsubscribeDerived = null;
99
+ let unsubscribeEffect = null;
100
+ const mount = () => {
101
+ const cached2 = cache.get(key);
102
+ if (!cached2) {
103
+ throw new Error(
104
+ `Actor with key "${key}" not found in cache. This indicates a bug in cleanup logic.`
105
+ );
106
+ }
107
+ if (cached2.cleanupTimeout !== null) {
108
+ clearTimeout(cached2.cleanupTimeout);
109
+ cached2.cleanupTimeout = null;
110
+ }
111
+ cached2.refCount++;
112
+ if (cached2.refCount === 1) {
113
+ unsubscribeDerived = derived.mount();
114
+ unsubscribeEffect = effect.mount();
115
+ const actor = store.state.actors[key];
116
+ if (actor && actor.opts.enabled && actor.connStatus === "idle") {
117
+ create(client, store, key);
118
+ }
119
+ }
120
+ return () => {
121
+ cached2.refCount--;
122
+ if (cached2.refCount === 0) {
123
+ cached2.cleanupTimeout = setTimeout(() => {
124
+ cached2.cleanupTimeout = null;
125
+ if (cached2.refCount > 0) return;
126
+ unsubscribeDerived == null ? void 0 : unsubscribeDerived();
127
+ unsubscribeEffect == null ? void 0 : unsubscribeEffect();
128
+ unsubscribeDerived = null;
129
+ unsubscribeEffect = null;
130
+ const actor = store.state.actors[key];
131
+ if (actor == null ? void 0 : actor.connection) {
132
+ actor.connection.dispose();
133
+ }
134
+ store.setState((prev) => {
135
+ const { [key]: _, ...rest } = prev.actors;
136
+ return { ...prev, actors: rest };
137
+ });
138
+ cache.delete(key);
139
+ }, 0);
140
+ }
141
+ };
142
+ };
143
+ cache.set(key, {
144
+ state: derived,
145
+ key,
146
+ mount,
147
+ create: create.bind(void 0, client, store, key),
148
+ refCount: 0,
149
+ cleanupTimeout: null
150
+ });
151
+ return {
152
+ mount,
153
+ state: derived,
154
+ key
155
+ };
156
+ }
157
+ function create(client, store, key) {
158
+ const actor = store.state.actors[key];
159
+ if (!actor) {
160
+ throw new Error(
161
+ `Actor with key "${key}" not found in store. This indicates a bug in cleanup logic.`
162
+ );
163
+ }
164
+ updateActor(store, key, {
165
+ connStatus: "connecting",
166
+ error: null
167
+ });
168
+ try {
169
+ const handle = client.getOrCreate(
170
+ actor.opts.name,
171
+ actor.opts.key,
172
+ {
173
+ params: actor.opts.params,
174
+ createInRegion: actor.opts.createInRegion,
175
+ createWithInput: actor.opts.createWithInput
176
+ }
177
+ );
178
+ const connection = handle.connect();
179
+ updateActor(store, key, {
180
+ handle,
181
+ connection
182
+ });
183
+ connection.onStatusChange((status) => {
184
+ store.setState((prev) => {
185
+ var _a;
186
+ const isActiveConnection = ((_a = prev.actors[key]) == null ? void 0 : _a.connection) === connection;
187
+ if (!isActiveConnection) return prev;
188
+ return {
189
+ ...prev,
190
+ actors: {
191
+ ...prev.actors,
192
+ [key]: {
193
+ ...prev.actors[key],
194
+ connStatus: status,
195
+ // Only clear error when successfully connected
196
+ ...status === "connected" ? { error: null } : {}
197
+ }
198
+ }
199
+ };
200
+ });
201
+ });
202
+ connection.onError((error) => {
203
+ store.setState((prev) => {
204
+ var _a;
205
+ if (((_a = prev.actors[key]) == null ? void 0 : _a.connection) !== connection) return prev;
206
+ return {
207
+ ...prev,
208
+ actors: {
209
+ ...prev.actors,
210
+ [key]: {
211
+ ...prev.actors[key],
212
+ error
213
+ }
214
+ }
215
+ };
216
+ });
217
+ });
218
+ } catch (error) {
219
+ console.error("Failed to create actor connection", error);
220
+ updateActor(store, key, {
221
+ connStatus: "disconnected",
222
+ error
223
+ });
224
+ }
225
+ }
226
+ function defaultHashFunction({ name, key, params }) {
227
+ return JSON.stringify({ name, key, params });
228
+ }
229
+ function optsEqual(a, b) {
230
+ return equal(a, b);
231
+ }
232
+ export {
233
+ createRivetKit
234
+ };
235
+ //# sourceMappingURL=mod.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mod.ts"],"sourcesContent":["import { Derived, Effect, Store } from \"@tanstack/store\";\nimport equal from \"fast-deep-equal\";\nimport type { AnyActorDefinition, Registry } from \"rivetkit\";\nimport {\n\ttype ActorConn,\n\ttype ActorConnStatus,\n\ttype ActorHandle,\n\ttype Client,\n\ttype ExtractActorsFromRegistry,\n} from \"rivetkit/client\";\n\nexport type AnyActorRegistry = Registry<any>;\n\nexport type { ActorConnStatus };\n\ninterface ActorStateReference<AD extends AnyActorDefinition> {\n\t/**\n\t * The unique identifier for the actor.\n\t * This is a hash generated from the actor's options.\n\t * It is used to identify the actor instance in the store.\n\t * @internal\n\t */\n\thash: string;\n\t/**\n\t * The state of the actor, derived from the store.\n\t * This includes the actor's connection and handle.\n\t */\n\thandle: ActorHandle<AD> | null;\n\t/**\n\t * The connection to the actor.\n\t * This is used to communicate with the actor in realtime.\n\t */\n\tconnection: ActorConn<AD> | null;\n\t/**\n\t * The connection status of the actor.\n\t */\n\tconnStatus: ActorConnStatus;\n\t/**\n\t * The error that occurred while trying to connect to the actor, if any.\n\t */\n\terror: Error | null;\n\t/**\n\t * Options for the actor, including its name, key, parameters, and whether it is enabled.\n\t */\n\topts: {\n\t\tname: keyof AD;\n\t\t/**\n\t\t * Unique key for the actor instance.\n\t\t * This can be a string or an array of strings to create multiple instances.\n\t\t * @example \"abc\" or [\"abc\", \"def\"]\n\t\t */\n\t\tkey: string | string[];\n\t\t/**\n\t\t * Parameters for the actor.\n\t\t * These are additional options that can be passed to the actor.\n\t\t */\n\t\tparams?: Record<string, string>;\n\t\t/** Region to create the actor in if it doesn't exist. */\n\t\tcreateInRegion?: string;\n\t\t/** Input data to pass to the actor. */\n\t\tcreateWithInput?: unknown;\n\t\t/**\n\t\t * Whether the actor is enabled.\n\t\t * Defaults to true.\n\t\t */\n\t\tenabled?: boolean;\n\t};\n}\n\ninterface InternalRivetKitStore<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> {\n\tactors: Record<string, ActorStateReference<Actors>>;\n}\n\n/**\n * Options for configuring a actor in RivetKit.\n */\nexport interface ActorOptions<\n\tRegistry extends AnyActorRegistry,\n\tActorName extends keyof ExtractActorsFromRegistry<Registry>,\n> {\n\t/**\n\t * Typesafe name of the actor.\n\t * This should match the actor's name in the app's actor definitions.\n\t * @example \"chatRoom\"\n\t */\n\tname: ActorName;\n\t/**\n\t * Unique key for the actor instance.\n\t * This can be a string or an array of strings to create multiple instances.\n\t * @example \"abc\" or [\"abc\", \"def\"]\n\t */\n\tkey: string | string[];\n\t/**\n\t * Parameters for the actor.\n\t */\n\tparams?: Registry[ExtractActorsFromRegistry<Registry>][\"params\"];\n\t/** Region to create the actor in if it doesn't exist. */\n\tcreateInRegion?: string;\n\t/** Input data to pass to the actor. */\n\tcreateWithInput?: unknown;\n\t/**\n\t * Whether the actor is enabled.\n\t * Defaults to true.\n\t */\n\tenabled?: boolean;\n}\n\nexport type ActorsStateDerived<\n\tRegistry extends AnyActorRegistry,\n\tWorkerName extends keyof ExtractActorsFromRegistry<Registry>,\n> = Derived<\n\tOmit<\n\t\tInternalRivetKitStore<\n\t\t\tRegistry,\n\t\t\tExtractActorsFromRegistry<Registry>\n\t\t>[\"actors\"][string],\n\t\t\"handle\" | \"connection\"\n\t> & {\n\t\thandle: ActorHandle<\n\t\t\tExtractActorsFromRegistry<Registry>[WorkerName]\n\t\t> | null;\n\t\tconnection: ActorConn<\n\t\t\tExtractActorsFromRegistry<Registry>[WorkerName]\n\t\t> | null;\n\t\t/** @deprecated Use `connStatus === \"connected\"` instead */\n\t\tisConnected: boolean;\n\t}\n>;\n\nexport type AnyActorOptions = ActorOptions<AnyActorRegistry, any>;\n\nexport interface CreateRivetKitOptions<Registry extends AnyActorRegistry> {\n\thashFunction?: (opts: ActorOptions<Registry, any>) => string;\n}\n\ntype ComputedActorState<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> = InternalRivetKitStore<Registry, Actors>[\"actors\"][string] & {\n\t/** @deprecated Use `connStatus === \"connected\"` instead */\n\tisConnected: boolean;\n};\n\ntype ActorCache<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> = Map<\n\tstring,\n\t{\n\t\tstate: Derived<ComputedActorState<Registry, Actors>>;\n\t\tkey: string;\n\t\tmount: () => () => void;\n\t\tcreate: () => void;\n\t\trefCount: number;\n\t\tcleanupTimeout: ReturnType<typeof setTimeout> | null;\n\t}\n>;\n\nexport function createRivetKit<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n>(client: Client<Registry>, createOpts: CreateRivetKitOptions<Registry> = {}) {\n\tconst store = new Store<InternalRivetKitStore<Registry, Actors>>({\n\t\tactors: {},\n\t});\n\n\tconst cache: ActorCache<Registry, Actors> = new Map();\n\n\treturn {\n\t\tgetOrCreateActor: <ActorName extends keyof Actors>(\n\t\t\tactorOpts: ActorOptions<Registry, ActorName>,\n\t\t) => getOrCreateActor(client, createOpts, store, cache, actorOpts),\n\t\tstore,\n\t};\n}\n\ntype ActorUpdates<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n> = Partial<InternalRivetKitStore<Registry, Actors>[\"actors\"][string]>;\n\nfunction updateActor<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n>(\n\tstore: Store<InternalRivetKitStore<Registry, Actors>>,\n\tkey: string,\n\tupdates: ActorUpdates<Registry, Actors>,\n) {\n\tstore.setState((prev) => ({\n\t\t...prev,\n\t\tactors: {\n\t\t\t...prev.actors,\n\t\t\t[key]: { ...prev.actors[key], ...updates },\n\t\t},\n\t}));\n}\n\n// See README.md for lifecycle documentation.\nfunction getOrCreateActor<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n\tActorName extends keyof Actors,\n>(\n\tclient: Client<Registry>,\n\tcreateOpts: CreateRivetKitOptions<Registry>,\n\tstore: Store<InternalRivetKitStore<Registry, Actors>>,\n\tcache: ActorCache<Registry, Actors>,\n\tactorOpts: ActorOptions<Registry, ActorName>,\n) {\n\tconst hash = createOpts.hashFunction || defaultHashFunction;\n\n\tconst normalizedOpts = {\n\t\t...actorOpts,\n\t\tenabled: actorOpts.enabled ?? true,\n\t};\n\n\tconst key = hash(normalizedOpts);\n\n\t// Sync opts to store on every call (even for cached entries)\n\t// Use queueMicrotask for updates to avoid \"Cannot update a component while rendering\" React error\n\tconst existing = store.state.actors[key];\n\tif (!existing) {\n\t\tstore.setState((prev) => ({\n\t\t\t...prev,\n\t\t\tactors: {\n\t\t\t\t...prev.actors,\n\t\t\t\t[key]: {\n\t\t\t\t\thash: key,\n\t\t\t\t\tconnStatus: \"idle\",\n\t\t\t\t\tconnection: null,\n\t\t\t\t\thandle: null,\n\t\t\t\t\terror: null,\n\t\t\t\t\topts: normalizedOpts,\n\t\t\t\t},\n\t\t\t},\n\t\t}));\n\t} else if (!optsEqual(existing.opts, normalizedOpts)) {\n\t\t// Defer opts update to avoid triggering re-render during render\n\t\tqueueMicrotask(() => {\n\t\t\tupdateActor(store, key, { opts: normalizedOpts });\n\t\t});\n\t}\n\n\tconst cached = cache.get(key);\n\tif (cached) {\n\t\treturn {\n\t\t\t...cached,\n\t\t\tstate: cached.state as ActorsStateDerived<Registry, ActorName>,\n\t\t};\n\t}\n\n\tconst derived = new Derived({\n\t\tfn: ({ currDepVals: [store] }) => {\n\t\t\tconst actor = store.actors[key];\n\t\t\treturn {\n\t\t\t\t...actor,\n\t\t\t\t/** @deprecated Use `connStatus === \"connected\"` instead */\n\t\t\t\tisConnected: actor.connStatus === \"connected\",\n\t\t\t};\n\t\t},\n\t\tdeps: [store],\n\t});\n\n\t// Handle enabled/disabled state changes.\n\t// Initial connection is triggered directly in mount() since Effect\n\t// only runs on state changes, not on mount.\n\tconst effect = new Effect({\n\t\tfn: () => {\n\t\t\tconst actor = store.state.actors[key];\n\t\t\tif (!actor) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Actor with key \"${key}\" not found in store. This indicates a bug in cleanup logic.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Dispose connection if disabled\n\t\t\tif (!actor.opts.enabled && actor.connection) {\n\t\t\t\tactor.connection.dispose();\n\n\t\t\t\t// Reset state so re-enabling will reconnect\n\t\t\t\tupdateActor(store, key, {\n\t\t\t\t\tconnection: null,\n\t\t\t\t\thandle: null,\n\t\t\t\t\tconnStatus: \"idle\",\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Reconnect when re-enabled after being disabled\n\t\t\t// Defer to avoid \"Cannot update a component while rendering\" React error\n\t\t\tif (\n\t\t\t\tactor.connStatus === \"idle\" &&\n\t\t\t\tactor.opts.enabled\n\t\t\t) {\n\t\t\t\tqueueMicrotask(() => {\n\t\t\t\t\t// Re-check state after microtask in case it changed\n\t\t\t\t\tconst currentActor = store.state.actors[key];\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrentActor &&\n\t\t\t\t\t\tcurrentActor.connStatus === \"idle\" &&\n\t\t\t\t\t\tcurrentActor.opts.enabled\n\t\t\t\t\t) {\n\t\t\t\t\t\tcreate<Registry, Actors, ActorName>(client, store, key);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tdeps: [derived],\n\t});\n\n\t// Track subscriptions for ref counting\n\tlet unsubscribeDerived: (() => void) | null = null;\n\tlet unsubscribeEffect: (() => void) | null = null;\n\n\tconst mount = () => {\n\t\tconst cached = cache.get(key);\n\t\tif (!cached) {\n\t\t\tthrow new Error(\n\t\t\t\t`Actor with key \"${key}\" not found in cache. This indicates a bug in cleanup logic.`,\n\t\t\t);\n\t\t}\n\n\t\t// Cancel pending cleanup\n\t\tif (cached.cleanupTimeout !== null) {\n\t\t\tclearTimeout(cached.cleanupTimeout);\n\t\t\tcached.cleanupTimeout = null;\n\t\t}\n\n\t\t// Increment ref count\n\t\tcached.refCount++;\n\n\t\t// Mount derived/effect on first reference (or re-mount after cleanup)\n\t\tif (cached.refCount === 1) {\n\t\t\tunsubscribeDerived = derived.mount();\n\t\t\tunsubscribeEffect = effect.mount();\n\n\t\t\t// Effect doesn't run immediately on mount, only on state changes.\n\t\t\t// Trigger initial connection if actor is enabled and idle.\n\t\t\tconst actor = store.state.actors[key];\n\t\t\tif (\n\t\t\t\tactor &&\n\t\t\t\tactor.opts.enabled &&\n\t\t\t\tactor.connStatus === \"idle\"\n\t\t\t) {\n\t\t\t\tcreate<Registry, Actors, ActorName>(client, store, key);\n\t\t\t}\n\t\t}\n\n\t\treturn () => {\n\t\t\t// Decrement ref count\n\t\t\tcached.refCount--;\n\n\t\t\tif (cached.refCount === 0) {\n\t\t\t\t// Deferred cleanup prevents needless reconnection when:\n\t\t\t\t// - React Strict Mode's unmount/remount cycle\n\t\t\t\t// - useActor hook moves between components in the same render cycle\n\t\t\t\tcached.cleanupTimeout = setTimeout(() => {\n\t\t\t\t\tcached.cleanupTimeout = null;\n\t\t\t\t\tif (cached.refCount > 0) return;\n\n\t\t\t\t\t// Unsubscribe from derived/effect\n\t\t\t\t\tunsubscribeDerived?.();\n\t\t\t\t\tunsubscribeEffect?.();\n\t\t\t\t\tunsubscribeDerived = null;\n\t\t\t\t\tunsubscribeEffect = null;\n\n\t\t\t\t\t// Dispose connection\n\t\t\t\t\tconst actor = store.state.actors[key];\n\t\t\t\t\tif (actor?.connection) {\n\t\t\t\t\t\tactor.connection.dispose();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove from store and cache\n\t\t\t\t\tstore.setState((prev) => {\n\t\t\t\t\t\tconst { [key]: _, ...rest } = prev.actors;\n\t\t\t\t\t\treturn { ...prev, actors: rest };\n\t\t\t\t\t});\n\t\t\t\t\tcache.delete(key);\n\t\t\t\t}, 0);\n\t\t\t}\n\t\t};\n\t};\n\n\tcache.set(key, {\n\t\tstate: derived,\n\t\tkey,\n\t\tmount,\n\t\tcreate: create.bind(undefined, client, store, key),\n\t\trefCount: 0,\n\t\tcleanupTimeout: null,\n\t});\n\n\treturn {\n\t\tmount,\n\t\tstate: derived as ActorsStateDerived<Registry, ActorName>,\n\t\tkey,\n\t};\n}\n\nfunction create<\n\tRegistry extends AnyActorRegistry,\n\tActors extends ExtractActorsFromRegistry<Registry>,\n\tActorName extends keyof Actors,\n>(\n\tclient: Client<Registry>,\n\tstore: Store<InternalRivetKitStore<Registry, Actors>>,\n\tkey: string,\n) {\n\tconst actor = store.state.actors[key];\n\tif (!actor) {\n\t\tthrow new Error(\n\t\t\t`Actor with key \"${key}\" not found in store. This indicates a bug in cleanup logic.`,\n\t\t);\n\t}\n\n\t// Save actor to map\n\tupdateActor(store, key, {\n\t\tconnStatus: \"connecting\",\n\t\terror: null,\n\t});\n\n\ttry {\n\t\tconst handle = client.getOrCreate(\n\t\t\tactor.opts.name as string,\n\t\t\tactor.opts.key,\n\t\t\t{\n\t\t\t\tparams: actor.opts.params,\n\t\t\t\tcreateInRegion: actor.opts.createInRegion,\n\t\t\t\tcreateWithInput: actor.opts.createWithInput,\n\t\t\t},\n\t\t);\n\n\t\tconst connection = handle.connect();\n\n\t\t// Store connection BEFORE registering callbacks to avoid race condition\n\t\t// where status change fires before connection is stored\n\t\tupdateActor(store, key, {\n\t\t\thandle: handle as ActorHandle<Actors[ActorName]>,\n\t\t\tconnection: connection as ActorConn<Actors[ActorName]>,\n\t\t});\n\n\t\t// Subscribe to connection state changes\n\t\tconnection.onStatusChange((status) => {\n\t\t\tstore.setState((prev) => {\n\t\t\t\t// Only update if this is still the active connection\n\t\t\t\tconst isActiveConnection = prev.actors[key]?.connection === connection;\n\t\t\t\tif (!isActiveConnection) return prev;\n\t\t\t\treturn {\n\t\t\t\t\t...prev,\n\t\t\t\t\tactors: {\n\t\t\t\t\t\t...prev.actors,\n\t\t\t\t\t\t[key]: {\n\t\t\t\t\t\t\t...prev.actors[key],\n\t\t\t\t\t\t\tconnStatus: status,\n\t\t\t\t\t\t\t// Only clear error when successfully connected\n\t\t\t\t\t\t\t...(status === \"connected\"\n\t\t\t\t\t\t\t\t? { error: null }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\n\t\t// onError is followed by onClose which will set connStatus to Disconnected\n\t\tconnection.onError((error) => {\n\t\t\tstore.setState((prev) => {\n\t\t\t\t// Only update if this is still the active connection\n\t\t\t\tif (prev.actors[key]?.connection !== connection) return prev;\n\t\t\t\treturn {\n\t\t\t\t\t...prev,\n\t\t\t\t\tactors: {\n\t\t\t\t\t\t...prev.actors,\n\t\t\t\t\t\t[key]: {\n\t\t\t\t\t\t\t...prev.actors[key],\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\t} catch (error) {\n\t\tconsole.error(\"Failed to create actor connection\", error);\n\t\t// Use Disconnected so Effect won't auto-retry\n\t\t// User must re-enable or take action to retry\n\t\tupdateActor(store, key, {\n\t\t\tconnStatus: \"disconnected\",\n\t\t\terror: error as Error,\n\t\t});\n\t}\n}\n\nfunction defaultHashFunction({ name, key, params }: AnyActorOptions) {\n\treturn JSON.stringify({ name, key, params });\n}\n\nfunction optsEqual(a: AnyActorOptions, b: AnyActorOptions) {\n\treturn equal(a, b);\n}\n"],"mappings":"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","names":["store","cached"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivetkit/framework-base",
3
- "version": "2.0.29",
3
+ "version": "2.0.31",
4
4
  "description": "Base framework utilities for RivetKit client integrations",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -10,8 +10,10 @@
10
10
  "utilities",
11
11
  "integration"
12
12
  ],
13
- "sideEffects": false,
14
- "type": "module",
13
+ "sideEffects": [
14
+ "./dist/chunk-*.js",
15
+ "./dist/chunk-*.cjs"
16
+ ],
15
17
  "files": [
16
18
  "dist",
17
19
  "package.json"
@@ -19,29 +21,27 @@
19
21
  "exports": {
20
22
  ".": {
21
23
  "import": {
22
- "types": "./dist/mod.d.ts",
23
- "default": "./dist/mod.js"
24
+ "types": "./dist/mod.d.mts",
25
+ "default": "./dist/mod.mjs"
24
26
  },
25
27
  "require": {
26
- "types": "./dist/mod.d.cts",
27
- "default": "./dist/mod.cjs"
28
+ "types": "./dist/mod.d.ts",
29
+ "default": "./dist/mod.js"
28
30
  }
29
31
  }
30
32
  },
31
33
  "devDependencies": {
32
- "typescript": "^5.5.2",
33
- "vite": "^6.3.5",
34
- "vite-plugin-dts": "^4.5.4",
35
- "vitest": "^3.1.1"
34
+ "tsup": "^8.4.0",
35
+ "typescript": "^5.5.2"
36
36
  },
37
37
  "stableVersion": "0.8.0",
38
38
  "dependencies": {
39
39
  "@tanstack/store": "^0.7.1",
40
- "rivetkit": "2.0.29"
40
+ "fast-deep-equal": "^3.1.3",
41
+ "rivetkit": "2.0.31"
41
42
  },
42
43
  "scripts": {
43
- "dev": "vite build --watch",
44
- "build": "tsc && vite build",
44
+ "build": "tsup src/mod.ts",
45
45
  "check-types": "tsc --noEmit"
46
46
  }
47
47
  }
package/dist/mod.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=new WeakMap,_=new WeakMap,V={current:[]};let m=!1;const v=new Set,k=new Map;function O(i){const n=Array.from(i).sort((t,e)=>t instanceof h&&t.options.deps.includes(e)?1:e instanceof h&&e.options.deps.includes(t)?-1:0);for(const t of n){if(V.current.includes(t))continue;V.current.push(t),t.recompute();const e=_.get(t);if(e)for(const s of e){const r=p.get(s);r&&O(r)}}}function F(i){i.listeners.forEach(n=>n({prevVal:i.prevState,currentVal:i.state}))}function R(i){i.listeners.forEach(n=>n({prevVal:i.prevState,currentVal:i.state}))}function G(i){if(v.add(i),!m)try{for(m=!0;v.size>0;){const n=Array.from(v);v.clear();for(const t of n){const e=k.get(t)??t.prevState;t.prevState=e,F(t)}for(const t of n){const e=p.get(t);e&&(V.current.push(t),O(e))}for(const t of n){const e=p.get(t);if(e)for(const s of e)R(s)}}}finally{m=!1,V.current=[],k.clear()}}function I(i){return typeof i=="function"}class y{constructor(n,t){this.listeners=new Set,this.subscribe=e=>{var s,r;this.listeners.add(e);const d=(r=(s=this.options)==null?void 0:s.onSubscribe)==null?void 0:r.call(s,e,this);return()=>{this.listeners.delete(e),d==null||d()}},this.prevState=n,this.state=n,this.options=t}setState(n){var t,e,s;this.prevState=this.state,(t=this.options)!=null&&t.updateFn?this.state=this.options.updateFn(this.prevState)(n):I(n)?this.state=n(this.prevState):this.state=n,(s=(e=this.options)==null?void 0:e.onUpdate)==null||s.call(e),G(this)}}class h{constructor(n){this.listeners=new Set,this._subscriptions=[],this.lastSeenDepValues=[],this.getDepVals=()=>{const t=[],e=[];for(const s of this.options.deps)t.push(s.prevState),e.push(s.state);return this.lastSeenDepValues=e,{prevDepVals:t,currDepVals:e,prevVal:this.prevState??void 0}},this.recompute=()=>{var t,e;this.prevState=this.state;const{prevDepVals:s,currDepVals:r,prevVal:d}=this.getDepVals();this.state=this.options.fn({prevDepVals:s,currDepVals:r,prevVal:d}),(e=(t=this.options).onUpdate)==null||e.call(t)},this.checkIfRecalculationNeededDeeply=()=>{for(const r of this.options.deps)r instanceof h&&r.checkIfRecalculationNeededDeeply();let t=!1;const e=this.lastSeenDepValues,{currDepVals:s}=this.getDepVals();for(let r=0;r<s.length;r++)if(s[r]!==e[r]){t=!0;break}t&&this.recompute()},this.mount=()=>(this.registerOnGraph(),this.checkIfRecalculationNeededDeeply(),()=>{this.unregisterFromGraph();for(const t of this._subscriptions)t()}),this.subscribe=t=>{var e,s;this.listeners.add(t);const r=(s=(e=this.options).onSubscribe)==null?void 0:s.call(e,t,this);return()=>{this.listeners.delete(t),r==null||r()}},this.options=n,this.state=n.fn({prevDepVals:void 0,prevVal:void 0,currDepVals:this.getDepVals().currDepVals})}registerOnGraph(n=this.options.deps){for(const t of n)if(t instanceof h)t.registerOnGraph(),this.registerOnGraph(t.options.deps);else if(t instanceof y){let e=p.get(t);e||(e=new Set,p.set(t,e)),e.add(this);let s=_.get(this);s||(s=new Set,_.set(this,s)),s.add(t)}}unregisterFromGraph(n=this.options.deps){for(const t of n)if(t instanceof h)this.unregisterFromGraph(t.options.deps);else if(t instanceof y){const e=p.get(t);e&&e.delete(this);const s=_.get(this);s&&s.delete(t)}}}class N{constructor(n){const{eager:t,fn:e,...s}=n;this._derived=new h({...s,fn:()=>{},onUpdate(){e()}}),t&&e()}mount(){return this._derived.mount()}}function T(i,n={}){const t=new y({actors:{}}),e=n.hashFunction||A,s=new Map;function r(d){const o=e(d),D=s.get(o);if(D)return{...D,state:D.state};const g=new h({fn:({currDepVals:[a]})=>a.actors[o],deps:[t]});function b(){async function a(){const c=t.state.actors[o];try{const f=i.getOrCreate(c.opts.name,c.opts.key,{params:c.opts.params,createInRegion:c.opts.createInRegion,createWithInput:c.opts.createWithInput}),u=f.connect();u.onOpen(()=>{t.setState(l=>{var S;return((S=l.actors[o])==null?void 0:S.connection)!==u?l:{...l,actors:{...l.actors,[o]:{...l.actors[o],isConnected:!0}}}})}),u.onClose(()=>{t.setState(l=>{var S;return((S=l.actors[o])==null?void 0:S.connection)!==u?l:{...l,actors:{...l.actors,[o]:{...l.actors[o],isConnected:!1}}}})}),await f.resolve(),t.setState(l=>({...l,actors:{...l.actors,[o]:{...l.actors[o],isConnected:u.isConnected,isConnecting:!1,handle:f,connection:u,isError:!1,error:null}}}))}catch(f){t.setState(u=>({...u,actors:{...u.actors,[o]:{...u.actors[o],isError:!0,isConnecting:!1,error:f}}}))}}t.setState(c=>(c.actors[o].isConnecting=!0,c.actors[o].isError=!1,c.actors[o].error=null,a(),c))}const E=new N({fn:()=>{const a=t.state.actors[o];JSON.stringify(t.prevState.actors[o].opts)===JSON.stringify(t.state.actors[o].opts)&&!a.isConnected&&!a.isConnecting&&!a.isError&&a.opts.enabled&&b()},deps:[g]});t.setState(a=>a.actors[o]?a:{...a,actors:{...a.actors,[o]:{hash:o,isConnected:!1,isConnecting:!1,connection:null,handle:null,isError:!1,error:null,opts:d}}});function w(a){t.setState(c=>{const f=c.actors[o];if(!f)throw new Error(`Actor with key "${o}" does not exist.`);let u;return typeof a=="function"?u=a(f):u=a,{...c,actors:{...c.actors,[o]:u}}})}const C=()=>{const a=g.mount(),c=E.mount();return()=>{a(),c()}};return s.set(o,{state:g,key:o,mount:C,setState:w,create:b}),{mount:C,setState:w,state:g,create:b,key:o}}return{getOrCreateActor:r,store:t}}function A({name:i,key:n,params:t}){return JSON.stringify({name:i,key:n,params:t})}exports.createRivetKit=T;