@iadev93/zuno 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +7 -11
- package/dist/index-IbvF6TBr.d.cts +151 -0
- package/dist/index-IbvF6TBr.d.ts +151 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/{shared/readable.d.ts → index.d.cts} +7 -4
- package/dist/index.d.ts +24 -10
- package/dist/index.js +2 -6
- package/dist/index.js.map +1 -0
- package/dist/server/index.cjs +17 -0
- package/dist/server/index.cjs.map +1 -0
- package/dist/server/index.d.cts +57 -0
- package/dist/server/index.d.ts +57 -4
- package/dist/server/index.js +17 -3
- package/dist/server/index.js.map +1 -0
- package/package.json +9 -5
- package/dist/core/createZuno.d.ts +0 -77
- package/dist/core/createZuno.d.ts.map +0 -1
- package/dist/core/createZuno.js +0 -250
- package/dist/core/store.d.ts +0 -10
- package/dist/core/store.d.ts.map +0 -1
- package/dist/core/store.js +0 -27
- package/dist/core/types.d.ts +0 -107
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js +0 -1
- package/dist/core/universe.d.ts +0 -12
- package/dist/core/universe.d.ts.map +0 -1
- package/dist/core/universe.js +0 -53
- package/dist/index.d.ts.map +0 -1
- package/dist/server/apply-state-event.d.ts +0 -26
- package/dist/server/apply-state-event.d.ts.map +0 -1
- package/dist/server/apply-state-event.js +0 -29
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/server-transport.d.ts +0 -8
- package/dist/server/server-transport.d.ts.map +0 -1
- package/dist/server/server-transport.js +0 -25
- package/dist/server/snapshot-handler.d.ts +0 -9
- package/dist/server/snapshot-handler.d.ts.map +0 -1
- package/dist/server/snapshot-handler.js +0 -18
- package/dist/server/sse-handler.d.ts +0 -24
- package/dist/server/sse-handler.d.ts.map +0 -1
- package/dist/server/sse-handler.js +0 -127
- package/dist/server/state.bus.d.ts +0 -18
- package/dist/server/state.bus.d.ts.map +0 -1
- package/dist/server/state.bus.js +0 -26
- package/dist/server/state.log.d.ts +0 -22
- package/dist/server/state.log.d.ts.map +0 -1
- package/dist/server/state.log.js +0 -37
- package/dist/server/types.d.ts +0 -8
- package/dist/server/types.d.ts.map +0 -1
- package/dist/server/types.js +0 -1
- package/dist/server/universe-store.d.ts +0 -29
- package/dist/server/universe-store.d.ts.map +0 -1
- package/dist/server/universe-store.js +0 -26
- package/dist/shared/readable.d.ts.map +0 -1
- package/dist/shared/readable.js +0 -7
- package/dist/sync/apply-incoming-event.d.ts +0 -10
- package/dist/sync/apply-incoming-event.d.ts.map +0 -1
- package/dist/sync/apply-incoming-event.js +0 -28
- package/dist/sync/broadcast-channel.d.ts +0 -12
- package/dist/sync/broadcast-channel.d.ts.map +0 -1
- package/dist/sync/broadcast-channel.js +0 -73
- package/dist/sync/sse-client.d.ts +0 -21
- package/dist/sync/sse-client.d.ts.map +0 -1
- package/dist/sync/sse-client.js +0 -162
- package/dist/sync/sync-types.d.ts +0 -164
- package/dist/sync/sync-types.d.ts.map +0 -1
- package/dist/sync/sync-types.js +0 -1
- package/dist/sync/transport.d.ts +0 -10
- package/dist/sync/transport.d.ts.map +0 -1
- package/dist/sync/transport.js +0 -26
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const universeState = new Map();
|
|
2
|
-
/**
|
|
3
|
-
* Retrieves the current state of a specific store in the universe.
|
|
4
|
-
* @param storeKey The key of the store to retrieve.
|
|
5
|
-
* @returns The current state of the store, or undefined if the store does not exist.
|
|
6
|
-
*/
|
|
7
|
-
export const getUniverseRecord = (storeKey) => {
|
|
8
|
-
return universeState.get(storeKey);
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Updates the state of a specific store in the universe.
|
|
12
|
-
* @param event The ZunoStateEvent containing the storeKey and the new state to set.
|
|
13
|
-
*/
|
|
14
|
-
export const updateUniverseState = (event) => {
|
|
15
|
-
const current = universeState.get(event.storeKey) ?? { state: undefined, version: 0 };
|
|
16
|
-
// If applyStateEvent already computed event.version, prefer it.
|
|
17
|
-
const nextVersion = typeof event.version === "number" ? event.version : current.version + 1;
|
|
18
|
-
universeState.set(event.storeKey, { state: event.state, version: nextVersion });
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Retrieves the current state of the entire universe.
|
|
22
|
-
* @returns An object containing the state of all stores in the universe.
|
|
23
|
-
*/
|
|
24
|
-
export const getUniverseState = () => {
|
|
25
|
-
return Object.fromEntries(universeState);
|
|
26
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"readable.d.ts","sourceRoot":"","sources":["../../src/shared/readable.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,gCAAgC;IAChC,WAAW,IAAI,CAAC,CAAC;IAEjB;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAE5C,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC;AAEF,8DAA8D;AAC9D,MAAM,MAAM,qBAAqB,CAAC,CAAC,IAAI;IACrC,GAAG,IAAI,CAAC,CAAC;IACT,SAAS,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC/C,CAAC;AAEF,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAK9E"}
|
package/dist/shared/readable.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { IncomingEventContext, Universe } from "../core/types";
|
|
2
|
-
import type { ZunoStateEvent } from "./sync-types";
|
|
3
|
-
/**
|
|
4
|
-
* Applies an incoming event to the Universe in a safe, reusable way.
|
|
5
|
-
* @property universe - The universe to apply the event to.
|
|
6
|
-
* @property event - The event to apply.
|
|
7
|
-
* @property ctx - The context for the event.
|
|
8
|
-
**/
|
|
9
|
-
export declare function applyIncomingEvent(universe: Universe, event: ZunoStateEvent, ctx: IncomingEventContext): void;
|
|
10
|
-
//# sourceMappingURL=apply-incoming-event.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"apply-incoming-event.d.ts","sourceRoot":"","sources":["../../src/sync/apply-incoming-event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;IAKI;AACJ,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,oBAAoB,QA4B1B"}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Applies an incoming event to the Universe in a safe, reusable way.
|
|
3
|
-
* @property universe - The universe to apply the event to.
|
|
4
|
-
* @property event - The event to apply.
|
|
5
|
-
* @property ctx - The context for the event.
|
|
6
|
-
**/
|
|
7
|
-
export function applyIncomingEvent(universe, event, ctx) {
|
|
8
|
-
/** Prevent echo loops (don’t re-apply your own broadcast) */
|
|
9
|
-
if (event.origin && event.origin === ctx.clientId)
|
|
10
|
-
return;
|
|
11
|
-
/** If versioned events exist (SSE/server/BC), ignore older ones */
|
|
12
|
-
if (ctx.versions && typeof event.version === "number") {
|
|
13
|
-
/** Check if the event has been seen */
|
|
14
|
-
const seen = ctx.versions.has(event.storeKey);
|
|
15
|
-
/** Get the current version */
|
|
16
|
-
const currentVersion = ctx.versions.get(event.storeKey) ?? -1;
|
|
17
|
-
/** If the event has been seen and the version is less than or equal to the current version, return */
|
|
18
|
-
if (seen && event.version <= currentVersion)
|
|
19
|
-
return;
|
|
20
|
-
/** Set the version */
|
|
21
|
-
ctx.versions.set(event.storeKey, event.version);
|
|
22
|
-
}
|
|
23
|
-
/** Apply to Universe store */
|
|
24
|
-
const store = universe.getStore(event.storeKey, () => event.state);
|
|
25
|
-
store.set(event.state);
|
|
26
|
-
/** Optional local state cache (for BroadcastChannel snapshot) */
|
|
27
|
-
ctx.localState?.set(event.storeKey, event.state);
|
|
28
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ZunoBCOptions, ZunoStateEvent } from "./sync-types";
|
|
2
|
-
/**
|
|
3
|
-
* Starts a broadcast channel for real-time state updates.
|
|
4
|
-
* @param opts The options for the broadcast channel.
|
|
5
|
-
* @returns An object with a `publish` method for publishing events and a `stop` method for stopping the channel.
|
|
6
|
-
*/
|
|
7
|
-
export declare const startBroadcastChannel: (opts: ZunoBCOptions) => {
|
|
8
|
-
publish: (event: ZunoStateEvent) => void;
|
|
9
|
-
hello: () => void;
|
|
10
|
-
stop: () => void;
|
|
11
|
-
};
|
|
12
|
-
//# sourceMappingURL=broadcast-channel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"broadcast-channel.d.ts","sourceRoot":"","sources":["../../src/sync/broadcast-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGzE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM,aAAa;qBAkE/B,cAAc;;;CAwBvC,CAAC"}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Starts a broadcast channel for real-time state updates.
|
|
3
|
-
* @param opts The options for the broadcast channel.
|
|
4
|
-
* @returns An object with a `publish` method for publishing events and a `stop` method for stopping the channel.
|
|
5
|
-
*/
|
|
6
|
-
export const startBroadcastChannel = (opts) => {
|
|
7
|
-
const bc = new BroadcastChannel(opts.channelName);
|
|
8
|
-
const post = (msg) => bc.postMessage(msg);
|
|
9
|
-
/**
|
|
10
|
-
* Handles incoming messages from the broadcast channel.
|
|
11
|
-
* @param e The message event.
|
|
12
|
-
*/
|
|
13
|
-
bc.onmessage = (e) => {
|
|
14
|
-
/** Message */
|
|
15
|
-
const msg = e.data;
|
|
16
|
-
/** Invalid message */
|
|
17
|
-
if (!msg || typeof msg !== "object")
|
|
18
|
-
return;
|
|
19
|
-
/** Ignore self messages */
|
|
20
|
-
if (msg.origin === opts.clientId)
|
|
21
|
-
return;
|
|
22
|
-
/** Event message */
|
|
23
|
-
if (msg.type === "zuno:event") {
|
|
24
|
-
/** Event */
|
|
25
|
-
const event = msg.event;
|
|
26
|
-
/** Apply event */
|
|
27
|
-
opts.onEvent(event);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
/** Hello message */
|
|
31
|
-
if (msg.type === "zuno:hello") {
|
|
32
|
-
/** Someone joined: respond with snapshot (if available) */
|
|
33
|
-
if (!opts.getSnapshot)
|
|
34
|
-
return;
|
|
35
|
-
/** Snapshot */
|
|
36
|
-
const snapshot = opts.getSnapshot();
|
|
37
|
-
/** Post snapshot */
|
|
38
|
-
post({
|
|
39
|
-
type: "zuno:snapshot",
|
|
40
|
-
origin: opts.clientId,
|
|
41
|
-
target: msg.origin,
|
|
42
|
-
snapshot,
|
|
43
|
-
});
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
/** Snapshot message */
|
|
47
|
-
if (msg.type === "zuno:snapshot") {
|
|
48
|
-
/** Accept only if snapshot is meant for me */
|
|
49
|
-
if (msg.target !== opts.clientId)
|
|
50
|
-
return;
|
|
51
|
-
/** Apply snapshot */
|
|
52
|
-
opts.onSnapshot?.(msg.snapshot);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
/** Publish event */
|
|
57
|
-
const publish = (event) => {
|
|
58
|
-
/** Post event */
|
|
59
|
-
post({
|
|
60
|
-
type: "zuno:event",
|
|
61
|
-
origin: opts.clientId,
|
|
62
|
-
event,
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
/** Hello */
|
|
66
|
-
const hello = () => {
|
|
67
|
-
/** Post hello - to notify others about my presence */
|
|
68
|
-
post({ type: "zuno:hello", origin: opts.clientId });
|
|
69
|
-
};
|
|
70
|
-
/** Stop */
|
|
71
|
-
const stop = () => bc.close();
|
|
72
|
-
return { publish, hello, stop };
|
|
73
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ZunoSSEOptions, ZunoStateEvent } from "./sync-types";
|
|
2
|
-
/**
|
|
3
|
-
* Starts a Server-Sent Events (SSE) connection to synchronize state from a server.
|
|
4
|
-
* It can synchronize either a Zuno universe (collection of stores) or a single Zuno store.
|
|
5
|
-
*
|
|
6
|
-
* @param options - Configuration options for the SSE connection, including the URL,
|
|
7
|
-
* and either a Zuno universe or a specific Zuno store to update.
|
|
8
|
-
*/
|
|
9
|
-
export declare const startSSE: (options: ZunoSSEOptions) => {
|
|
10
|
-
unsubscribe: () => void;
|
|
11
|
-
dispatch: (event: ZunoStateEvent) => Promise<{
|
|
12
|
-
ok: boolean;
|
|
13
|
-
status: number;
|
|
14
|
-
json: unknown;
|
|
15
|
-
} | {
|
|
16
|
-
ok: boolean;
|
|
17
|
-
status: number;
|
|
18
|
-
json: any;
|
|
19
|
-
}>;
|
|
20
|
-
};
|
|
21
|
-
//# sourceMappingURL=sse-client.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sse-client.d.ts","sourceRoot":"","sources":["../../src/sync/sse-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAOnE;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,SAAS,cAAc;;sBA6If,cAAc;;;;;;;;;CAmC9C,CAAC"}
|
package/dist/sync/sse-client.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { createTransport } from "./transport";
|
|
2
|
-
import { applyIncomingEvent } from "./apply-incoming-event";
|
|
3
|
-
/**
|
|
4
|
-
* Starts a Server-Sent Events (SSE) connection to synchronize state from a server.
|
|
5
|
-
* It can synchronize either a Zuno universe (collection of stores) or a single Zuno store.
|
|
6
|
-
*
|
|
7
|
-
* @param options - Configuration options for the SSE connection, including the URL,
|
|
8
|
-
* and either a Zuno universe or a specific Zuno store to update.
|
|
9
|
-
*/
|
|
10
|
-
export const startSSE = (options) => {
|
|
11
|
-
if (!options?.url)
|
|
12
|
-
throw new Error("startSSE: 'url' is required");
|
|
13
|
-
if (!options.universe && !options.store)
|
|
14
|
-
throw new Error("startSSE: provide either 'universe' or 'store'");
|
|
15
|
-
const clientId = options.clientId ?? (crypto?.randomUUID?.() ?? String(Math.random()));
|
|
16
|
-
// const eventSource = new EventSource(options.url);
|
|
17
|
-
const lastEventId = options.getLastEventId?.() ?? 0;
|
|
18
|
-
const url = lastEventId > 0
|
|
19
|
-
? `${options.url}?lastEventId=${encodeURIComponent(String(lastEventId))}`
|
|
20
|
-
: options.url;
|
|
21
|
-
const eventSource = new EventSource(url);
|
|
22
|
-
const transport = createTransport(options.syncUrl);
|
|
23
|
-
/**
|
|
24
|
-
* Applies an incoming state event to the target Zuno universe or store.
|
|
25
|
-
* If a universe is provided, it updates the specific store identified by `storeKey`.
|
|
26
|
-
* If a single store is provided, it updates that store directly.
|
|
27
|
-
* @param eventState - The state event received from the SSE connection, containing `storeKey` and `state`.
|
|
28
|
-
*/
|
|
29
|
-
const applyEventToTarget = (eventState) => {
|
|
30
|
-
if (options.universe) {
|
|
31
|
-
const store = options.universe.getStore(eventState.storeKey, () => eventState.state);
|
|
32
|
-
store.set(eventState.state);
|
|
33
|
-
}
|
|
34
|
-
else if (options.store) {
|
|
35
|
-
options.store.set(eventState.state);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* Tracks the version of each store to handle conflicts.
|
|
40
|
-
*/
|
|
41
|
-
const versions = options.versions;
|
|
42
|
-
/**
|
|
43
|
-
* Applies an incoming snapshot to the target Zuno universe or store.
|
|
44
|
-
* If a universe is provided, it updates all stores in the snapshot.
|
|
45
|
-
* If a single store is provided, it updates that store directly.
|
|
46
|
-
* @param snapshot - The snapshot received from the SSE connection, containing a map of store keys to states.
|
|
47
|
-
*/
|
|
48
|
-
const applySnapshotToTarget = (snapshot) => {
|
|
49
|
-
if (options.universe) {
|
|
50
|
-
const snap = (snapshot ?? {});
|
|
51
|
-
for (const [storeKey, rec] of Object.entries(snap)) {
|
|
52
|
-
versions.set(storeKey, rec?.version ?? 0);
|
|
53
|
-
const store = options.universe.getStore(storeKey, () => rec.state);
|
|
54
|
-
store.set(rec.state);
|
|
55
|
-
}
|
|
56
|
-
options.getSnapshot?.(options.universe);
|
|
57
|
-
}
|
|
58
|
-
else if (options.store) {
|
|
59
|
-
options.store.set(snapshot);
|
|
60
|
-
options.getSnapshot?.(options.store);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Handles incoming snapshot events from the SSE connection.
|
|
65
|
-
* Parses the snapshot data and applies it to the target Zuno universe or store.
|
|
66
|
-
* @param event - The MessageEvent containing the snapshot data.
|
|
67
|
-
*/
|
|
68
|
-
const onSnapshot = (event) => {
|
|
69
|
-
try {
|
|
70
|
-
const snapshotState = JSON.parse(event.data);
|
|
71
|
-
applySnapshotToTarget(snapshotState);
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
console.error("Zuno SSE: failed to parse snapshot payload");
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Handles incoming state events from the SSE connection.
|
|
79
|
-
* Parses the state data and applies it to the target Zuno universe or store.
|
|
80
|
-
* @param event - The MessageEvent containing the state data.
|
|
81
|
-
*/
|
|
82
|
-
const onState = (event) => {
|
|
83
|
-
try {
|
|
84
|
-
const eventState = JSON.parse(event.data);
|
|
85
|
-
/**
|
|
86
|
-
* Apply incoming event to universe or store
|
|
87
|
-
*/
|
|
88
|
-
if (options.universe) {
|
|
89
|
-
applyIncomingEvent(options.universe, eventState, {
|
|
90
|
-
clientId,
|
|
91
|
-
versions,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Apply incoming event to store
|
|
96
|
-
*/
|
|
97
|
-
else if (options.store) {
|
|
98
|
-
// Minimal support for single-store subscriptions.
|
|
99
|
-
if (typeof eventState.version === "number") {
|
|
100
|
-
const currentVersion = versions.get(eventState.storeKey) ?? 0;
|
|
101
|
-
if (eventState.version <= currentVersion)
|
|
102
|
-
return;
|
|
103
|
-
versions.set(eventState.storeKey, eventState.version);
|
|
104
|
-
}
|
|
105
|
-
options.store.set(eventState.state);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
console.error("Zuno SSE: failed to parse state payload");
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
eventSource.addEventListener("snapshot", onSnapshot);
|
|
113
|
-
eventSource.addEventListener("state", onState);
|
|
114
|
-
eventSource.onopen = () => {
|
|
115
|
-
options.onOpen?.();
|
|
116
|
-
};
|
|
117
|
-
eventSource.onerror = () => {
|
|
118
|
-
options.onClose?.();
|
|
119
|
-
};
|
|
120
|
-
/**
|
|
121
|
-
* Unsubscribes from the SSE connection and removes the event listeners.
|
|
122
|
-
*/
|
|
123
|
-
const unsubscribe = () => {
|
|
124
|
-
eventSource.removeEventListener("snapshot", onSnapshot);
|
|
125
|
-
eventSource.removeEventListener("state", onState);
|
|
126
|
-
eventSource.close();
|
|
127
|
-
};
|
|
128
|
-
/**
|
|
129
|
-
* Dispatches a state event to the server.
|
|
130
|
-
* If optimistic = true, also applies the event locally immediately.
|
|
131
|
-
* @param event - The state event to dispatch.
|
|
132
|
-
*/
|
|
133
|
-
const dispatch = async (event) => {
|
|
134
|
-
const baseVersion = versions.get(event.storeKey) ?? 0;
|
|
135
|
-
/** Payload to send to server with event metadata, version and origin */
|
|
136
|
-
const payload = {
|
|
137
|
-
...event,
|
|
138
|
-
origin: clientId
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Optimistic logic applied locally
|
|
142
|
-
*/
|
|
143
|
-
if (options.optimistic) {
|
|
144
|
-
applyEventToTarget(payload);
|
|
145
|
-
versions.set(event.storeKey, baseVersion + 1);
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* AUTHORITATIVE: send to server
|
|
149
|
-
*/
|
|
150
|
-
const result = await transport.publish(payload);
|
|
151
|
-
/**
|
|
152
|
-
* If server rejects, reconcile (optional but good)
|
|
153
|
-
*/
|
|
154
|
-
if (!result.ok && result.status === 409 && result.json?.current && options.universe) {
|
|
155
|
-
const { state, version } = result.json.current;
|
|
156
|
-
versions.set(event.storeKey, version);
|
|
157
|
-
options.universe.getStore(event.storeKey, () => state).set(state);
|
|
158
|
-
}
|
|
159
|
-
return result;
|
|
160
|
-
};
|
|
161
|
-
return { unsubscribe, dispatch };
|
|
162
|
-
};
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import type { Store, Universe } from "../core/types";
|
|
2
|
-
/**
|
|
3
|
-
* Represents a state event received from a Zuno SSE stream.
|
|
4
|
-
*/
|
|
5
|
-
export interface ZunoStateEvent {
|
|
6
|
-
/** The kind of the event. */
|
|
7
|
-
kind?: "state";
|
|
8
|
-
/** The key of the store that emitted the state change. */
|
|
9
|
-
storeKey: string;
|
|
10
|
-
/** The new state value. */
|
|
11
|
-
state: unknown;
|
|
12
|
-
/** The version of the store before the state change to resolve conflicts and ordering. */
|
|
13
|
-
baseVersion?: number;
|
|
14
|
-
/** The authoritative version after server applies. */
|
|
15
|
-
version?: number;
|
|
16
|
-
/** The origin of the state change. */
|
|
17
|
-
origin?: string;
|
|
18
|
-
/** The timestamp of the state change. */
|
|
19
|
-
ts?: number;
|
|
20
|
-
/** The global monotonic id of the event. */
|
|
21
|
-
eventId?: number;
|
|
22
|
-
/** The transport layer that published the event. */
|
|
23
|
-
via?: "http" | "sse" | "bc";
|
|
24
|
-
}
|
|
25
|
-
export type ZunoSSEOptionsDefault = {
|
|
26
|
-
/**
|
|
27
|
-
* The URL of the SSE endpoint.
|
|
28
|
-
* */
|
|
29
|
-
url: string;
|
|
30
|
-
/**
|
|
31
|
-
* The URL of the Sync endpoint.
|
|
32
|
-
*/
|
|
33
|
-
syncUrl: string;
|
|
34
|
-
/**
|
|
35
|
-
* Get the snapshot of the universe or store.
|
|
36
|
-
*/
|
|
37
|
-
getSnapshot?: (data: Universe | Store<unknown>) => void;
|
|
38
|
-
/**
|
|
39
|
-
* Whether to enable optimistic updates.
|
|
40
|
-
* If true, the client will update its state optimistically before receiving the server's response.
|
|
41
|
-
*/
|
|
42
|
-
optimistic?: boolean;
|
|
43
|
-
/**
|
|
44
|
-
* The client id for the Broadcast Channel.
|
|
45
|
-
*/
|
|
46
|
-
clientId?: string;
|
|
47
|
-
/**
|
|
48
|
-
* The name of the Broadcast Channel.
|
|
49
|
-
*/
|
|
50
|
-
channelName?: string;
|
|
51
|
-
/**
|
|
52
|
-
* The versions of the stores.
|
|
53
|
-
*/
|
|
54
|
-
versions: Map<string, number>;
|
|
55
|
-
/**
|
|
56
|
-
* Callback when SSE connection is opened.
|
|
57
|
-
*/
|
|
58
|
-
onOpen?: () => void;
|
|
59
|
-
/**
|
|
60
|
-
* Callback when SSE connection is closed.
|
|
61
|
-
*/
|
|
62
|
-
onClose?: () => void;
|
|
63
|
-
/**
|
|
64
|
-
* The last event ID received from the server.
|
|
65
|
-
*/
|
|
66
|
-
getLastEventId?: () => number;
|
|
67
|
-
/**
|
|
68
|
-
* Callback when an event is received from the server.
|
|
69
|
-
*/
|
|
70
|
-
onEvent?: (event: ZunoStateEvent) => void;
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Options for configuring a Zuno Server-Sent Events (SSE) connection.
|
|
74
|
-
* It can be configured either with a `Universe` or a specific `Store`.
|
|
75
|
-
*/
|
|
76
|
-
export type ZunoSSEOptions = ZunoSSEOptionsDefault & ({
|
|
77
|
-
/** The universe to subscribe to. */
|
|
78
|
-
universe: Universe;
|
|
79
|
-
store?: never;
|
|
80
|
-
} | {
|
|
81
|
-
/** The specific store to subscribe to. */
|
|
82
|
-
store: Store<any>;
|
|
83
|
-
universe?: never;
|
|
84
|
-
});
|
|
85
|
-
/**
|
|
86
|
-
* Defines the interface for a Zuno transport layer, responsible for
|
|
87
|
-
* publishing and subscribing to state events.
|
|
88
|
-
*/
|
|
89
|
-
export interface ZunoTransport {
|
|
90
|
-
/**
|
|
91
|
-
* Publishes a state event to the transport.
|
|
92
|
-
* @param event The state event to publish.
|
|
93
|
-
*/
|
|
94
|
-
publish(event: ZunoStateEvent): {
|
|
95
|
-
ok: boolean;
|
|
96
|
-
status: number;
|
|
97
|
-
json: unknown;
|
|
98
|
-
} | Promise<{
|
|
99
|
-
ok: boolean;
|
|
100
|
-
status: number;
|
|
101
|
-
json: any;
|
|
102
|
-
}>;
|
|
103
|
-
/**
|
|
104
|
-
* Subscribes to state events from the transport.
|
|
105
|
-
* @param handler The function to call when a new state event is received.
|
|
106
|
-
*/
|
|
107
|
-
subscribe(handler: (event: ZunoStateEvent) => void): () => void;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* A record of a store's state and version.
|
|
111
|
-
* @property {unknown} state - The state of the store.
|
|
112
|
-
* @property {number} version - The version of the store.
|
|
113
|
-
*/
|
|
114
|
-
export type ZunoSnapshotRecord = {
|
|
115
|
-
/**
|
|
116
|
-
* The state of the store.
|
|
117
|
-
*/
|
|
118
|
-
state: unknown;
|
|
119
|
-
/**
|
|
120
|
-
* The version of the store.
|
|
121
|
-
*/
|
|
122
|
-
version: number;
|
|
123
|
-
};
|
|
124
|
-
/**
|
|
125
|
-
* A snapshot of the universe or store.
|
|
126
|
-
* @property {Record<string, ZunoSnapshotRecord>} state - The state of the store.
|
|
127
|
-
*/
|
|
128
|
-
export type ZunoSnapshotState = Record<string, ZunoSnapshotRecord>;
|
|
129
|
-
/**
|
|
130
|
-
* A message sent over the broadcast channel.
|
|
131
|
-
* @property {"zuno:hello" | "zuno:snapshot" | "zuno:event"} type - The type of the message.
|
|
132
|
-
* @property {string} origin - The origin of the message.
|
|
133
|
-
* @property {string} target - The target of the message.
|
|
134
|
-
* @property {ZunoSnapshotState} snapshot - The snapshot of the universe or store.
|
|
135
|
-
* @property {ZunoStateEvent} event - The state event.
|
|
136
|
-
*/
|
|
137
|
-
export type BCMsg = {
|
|
138
|
-
type: "zuno:hello";
|
|
139
|
-
origin: string;
|
|
140
|
-
} | {
|
|
141
|
-
type: "zuno:snapshot";
|
|
142
|
-
origin: string;
|
|
143
|
-
target: string;
|
|
144
|
-
snapshot: ZunoSnapshotState;
|
|
145
|
-
} | {
|
|
146
|
-
type: "zuno:event";
|
|
147
|
-
origin: string;
|
|
148
|
-
event: ZunoStateEvent;
|
|
149
|
-
};
|
|
150
|
-
/**
|
|
151
|
-
* Options for starting a broadcast channel.
|
|
152
|
-
* @property {string} channelName - The name of the broadcast channel.
|
|
153
|
-
* @property {string} clientId - The client id for the broadcast channel.
|
|
154
|
-
* @property {(event: ZunoStateEvent) => void} onEvent - The function to call when a new state event is received.
|
|
155
|
-
* @property {() => ZunoSnapshotState} getSnapshot - The function to get the snapshot of the universe or store.
|
|
156
|
-
*/
|
|
157
|
-
export type ZunoBCOptions = {
|
|
158
|
-
channelName: string;
|
|
159
|
-
clientId: string;
|
|
160
|
-
onEvent: (event: ZunoStateEvent) => void;
|
|
161
|
-
getSnapshot?: () => ZunoSnapshotState;
|
|
162
|
-
onSnapshot?: (snapshot: ZunoSnapshotState) => void;
|
|
163
|
-
};
|
|
164
|
-
//# sourceMappingURL=sync-types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sync-types.d.ts","sourceRoot":"","sources":["../../src/sync/sync-types.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/sync-types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/sync/transport.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ZunoTransport } from "./sync-types";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a transport for publishing Zuno state events.
|
|
4
|
-
*
|
|
5
|
-
* @param url The URL where events will be published.
|
|
6
|
-
* @param headers Additional headers to include in the HTTP request.
|
|
7
|
-
* @returns A ZunoTransport object with a publish method.
|
|
8
|
-
*/
|
|
9
|
-
export declare const createTransport: (url: string, headers?: HeadersInit) => ZunoTransport;
|
|
10
|
-
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/sync/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlE;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,EAAE,UAAU,WAAW,KAAG,aAsBpE,CAAC"}
|
package/dist/sync/transport.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a transport for publishing Zuno state events.
|
|
3
|
-
*
|
|
4
|
-
* @param url The URL where events will be published.
|
|
5
|
-
* @param headers Additional headers to include in the HTTP request.
|
|
6
|
-
* @returns A ZunoTransport object with a publish method.
|
|
7
|
-
*/
|
|
8
|
-
export const createTransport = (url, headers) => {
|
|
9
|
-
/** A set of subscribers to state events. */
|
|
10
|
-
const subs = new Set();
|
|
11
|
-
return {
|
|
12
|
-
async publish(event) {
|
|
13
|
-
const res = await fetch(url, {
|
|
14
|
-
method: "POST",
|
|
15
|
-
headers: { "Content-Type": "application/json", ...headers },
|
|
16
|
-
body: JSON.stringify(event),
|
|
17
|
-
});
|
|
18
|
-
const json = await res.json().catch(() => null);
|
|
19
|
-
return { ok: res.ok, status: res.status, json };
|
|
20
|
-
},
|
|
21
|
-
subscribe(cb) {
|
|
22
|
-
subs.add(cb);
|
|
23
|
-
return () => subs.delete(cb);
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
};
|