@rivetkit/framework-base
Version:
Base framework utilities for RivetKit client integrations
235 lines (233 loc) • 6.85 kB
JavaScript
;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
var _store = require('@tanstack/store');
var _fastdeepequal = require('fast-deep-equal'); var _fastdeepequal2 = _interopRequireDefault(_fastdeepequal);
require('rivetkit/client');
function createRivetKit(client, createOpts = {}) {
const store = new (0, _store.Store)({
actors: {}
});
const cache = /* @__PURE__ */ new Map();
return {
getOrCreateActor: (actorOpts) => getOrCreateActor(client, createOpts, store, cache, actorOpts),
store
};
}
function updateActor(store, key, updates) {
store.setState((prev) => ({
...prev,
actors: {
...prev.actors,
[key]: { ...prev.actors[key], ...updates }
}
}));
}
function getOrCreateActor(client, createOpts, store, cache, actorOpts) {
const hash = createOpts.hashFunction || defaultHashFunction;
const normalizedOpts = {
...actorOpts,
enabled: _nullishCoalesce(actorOpts.enabled, () => ( true))
};
const key = hash(normalizedOpts);
const existing = store.state.actors[key];
if (!existing) {
store.setState((prev) => ({
...prev,
actors: {
...prev.actors,
[key]: {
hash: key,
connStatus: "idle",
connection: null,
handle: null,
error: null,
opts: normalizedOpts
}
}
}));
} else if (!optsEqual(existing.opts, normalizedOpts)) {
queueMicrotask(() => {
updateActor(store, key, { opts: normalizedOpts });
});
}
const cached = cache.get(key);
if (cached) {
return {
...cached,
state: cached.state
};
}
const derived = new (0, _store.Derived)({
fn: ({ currDepVals: [store2] }) => {
const actor = store2.actors[key];
return {
...actor,
/** @deprecated Use `connStatus === "connected"` instead */
isConnected: actor.connStatus === "connected"
};
},
deps: [store]
});
const effect = new (0, _store.Effect)({
fn: () => {
const actor = store.state.actors[key];
if (!actor) {
throw new Error(
`Actor with key "${key}" not found in store. This indicates a bug in cleanup logic.`
);
}
if (!actor.opts.enabled && actor.connection) {
actor.connection.dispose();
updateActor(store, key, {
connection: null,
handle: null,
connStatus: "idle"
});
return;
}
if (actor.connStatus === "idle" && actor.opts.enabled) {
queueMicrotask(() => {
const currentActor = store.state.actors[key];
if (currentActor && currentActor.connStatus === "idle" && currentActor.opts.enabled) {
create(client, store, key);
}
});
}
},
deps: [derived]
});
let unsubscribeDerived = null;
let unsubscribeEffect = null;
const mount = () => {
const cached2 = cache.get(key);
if (!cached2) {
throw new Error(
`Actor with key "${key}" not found in cache. This indicates a bug in cleanup logic.`
);
}
if (cached2.cleanupTimeout !== null) {
clearTimeout(cached2.cleanupTimeout);
cached2.cleanupTimeout = null;
}
cached2.refCount++;
if (cached2.refCount === 1) {
unsubscribeDerived = derived.mount();
unsubscribeEffect = effect.mount();
const actor = store.state.actors[key];
if (actor && actor.opts.enabled && actor.connStatus === "idle") {
create(client, store, key);
}
}
return () => {
cached2.refCount--;
if (cached2.refCount === 0) {
cached2.cleanupTimeout = setTimeout(() => {
cached2.cleanupTimeout = null;
if (cached2.refCount > 0) return;
unsubscribeDerived == null ? void 0 : unsubscribeDerived();
unsubscribeEffect == null ? void 0 : unsubscribeEffect();
unsubscribeDerived = null;
unsubscribeEffect = null;
const actor = store.state.actors[key];
if (actor == null ? void 0 : actor.connection) {
actor.connection.dispose();
}
store.setState((prev) => {
const { [key]: _, ...rest } = prev.actors;
return { ...prev, actors: rest };
});
cache.delete(key);
}, 0);
}
};
};
cache.set(key, {
state: derived,
key,
mount,
create: create.bind(void 0, client, store, key),
refCount: 0,
cleanupTimeout: null
});
return {
mount,
state: derived,
key
};
}
function create(client, store, key) {
const actor = store.state.actors[key];
if (!actor) {
throw new Error(
`Actor with key "${key}" not found in store. This indicates a bug in cleanup logic.`
);
}
updateActor(store, key, {
connStatus: "connecting",
error: null
});
try {
const handle = client.getOrCreate(
actor.opts.name,
actor.opts.key,
{
params: actor.opts.params,
createInRegion: actor.opts.createInRegion,
createWithInput: actor.opts.createWithInput
}
);
const connection = handle.connect();
updateActor(store, key, {
handle,
connection
});
connection.onStatusChange((status) => {
store.setState((prev) => {
var _a;
const isActiveConnection = ((_a = prev.actors[key]) == null ? void 0 : _a.connection) === connection;
if (!isActiveConnection) return prev;
return {
...prev,
actors: {
...prev.actors,
[key]: {
...prev.actors[key],
connStatus: status,
// Only clear error when successfully connected
...status === "connected" ? { error: null } : {}
}
}
};
});
});
connection.onError((error) => {
store.setState((prev) => {
var _a;
if (((_a = prev.actors[key]) == null ? void 0 : _a.connection) !== connection) return prev;
return {
...prev,
actors: {
...prev.actors,
[key]: {
...prev.actors[key],
error
}
}
};
});
});
} catch (error) {
console.error("Failed to create actor connection", error);
updateActor(store, key, {
connStatus: "disconnected",
error
});
}
}
function defaultHashFunction({ name, key, params }) {
return JSON.stringify({ name, key, params });
}
function optsEqual(a, b) {
return _fastdeepequal2.default.call(void 0, a, b);
}
exports.createRivetKit = createRivetKit;
//# sourceMappingURL=mod.js.map