@korajs/core 0.5.0 → 0.6.0

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.
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/bindings/index.ts
21
+ var bindings_exports = {};
22
+ __export(bindings_exports, {
23
+ createMutationController: () => createMutationController
24
+ });
25
+ module.exports = __toCommonJS(bindings_exports);
26
+
27
+ // src/bindings/create-mutation-controller.ts
28
+ function createMutationController(options) {
29
+ let snapshot = { isLoading: false, error: null };
30
+ const listeners = /* @__PURE__ */ new Set();
31
+ let disposed = false;
32
+ let inFlight = 0;
33
+ const notify = () => {
34
+ for (const listener of listeners) {
35
+ listener();
36
+ }
37
+ options.onStateChange?.(snapshot);
38
+ };
39
+ const setSnapshot = (next) => {
40
+ snapshot = next;
41
+ notify();
42
+ };
43
+ const getSnapshot = () => snapshot;
44
+ const subscribe = (listener) => {
45
+ listeners.add(listener);
46
+ return () => {
47
+ listeners.delete(listener);
48
+ };
49
+ };
50
+ const reset = () => {
51
+ if (disposed) return;
52
+ setSnapshot({ isLoading: false, error: null });
53
+ };
54
+ const mutateAsync = async (...args) => {
55
+ if (disposed) {
56
+ throw new Error("Mutation controller is destroyed");
57
+ }
58
+ const opts = options.resolveOptions?.() ?? options.options;
59
+ let context;
60
+ inFlight++;
61
+ setSnapshot({ isLoading: true, error: null });
62
+ try {
63
+ if (opts?.onMutate) {
64
+ context = await opts.onMutate(...args);
65
+ }
66
+ const result = await options.mutationFn(...args);
67
+ inFlight = Math.max(0, inFlight - 1);
68
+ setSnapshot({ isLoading: inFlight > 0, error: null });
69
+ opts?.onSuccess?.(result, ...args);
70
+ opts?.onSettled?.(result, null, ...args);
71
+ return result;
72
+ } catch (err) {
73
+ const error = err instanceof Error ? err : new Error(String(err));
74
+ if (context !== void 0 && opts?.onRollback) {
75
+ await opts.onRollback(context, ...args);
76
+ }
77
+ inFlight = Math.max(0, inFlight - 1);
78
+ setSnapshot({ isLoading: inFlight > 0, error });
79
+ opts?.onError?.(error, ...args);
80
+ opts?.onSettled?.(void 0, error, ...args);
81
+ throw error;
82
+ }
83
+ };
84
+ const mutate = (...args) => {
85
+ void mutateAsync(...args).catch(() => {
86
+ });
87
+ };
88
+ const destroy = () => {
89
+ disposed = true;
90
+ listeners.clear();
91
+ };
92
+ return {
93
+ getSnapshot,
94
+ subscribe,
95
+ mutate,
96
+ mutateAsync,
97
+ reset,
98
+ destroy
99
+ };
100
+ }
101
+ // Annotate the CommonJS export names for ESM import in node:
102
+ 0 && (module.exports = {
103
+ createMutationController
104
+ });
105
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bindings/index.ts","../../src/bindings/create-mutation-controller.ts"],"sourcesContent":["export type {\n\tAuthSyncBinding,\n\tKoraAppLike,\n\tKoraBindingSyncBridge,\n\tKoraBindingSyncStatus,\n\tKoraContextValue,\n\tUseMutationOptions,\n\tUseMutationResultBase,\n\tUseQueryOptions,\n} from './types'\nexport {\n\tcreateMutationController,\n\ttype CreateMutationControllerOptions,\n\ttype MutationController,\n\ttype MutationControllerState,\n} from './create-mutation-controller'\n","import type { UseMutationOptions } from './types'\n\nexport interface MutationControllerState {\n\tisLoading: boolean\n\terror: Error | null\n}\n\nexport interface MutationController<TData, TArgs extends unknown[], TContext = void> {\n\tgetSnapshot(): MutationControllerState\n\tsubscribe(listener: () => void): () => void\n\tmutate(...args: TArgs): void\n\tmutateAsync(...args: TArgs): Promise<TData>\n\treset(): void\n\tdestroy(): void\n}\n\nexport interface CreateMutationControllerOptions<TData, TArgs extends unknown[], TContext = void> {\n\tmutationFn: (...args: TArgs) => Promise<TData>\n\toptions?: UseMutationOptions<TData, TArgs, TContext>\n\t/** Reads latest options on each mutation (for framework hooks with ref-backed options). */\n\tresolveOptions?: () => UseMutationOptions<TData, TArgs, TContext> | undefined\n\tonStateChange?: (state: MutationControllerState) => void\n}\n\n/**\n * Framework-agnostic mutation runner with optimistic lifecycle hooks.\n */\nexport function createMutationController<TData, TArgs extends unknown[], TContext = void>(\n\toptions: CreateMutationControllerOptions<TData, TArgs, TContext>,\n): MutationController<TData, TArgs, TContext> {\n\tlet snapshot: MutationControllerState = { isLoading: false, error: null }\n\tconst listeners = new Set<() => void>()\n\tlet disposed = false\n\tlet inFlight = 0\n\n\tconst notify = (): void => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener()\n\t\t}\n\t\toptions.onStateChange?.(snapshot)\n\t}\n\n\tconst setSnapshot = (next: MutationControllerState): void => {\n\t\tsnapshot = next\n\t\tnotify()\n\t}\n\n\tconst getSnapshot = (): MutationControllerState => snapshot\n\n\tconst subscribe = (listener: () => void): (() => void) => {\n\t\tlisteners.add(listener)\n\t\treturn () => {\n\t\t\tlisteners.delete(listener)\n\t\t}\n\t}\n\n\tconst reset = (): void => {\n\t\tif (disposed) return\n\t\tsetSnapshot({ isLoading: false, error: null })\n\t}\n\n\tconst mutateAsync = async (...args: TArgs): Promise<TData> => {\n\t\tif (disposed) {\n\t\t\tthrow new Error('Mutation controller is destroyed')\n\t\t}\n\n\t\tconst opts = options.resolveOptions?.() ?? options.options\n\t\tlet context: TContext | undefined\n\n\t\tinFlight++\n\t\tsetSnapshot({ isLoading: true, error: null })\n\n\t\ttry {\n\t\t\tif (opts?.onMutate) {\n\t\t\t\tcontext = await opts.onMutate(...args)\n\t\t\t}\n\n\t\t\tconst result = await options.mutationFn(...args)\n\t\t\tinFlight = Math.max(0, inFlight - 1)\n\t\t\tsetSnapshot({ isLoading: inFlight > 0, error: null })\n\t\t\topts?.onSuccess?.(result, ...args)\n\t\t\topts?.onSettled?.(result, null, ...args)\n\t\t\treturn result\n\t\t} catch (err) {\n\t\t\tconst error = err instanceof Error ? err : new Error(String(err))\n\n\t\t\tif (context !== undefined && opts?.onRollback) {\n\t\t\t\tawait opts.onRollback(context, ...args)\n\t\t\t}\n\n\t\t\tinFlight = Math.max(0, inFlight - 1)\n\t\t\tsetSnapshot({ isLoading: inFlight > 0, error })\n\t\t\topts?.onError?.(error, ...args)\n\t\t\topts?.onSettled?.(undefined, error, ...args)\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tconst mutate = (...args: TArgs): void => {\n\t\tvoid mutateAsync(...args).catch(() => {})\n\t}\n\n\tconst destroy = (): void => {\n\t\tdisposed = true\n\t\tlisteners.clear()\n\t}\n\n\treturn {\n\t\tgetSnapshot,\n\t\tsubscribe,\n\t\tmutate,\n\t\tmutateAsync,\n\t\treset,\n\t\tdestroy,\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC2BO,SAAS,yBACf,SAC6C;AAC7C,MAAI,WAAoC,EAAE,WAAW,OAAO,OAAO,KAAK;AACxE,QAAM,YAAY,oBAAI,IAAgB;AACtC,MAAI,WAAW;AACf,MAAI,WAAW;AAEf,QAAM,SAAS,MAAY;AAC1B,eAAW,YAAY,WAAW;AACjC,eAAS;AAAA,IACV;AACA,YAAQ,gBAAgB,QAAQ;AAAA,EACjC;AAEA,QAAM,cAAc,CAAC,SAAwC;AAC5D,eAAW;AACX,WAAO;AAAA,EACR;AAEA,QAAM,cAAc,MAA+B;AAEnD,QAAM,YAAY,CAAC,aAAuC;AACzD,cAAU,IAAI,QAAQ;AACtB,WAAO,MAAM;AACZ,gBAAU,OAAO,QAAQ;AAAA,IAC1B;AAAA,EACD;AAEA,QAAM,QAAQ,MAAY;AACzB,QAAI,SAAU;AACd,gBAAY,EAAE,WAAW,OAAO,OAAO,KAAK,CAAC;AAAA,EAC9C;AAEA,QAAM,cAAc,UAAU,SAAgC;AAC7D,QAAI,UAAU;AACb,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACnD;AAEA,UAAM,OAAO,QAAQ,iBAAiB,KAAK,QAAQ;AACnD,QAAI;AAEJ;AACA,gBAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAE5C,QAAI;AACH,UAAI,MAAM,UAAU;AACnB,kBAAU,MAAM,KAAK,SAAS,GAAG,IAAI;AAAA,MACtC;AAEA,YAAM,SAAS,MAAM,QAAQ,WAAW,GAAG,IAAI;AAC/C,iBAAW,KAAK,IAAI,GAAG,WAAW,CAAC;AACnC,kBAAY,EAAE,WAAW,WAAW,GAAG,OAAO,KAAK,CAAC;AACpD,YAAM,YAAY,QAAQ,GAAG,IAAI;AACjC,YAAM,YAAY,QAAQ,MAAM,GAAG,IAAI;AACvC,aAAO;AAAA,IACR,SAAS,KAAK;AACb,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAEhE,UAAI,YAAY,UAAa,MAAM,YAAY;AAC9C,cAAM,KAAK,WAAW,SAAS,GAAG,IAAI;AAAA,MACvC;AAEA,iBAAW,KAAK,IAAI,GAAG,WAAW,CAAC;AACnC,kBAAY,EAAE,WAAW,WAAW,GAAG,MAAM,CAAC;AAC9C,YAAM,UAAU,OAAO,GAAG,IAAI;AAC9B,YAAM,YAAY,QAAW,OAAO,GAAG,IAAI;AAC3C,YAAM;AAAA,IACP;AAAA,EACD;AAEA,QAAM,SAAS,IAAI,SAAsB;AACxC,SAAK,YAAY,GAAG,IAAI,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACzC;AAEA,QAAM,UAAU,MAAY;AAC3B,eAAW;AACX,cAAU,MAAM;AAAA,EACjB;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;","names":[]}
@@ -0,0 +1,101 @@
1
+ import { p as KoraEventEmitter } from '../events-D-FWfFg8.cjs';
2
+ import { S as ScopeMap } from '../build-scope-map-B1CcncZN.cjs';
3
+
4
+ /** Sync status shape consumed by framework binding hooks (matches {@link SyncStatusInfo} in `@korajs/sync`). */
5
+ interface KoraBindingSyncStatus {
6
+ status: 'connected' | 'syncing' | 'synced' | 'offline' | 'error' | 'schema-mismatch';
7
+ pendingOperations: number;
8
+ lastSyncedAt: number | null;
9
+ lastSuccessfulPush: number | null;
10
+ lastSuccessfulPull: number | null;
11
+ conflicts: number;
12
+ }
13
+ /** Minimal sync bridge surface exposed on `createApp().sync`. */
14
+ interface KoraBindingSyncBridge {
15
+ subscribeStatus(listener: (status: KoraBindingSyncStatus) => void): () => void;
16
+ }
17
+ /**
18
+ * Structural type for a Kora application instance from `createApp()`.
19
+ * Framework packages specialize `TStore` and `TSyncEngine` with concrete types.
20
+ */
21
+ interface KoraAppLike<TStore = unknown, TSyncEngine = unknown, TQueryCache = unknown> {
22
+ ready: Promise<void>;
23
+ events?: KoraEventEmitter;
24
+ sync?: KoraBindingSyncBridge | null;
25
+ getStore(): TStore;
26
+ getSyncEngine(): TSyncEngine | null;
27
+ getQueryStoreCache(): TQueryCache;
28
+ }
29
+ /** Value provided by framework `KoraProvider` implementations. */
30
+ interface KoraContextValue<TStore = unknown, TSyncEngine = unknown, TQueryCache = unknown> {
31
+ store: TStore;
32
+ syncEngine: TSyncEngine | null;
33
+ app: KoraAppLike<TStore, TSyncEngine, TQueryCache> | null;
34
+ events: KoraEventEmitter | null;
35
+ subscribeSyncStatus: KoraBindingSyncBridge['subscribeStatus'] | null;
36
+ queryStoreCache: TQueryCache;
37
+ }
38
+ /** Options for reactive query bindings (`useQuery`, `createQueryStore`, etc.). */
39
+ interface UseQueryOptions {
40
+ /** When false, the query subscription is disabled. Defaults to true. */
41
+ enabled?: boolean;
42
+ }
43
+ /** Optimistic mutation lifecycle callbacks shared across framework bindings. */
44
+ interface UseMutationOptions<TData, TArgs extends unknown[], TContext = void> {
45
+ onMutate?: (...args: TArgs) => TContext | Promise<TContext>;
46
+ onRollback?: (context: TContext, ...args: TArgs) => void | Promise<void>;
47
+ onSuccess?: (data: TData, ...args: TArgs) => void;
48
+ onError?: (error: Error, ...args: TArgs) => void;
49
+ onSettled?: (data: TData | undefined, error: Error | null, ...args: TArgs) => void;
50
+ }
51
+ /** Common mutation result surface (React uses plain values; Vue/Svelte extend this). */
52
+ interface UseMutationResultBase<TData, TArgs extends unknown[]> {
53
+ mutate: (...args: TArgs) => void;
54
+ mutateAsync: (...args: TArgs) => Promise<TData>;
55
+ reset: () => void;
56
+ }
57
+ /**
58
+ * Pre-built auth binding for `createApp({ sync: { authClient } })`.
59
+ * Created by `createKoraAuthSync()` in `@korajs/auth`.
60
+ */
61
+ interface AuthSyncBinding {
62
+ /** Returns the access token for sync handshake (empty string when signed out). */
63
+ auth: () => Promise<{
64
+ token: string;
65
+ }>;
66
+ /** Builds a scope map from the current token and schema. */
67
+ resolveScopeMap?: () => Promise<ScopeMap | undefined>;
68
+ /**
69
+ * Returns the device-bound sync node id from the token `dev` claim.
70
+ * Separate from the user id (`sub`).
71
+ */
72
+ resolveNodeId?: () => Promise<string | undefined>;
73
+ /** Notifies when auth state changes so sync can refresh scope or reconnect. */
74
+ subscribe?: (listener: () => void) => () => void;
75
+ }
76
+
77
+ interface MutationControllerState {
78
+ isLoading: boolean;
79
+ error: Error | null;
80
+ }
81
+ interface MutationController<TData, TArgs extends unknown[], TContext = void> {
82
+ getSnapshot(): MutationControllerState;
83
+ subscribe(listener: () => void): () => void;
84
+ mutate(...args: TArgs): void;
85
+ mutateAsync(...args: TArgs): Promise<TData>;
86
+ reset(): void;
87
+ destroy(): void;
88
+ }
89
+ interface CreateMutationControllerOptions<TData, TArgs extends unknown[], TContext = void> {
90
+ mutationFn: (...args: TArgs) => Promise<TData>;
91
+ options?: UseMutationOptions<TData, TArgs, TContext>;
92
+ /** Reads latest options on each mutation (for framework hooks with ref-backed options). */
93
+ resolveOptions?: () => UseMutationOptions<TData, TArgs, TContext> | undefined;
94
+ onStateChange?: (state: MutationControllerState) => void;
95
+ }
96
+ /**
97
+ * Framework-agnostic mutation runner with optimistic lifecycle hooks.
98
+ */
99
+ declare function createMutationController<TData, TArgs extends unknown[], TContext = void>(options: CreateMutationControllerOptions<TData, TArgs, TContext>): MutationController<TData, TArgs, TContext>;
100
+
101
+ export { type AuthSyncBinding, type CreateMutationControllerOptions, type KoraAppLike, type KoraBindingSyncBridge, type KoraBindingSyncStatus, type KoraContextValue, type MutationController, type MutationControllerState, type UseMutationOptions, type UseMutationResultBase, type UseQueryOptions, createMutationController };
@@ -0,0 +1,101 @@
1
+ import { p as KoraEventEmitter } from '../events-D-FWfFg8.js';
2
+ import { S as ScopeMap } from '../build-scope-map-BmgAT82h.js';
3
+
4
+ /** Sync status shape consumed by framework binding hooks (matches {@link SyncStatusInfo} in `@korajs/sync`). */
5
+ interface KoraBindingSyncStatus {
6
+ status: 'connected' | 'syncing' | 'synced' | 'offline' | 'error' | 'schema-mismatch';
7
+ pendingOperations: number;
8
+ lastSyncedAt: number | null;
9
+ lastSuccessfulPush: number | null;
10
+ lastSuccessfulPull: number | null;
11
+ conflicts: number;
12
+ }
13
+ /** Minimal sync bridge surface exposed on `createApp().sync`. */
14
+ interface KoraBindingSyncBridge {
15
+ subscribeStatus(listener: (status: KoraBindingSyncStatus) => void): () => void;
16
+ }
17
+ /**
18
+ * Structural type for a Kora application instance from `createApp()`.
19
+ * Framework packages specialize `TStore` and `TSyncEngine` with concrete types.
20
+ */
21
+ interface KoraAppLike<TStore = unknown, TSyncEngine = unknown, TQueryCache = unknown> {
22
+ ready: Promise<void>;
23
+ events?: KoraEventEmitter;
24
+ sync?: KoraBindingSyncBridge | null;
25
+ getStore(): TStore;
26
+ getSyncEngine(): TSyncEngine | null;
27
+ getQueryStoreCache(): TQueryCache;
28
+ }
29
+ /** Value provided by framework `KoraProvider` implementations. */
30
+ interface KoraContextValue<TStore = unknown, TSyncEngine = unknown, TQueryCache = unknown> {
31
+ store: TStore;
32
+ syncEngine: TSyncEngine | null;
33
+ app: KoraAppLike<TStore, TSyncEngine, TQueryCache> | null;
34
+ events: KoraEventEmitter | null;
35
+ subscribeSyncStatus: KoraBindingSyncBridge['subscribeStatus'] | null;
36
+ queryStoreCache: TQueryCache;
37
+ }
38
+ /** Options for reactive query bindings (`useQuery`, `createQueryStore`, etc.). */
39
+ interface UseQueryOptions {
40
+ /** When false, the query subscription is disabled. Defaults to true. */
41
+ enabled?: boolean;
42
+ }
43
+ /** Optimistic mutation lifecycle callbacks shared across framework bindings. */
44
+ interface UseMutationOptions<TData, TArgs extends unknown[], TContext = void> {
45
+ onMutate?: (...args: TArgs) => TContext | Promise<TContext>;
46
+ onRollback?: (context: TContext, ...args: TArgs) => void | Promise<void>;
47
+ onSuccess?: (data: TData, ...args: TArgs) => void;
48
+ onError?: (error: Error, ...args: TArgs) => void;
49
+ onSettled?: (data: TData | undefined, error: Error | null, ...args: TArgs) => void;
50
+ }
51
+ /** Common mutation result surface (React uses plain values; Vue/Svelte extend this). */
52
+ interface UseMutationResultBase<TData, TArgs extends unknown[]> {
53
+ mutate: (...args: TArgs) => void;
54
+ mutateAsync: (...args: TArgs) => Promise<TData>;
55
+ reset: () => void;
56
+ }
57
+ /**
58
+ * Pre-built auth binding for `createApp({ sync: { authClient } })`.
59
+ * Created by `createKoraAuthSync()` in `@korajs/auth`.
60
+ */
61
+ interface AuthSyncBinding {
62
+ /** Returns the access token for sync handshake (empty string when signed out). */
63
+ auth: () => Promise<{
64
+ token: string;
65
+ }>;
66
+ /** Builds a scope map from the current token and schema. */
67
+ resolveScopeMap?: () => Promise<ScopeMap | undefined>;
68
+ /**
69
+ * Returns the device-bound sync node id from the token `dev` claim.
70
+ * Separate from the user id (`sub`).
71
+ */
72
+ resolveNodeId?: () => Promise<string | undefined>;
73
+ /** Notifies when auth state changes so sync can refresh scope or reconnect. */
74
+ subscribe?: (listener: () => void) => () => void;
75
+ }
76
+
77
+ interface MutationControllerState {
78
+ isLoading: boolean;
79
+ error: Error | null;
80
+ }
81
+ interface MutationController<TData, TArgs extends unknown[], TContext = void> {
82
+ getSnapshot(): MutationControllerState;
83
+ subscribe(listener: () => void): () => void;
84
+ mutate(...args: TArgs): void;
85
+ mutateAsync(...args: TArgs): Promise<TData>;
86
+ reset(): void;
87
+ destroy(): void;
88
+ }
89
+ interface CreateMutationControllerOptions<TData, TArgs extends unknown[], TContext = void> {
90
+ mutationFn: (...args: TArgs) => Promise<TData>;
91
+ options?: UseMutationOptions<TData, TArgs, TContext>;
92
+ /** Reads latest options on each mutation (for framework hooks with ref-backed options). */
93
+ resolveOptions?: () => UseMutationOptions<TData, TArgs, TContext> | undefined;
94
+ onStateChange?: (state: MutationControllerState) => void;
95
+ }
96
+ /**
97
+ * Framework-agnostic mutation runner with optimistic lifecycle hooks.
98
+ */
99
+ declare function createMutationController<TData, TArgs extends unknown[], TContext = void>(options: CreateMutationControllerOptions<TData, TArgs, TContext>): MutationController<TData, TArgs, TContext>;
100
+
101
+ export { type AuthSyncBinding, type CreateMutationControllerOptions, type KoraAppLike, type KoraBindingSyncBridge, type KoraBindingSyncStatus, type KoraContextValue, type MutationController, type MutationControllerState, type UseMutationOptions, type UseMutationResultBase, type UseQueryOptions, createMutationController };
@@ -0,0 +1,78 @@
1
+ // src/bindings/create-mutation-controller.ts
2
+ function createMutationController(options) {
3
+ let snapshot = { isLoading: false, error: null };
4
+ const listeners = /* @__PURE__ */ new Set();
5
+ let disposed = false;
6
+ let inFlight = 0;
7
+ const notify = () => {
8
+ for (const listener of listeners) {
9
+ listener();
10
+ }
11
+ options.onStateChange?.(snapshot);
12
+ };
13
+ const setSnapshot = (next) => {
14
+ snapshot = next;
15
+ notify();
16
+ };
17
+ const getSnapshot = () => snapshot;
18
+ const subscribe = (listener) => {
19
+ listeners.add(listener);
20
+ return () => {
21
+ listeners.delete(listener);
22
+ };
23
+ };
24
+ const reset = () => {
25
+ if (disposed) return;
26
+ setSnapshot({ isLoading: false, error: null });
27
+ };
28
+ const mutateAsync = async (...args) => {
29
+ if (disposed) {
30
+ throw new Error("Mutation controller is destroyed");
31
+ }
32
+ const opts = options.resolveOptions?.() ?? options.options;
33
+ let context;
34
+ inFlight++;
35
+ setSnapshot({ isLoading: true, error: null });
36
+ try {
37
+ if (opts?.onMutate) {
38
+ context = await opts.onMutate(...args);
39
+ }
40
+ const result = await options.mutationFn(...args);
41
+ inFlight = Math.max(0, inFlight - 1);
42
+ setSnapshot({ isLoading: inFlight > 0, error: null });
43
+ opts?.onSuccess?.(result, ...args);
44
+ opts?.onSettled?.(result, null, ...args);
45
+ return result;
46
+ } catch (err) {
47
+ const error = err instanceof Error ? err : new Error(String(err));
48
+ if (context !== void 0 && opts?.onRollback) {
49
+ await opts.onRollback(context, ...args);
50
+ }
51
+ inFlight = Math.max(0, inFlight - 1);
52
+ setSnapshot({ isLoading: inFlight > 0, error });
53
+ opts?.onError?.(error, ...args);
54
+ opts?.onSettled?.(void 0, error, ...args);
55
+ throw error;
56
+ }
57
+ };
58
+ const mutate = (...args) => {
59
+ void mutateAsync(...args).catch(() => {
60
+ });
61
+ };
62
+ const destroy = () => {
63
+ disposed = true;
64
+ listeners.clear();
65
+ };
66
+ return {
67
+ getSnapshot,
68
+ subscribe,
69
+ mutate,
70
+ mutateAsync,
71
+ reset,
72
+ destroy
73
+ };
74
+ }
75
+ export {
76
+ createMutationController
77
+ };
78
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bindings/create-mutation-controller.ts"],"sourcesContent":["import type { UseMutationOptions } from './types'\n\nexport interface MutationControllerState {\n\tisLoading: boolean\n\terror: Error | null\n}\n\nexport interface MutationController<TData, TArgs extends unknown[], TContext = void> {\n\tgetSnapshot(): MutationControllerState\n\tsubscribe(listener: () => void): () => void\n\tmutate(...args: TArgs): void\n\tmutateAsync(...args: TArgs): Promise<TData>\n\treset(): void\n\tdestroy(): void\n}\n\nexport interface CreateMutationControllerOptions<TData, TArgs extends unknown[], TContext = void> {\n\tmutationFn: (...args: TArgs) => Promise<TData>\n\toptions?: UseMutationOptions<TData, TArgs, TContext>\n\t/** Reads latest options on each mutation (for framework hooks with ref-backed options). */\n\tresolveOptions?: () => UseMutationOptions<TData, TArgs, TContext> | undefined\n\tonStateChange?: (state: MutationControllerState) => void\n}\n\n/**\n * Framework-agnostic mutation runner with optimistic lifecycle hooks.\n */\nexport function createMutationController<TData, TArgs extends unknown[], TContext = void>(\n\toptions: CreateMutationControllerOptions<TData, TArgs, TContext>,\n): MutationController<TData, TArgs, TContext> {\n\tlet snapshot: MutationControllerState = { isLoading: false, error: null }\n\tconst listeners = new Set<() => void>()\n\tlet disposed = false\n\tlet inFlight = 0\n\n\tconst notify = (): void => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener()\n\t\t}\n\t\toptions.onStateChange?.(snapshot)\n\t}\n\n\tconst setSnapshot = (next: MutationControllerState): void => {\n\t\tsnapshot = next\n\t\tnotify()\n\t}\n\n\tconst getSnapshot = (): MutationControllerState => snapshot\n\n\tconst subscribe = (listener: () => void): (() => void) => {\n\t\tlisteners.add(listener)\n\t\treturn () => {\n\t\t\tlisteners.delete(listener)\n\t\t}\n\t}\n\n\tconst reset = (): void => {\n\t\tif (disposed) return\n\t\tsetSnapshot({ isLoading: false, error: null })\n\t}\n\n\tconst mutateAsync = async (...args: TArgs): Promise<TData> => {\n\t\tif (disposed) {\n\t\t\tthrow new Error('Mutation controller is destroyed')\n\t\t}\n\n\t\tconst opts = options.resolveOptions?.() ?? options.options\n\t\tlet context: TContext | undefined\n\n\t\tinFlight++\n\t\tsetSnapshot({ isLoading: true, error: null })\n\n\t\ttry {\n\t\t\tif (opts?.onMutate) {\n\t\t\t\tcontext = await opts.onMutate(...args)\n\t\t\t}\n\n\t\t\tconst result = await options.mutationFn(...args)\n\t\t\tinFlight = Math.max(0, inFlight - 1)\n\t\t\tsetSnapshot({ isLoading: inFlight > 0, error: null })\n\t\t\topts?.onSuccess?.(result, ...args)\n\t\t\topts?.onSettled?.(result, null, ...args)\n\t\t\treturn result\n\t\t} catch (err) {\n\t\t\tconst error = err instanceof Error ? err : new Error(String(err))\n\n\t\t\tif (context !== undefined && opts?.onRollback) {\n\t\t\t\tawait opts.onRollback(context, ...args)\n\t\t\t}\n\n\t\t\tinFlight = Math.max(0, inFlight - 1)\n\t\t\tsetSnapshot({ isLoading: inFlight > 0, error })\n\t\t\topts?.onError?.(error, ...args)\n\t\t\topts?.onSettled?.(undefined, error, ...args)\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tconst mutate = (...args: TArgs): void => {\n\t\tvoid mutateAsync(...args).catch(() => {})\n\t}\n\n\tconst destroy = (): void => {\n\t\tdisposed = true\n\t\tlisteners.clear()\n\t}\n\n\treturn {\n\t\tgetSnapshot,\n\t\tsubscribe,\n\t\tmutate,\n\t\tmutateAsync,\n\t\treset,\n\t\tdestroy,\n\t}\n}\n"],"mappings":";AA2BO,SAAS,yBACf,SAC6C;AAC7C,MAAI,WAAoC,EAAE,WAAW,OAAO,OAAO,KAAK;AACxE,QAAM,YAAY,oBAAI,IAAgB;AACtC,MAAI,WAAW;AACf,MAAI,WAAW;AAEf,QAAM,SAAS,MAAY;AAC1B,eAAW,YAAY,WAAW;AACjC,eAAS;AAAA,IACV;AACA,YAAQ,gBAAgB,QAAQ;AAAA,EACjC;AAEA,QAAM,cAAc,CAAC,SAAwC;AAC5D,eAAW;AACX,WAAO;AAAA,EACR;AAEA,QAAM,cAAc,MAA+B;AAEnD,QAAM,YAAY,CAAC,aAAuC;AACzD,cAAU,IAAI,QAAQ;AACtB,WAAO,MAAM;AACZ,gBAAU,OAAO,QAAQ;AAAA,IAC1B;AAAA,EACD;AAEA,QAAM,QAAQ,MAAY;AACzB,QAAI,SAAU;AACd,gBAAY,EAAE,WAAW,OAAO,OAAO,KAAK,CAAC;AAAA,EAC9C;AAEA,QAAM,cAAc,UAAU,SAAgC;AAC7D,QAAI,UAAU;AACb,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACnD;AAEA,UAAM,OAAO,QAAQ,iBAAiB,KAAK,QAAQ;AACnD,QAAI;AAEJ;AACA,gBAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAE5C,QAAI;AACH,UAAI,MAAM,UAAU;AACnB,kBAAU,MAAM,KAAK,SAAS,GAAG,IAAI;AAAA,MACtC;AAEA,YAAM,SAAS,MAAM,QAAQ,WAAW,GAAG,IAAI;AAC/C,iBAAW,KAAK,IAAI,GAAG,WAAW,CAAC;AACnC,kBAAY,EAAE,WAAW,WAAW,GAAG,OAAO,KAAK,CAAC;AACpD,YAAM,YAAY,QAAQ,GAAG,IAAI;AACjC,YAAM,YAAY,QAAQ,MAAM,GAAG,IAAI;AACvC,aAAO;AAAA,IACR,SAAS,KAAK;AACb,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAEhE,UAAI,YAAY,UAAa,MAAM,YAAY;AAC9C,cAAM,KAAK,WAAW,SAAS,GAAG,IAAI;AAAA,MACvC;AAEA,iBAAW,KAAK,IAAI,GAAG,WAAW,CAAC;AACnC,kBAAY,EAAE,WAAW,WAAW,GAAG,MAAM,CAAC;AAC9C,YAAM,UAAU,OAAO,GAAG,IAAI;AAC9B,YAAM,YAAY,QAAW,OAAO,GAAG,IAAI;AAC3C,YAAM;AAAA,IACP;AAAA,EACD;AAEA,QAAM,SAAS,IAAI,SAAsB;AACxC,SAAK,YAAY,GAAG,IAAI,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACzC;AAEA,QAAM,UAAU,MAAY;AAC3B,eAAW;AACX,cAAU,MAAM;AAAA,EACjB;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;","names":[]}
@@ -0,0 +1,33 @@
1
+ import { S as SchemaDefinition } from './events-D-FWfFg8.cjs';
2
+
3
+ /**
4
+ * Per-collection scope map: `{ collectionName: { field: value, ... } }`
5
+ *
6
+ * Used to filter which operations a client should receive during sync.
7
+ */
8
+ type ScopeMap = Record<string, Record<string, unknown>>;
9
+ /**
10
+ * Build a per-collection scope map from the schema's scope declarations
11
+ * and the client's flat scope values.
12
+ *
13
+ * Supports both legacy `collection.scope` arrays and declarative `schema.sync`
14
+ * rules (`sync: { todos: { where: { userId: true } } }`).
15
+ *
16
+ * When `schema.sync` is present, only collections with sync rules or legacy
17
+ * scope fields are included in the result. Other collections are omitted so
18
+ * sync engines treat them as out of scope (partial sync).
19
+ *
20
+ * @param schema - The schema definition with scope declarations
21
+ * @param scopeValues - Flat key-value scope values from the client
22
+ * @returns A per-collection scope map
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Schema declares: sales.scope = ['orgId', 'storeId']
27
+ * // Client provides: { orgId: 'org-123', storeId: 'store-456' }
28
+ * // Result: { sales: { orgId: 'org-123', storeId: 'store-456' }, products: {} }
29
+ * ```
30
+ */
31
+ declare function buildScopeMap(schema: SchemaDefinition, scopeValues: Record<string, unknown>): ScopeMap;
32
+
33
+ export { type ScopeMap as S, buildScopeMap as b };
@@ -0,0 +1,33 @@
1
+ import { S as SchemaDefinition } from './events-D-FWfFg8.js';
2
+
3
+ /**
4
+ * Per-collection scope map: `{ collectionName: { field: value, ... } }`
5
+ *
6
+ * Used to filter which operations a client should receive during sync.
7
+ */
8
+ type ScopeMap = Record<string, Record<string, unknown>>;
9
+ /**
10
+ * Build a per-collection scope map from the schema's scope declarations
11
+ * and the client's flat scope values.
12
+ *
13
+ * Supports both legacy `collection.scope` arrays and declarative `schema.sync`
14
+ * rules (`sync: { todos: { where: { userId: true } } }`).
15
+ *
16
+ * When `schema.sync` is present, only collections with sync rules or legacy
17
+ * scope fields are included in the result. Other collections are omitted so
18
+ * sync engines treat them as out of scope (partial sync).
19
+ *
20
+ * @param schema - The schema definition with scope declarations
21
+ * @param scopeValues - Flat key-value scope values from the client
22
+ * @returns A per-collection scope map
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Schema declares: sales.scope = ['orgId', 'storeId']
27
+ * // Client provides: { orgId: 'org-123', storeId: 'store-456' }
28
+ * // Result: { sales: { orgId: 'org-123', storeId: 'store-456' }, products: {} }
29
+ * ```
30
+ */
31
+ declare function buildScopeMap(schema: SchemaDefinition, scopeValues: Record<string, unknown>): ScopeMap;
32
+
33
+ export { type ScopeMap as S, buildScopeMap as b };
@@ -76,6 +76,14 @@ var StorageError = class extends KoraError {
76
76
  this.name = "StorageError";
77
77
  }
78
78
  };
79
+ var AppNotReadyError = class extends KoraError {
80
+ constructor(detail) {
81
+ super(detail, "APP_NOT_READY", {
82
+ fix: "Await app.ready, or wrap your UI in <KoraProvider app={app}> before calling useQuery()."
83
+ });
84
+ this.name = "AppNotReadyError";
85
+ }
86
+ };
79
87
  var ClockDriftError = class extends KoraError {
80
88
  constructor(currentHlcTime, physicalTime) {
81
89
  const driftSeconds = Math.round((currentHlcTime - physicalTime) / 1e3);
@@ -488,6 +496,7 @@ export {
488
496
  MergeConflictError,
489
497
  SyncError,
490
498
  StorageError,
499
+ AppNotReadyError,
491
500
  ClockDriftError,
492
501
  HybridLogicalClock,
493
502
  computeOperationId,
@@ -498,4 +507,4 @@ export {
498
507
  isValidOperation,
499
508
  topologicalSort
500
509
  };
501
- //# sourceMappingURL=chunk-H4FXU5OP.js.map
510
+ //# sourceMappingURL=chunk-3VIOZT7D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/error-fixes.ts","../src/errors/errors.ts","../src/clock/hlc.ts","../src/operations/content-hash.ts","../src/operations/operation.ts","../src/version-vector/topological-sort.ts"],"sourcesContent":["/**\n * Human-readable remediation hints keyed by {@link KoraError} `code`.\n */\nexport const KORA_ERROR_FIX_SUGGESTIONS: Record<string, string> = {\n\tSCHEMA_VALIDATION:\n\t\t'Review your defineSchema() definition: every collection needs at least one field and a positive version.',\n\tOPERATION_ERROR:\n\t\t'Check the operation payload matches your schema field types and required fields.',\n\tMERGE_CONFLICT:\n\t\t'Add a custom resolver for the conflicting field in defineSchema(), or adjust constraint onConflict rules.',\n\tSYNC_ERROR:\n\t\t'Verify the sync server URL, auth token, and that the server accepts your schema version.',\n\tSTORAGE_ERROR:\n\t\t'Confirm the storage adapter is supported in this environment and the database path is writable.',\n\tCLOCK_DRIFT:\n\t\t'Sync device wall-clock time (NTP). Kora refuses new timestamps when drift exceeds five minutes.',\n\tPERSISTENCE_ERROR:\n\t\t'IndexedDB persistence failed; check browser storage settings and available disk quota.',\n\tMISSING_WORKER_URL:\n\t\t'Pass store.workerUrl pointing to sqlite-wasm-worker.js (see create-kora-app templates).',\n\tINVALID_SYNC_URL:\n\t\t'Use ws:// or wss:// for WebSocket transport, or http(s):// for HTTP long-polling.',\n\tAPP_NOT_READY:\n\t\t'Await app.ready before querying or mutating collections, or wrap the tree in <KoraProvider app={app}>.',\n}\n\n/**\n * Returns a suggested fix for a Kora error code, if one is known.\n */\nexport function getKoraErrorFix(code: string): string | undefined {\n\treturn KORA_ERROR_FIX_SUGGESTIONS[code]\n}\n","import { getKoraErrorFix } from './error-fixes'\n\n/**\n * Base error class for all Kora errors.\n * Every error includes a machine-readable code and optional context for debugging.\n */\nexport class KoraError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly code: string,\n\t\tpublic readonly context?: Record<string, unknown>,\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'KoraError'\n\t}\n\n\t/**\n\t * Actionable hint for resolving this error (from registry or error context).\n\t */\n\tget fix(): string | undefined {\n\t\tconst fromContext = this.context?.fix\n\t\tif (typeof fromContext === 'string' && fromContext.length > 0) {\n\t\t\treturn fromContext\n\t\t}\n\t\treturn getKoraErrorFix(this.code)\n\t}\n}\n\n/**\n * Thrown when schema validation fails during defineSchema() or at app initialization.\n */\nexport class SchemaValidationError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'SCHEMA_VALIDATION', context)\n\t\tthis.name = 'SchemaValidationError'\n\t}\n}\n\n/**\n * Thrown when an operation is invalid or cannot be created.\n */\nexport class OperationError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'OPERATION_ERROR', context)\n\t\tthis.name = 'OperationError'\n\t}\n}\n\n/**\n * Thrown when a merge conflict cannot be automatically resolved.\n */\nexport class MergeConflictError extends KoraError {\n\tconstructor(\n\t\tpublic readonly operationA: { id: string; collection: string },\n\t\tpublic readonly operationB: { id: string; collection: string },\n\t\tpublic readonly field: string,\n\t) {\n\t\tsuper(\n\t\t\t`Merge conflict on field \"${field}\" in collection \"${operationA.collection}\"`,\n\t\t\t'MERGE_CONFLICT',\n\t\t\t{ operationA: operationA.id, operationB: operationB.id, field },\n\t\t)\n\t\tthis.name = 'MergeConflictError'\n\t}\n}\n\n/**\n * Thrown when a sync error occurs.\n */\nexport class SyncError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'SYNC_ERROR', context)\n\t\tthis.name = 'SyncError'\n\t}\n}\n\n/**\n * Thrown when a storage operation fails.\n */\nexport class StorageError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'STORAGE_ERROR', context)\n\t\tthis.name = 'StorageError'\n\t}\n}\n\n/**\n * Thrown when collection/query APIs are used before {@link KoraApp.ready} resolves.\n */\nexport class AppNotReadyError extends KoraError {\n\tconstructor(detail: string) {\n\t\tsuper(detail, 'APP_NOT_READY', {\n\t\t\tfix: 'Await app.ready, or wrap your UI in <KoraProvider app={app}> before calling useQuery().',\n\t\t})\n\t\tthis.name = 'AppNotReadyError'\n\t}\n}\n\n/**\n * Thrown when the HLC detects excessive clock drift.\n * Drift > 60s: warning. Drift > 5min: this error is thrown, refusing to generate timestamps.\n */\nexport class ClockDriftError extends KoraError {\n\tconstructor(\n\t\tpublic readonly currentHlcTime: number,\n\t\tpublic readonly physicalTime: number,\n\t) {\n\t\tconst driftSeconds = Math.round((currentHlcTime - physicalTime) / 1000)\n\t\tsuper(\n\t\t\t`Clock drift of ${driftSeconds}s detected. Physical time is behind HLC by more than 5 minutes. This indicates a severe clock issue.`,\n\t\t\t'CLOCK_DRIFT',\n\t\t\t{ currentHlcTime, physicalTime, driftSeconds },\n\t\t)\n\t\tthis.name = 'ClockDriftError'\n\t}\n}\n","import { ClockDriftError } from '../errors/errors'\nimport type { HLCTimestamp, TimeSource } from '../types'\n\n/** Default time source using the system clock */\nconst systemTimeSource: TimeSource = { now: () => Date.now() }\n\n/** Maximum allowed drift before warning (60 seconds) */\nconst DRIFT_WARN_MS = 60_000\n\n/** Maximum allowed drift before refusing to generate timestamps (5 minutes) */\nconst DRIFT_ERROR_MS = 5 * 60_000\n\n/**\n * Hybrid Logical Clock implementation based on Kulkarni et al.\n *\n * Provides a total order that respects causality without requiring synchronized clocks.\n * Each call to now() returns a timestamp strictly greater than the previous one.\n *\n * @example\n * ```typescript\n * const clock = new HybridLogicalClock('node-1')\n * const ts1 = clock.now()\n * const ts2 = clock.now()\n * // HybridLogicalClock.compare(ts1, ts2) < 0 (ts1 is earlier)\n * ```\n */\nexport class HybridLogicalClock {\n\tprivate wallTime = 0\n\tprivate logical = 0\n\n\tconstructor(\n\t\tprivate readonly nodeId: string,\n\t\tprivate readonly timeSource: TimeSource = systemTimeSource,\n\t\tprivate readonly onDriftWarning?: (driftMs: number) => void,\n\t) {}\n\n\t/**\n\t * Generate a new timestamp for a local event.\n\t * Guarantees monotonicity: each call returns a timestamp strictly greater than the previous.\n\t *\n\t * @throws {ClockDriftError} If physical time is more than 5 minutes behind the HLC wallTime\n\t */\n\tnow(): HLCTimestamp {\n\t\tconst physicalTime = this.timeSource.now()\n\t\tthis.checkDrift(physicalTime)\n\n\t\tif (physicalTime > this.wallTime) {\n\t\t\tthis.wallTime = physicalTime\n\t\t\tthis.logical = 0\n\t\t} else {\n\t\t\tthis.logical++\n\t\t}\n\n\t\treturn { wallTime: this.wallTime, logical: this.logical, nodeId: this.nodeId }\n\t}\n\n\t/**\n\t * Update clock on receiving a remote timestamp.\n\t * Merges the remote clock state with the local state to maintain causal ordering.\n\t *\n\t * @throws {ClockDriftError} If physical time is more than 5 minutes behind the resulting wallTime\n\t */\n\treceive(remote: HLCTimestamp): HLCTimestamp {\n\t\tconst physicalTime = this.timeSource.now()\n\t\tconst wasColdStart = this.wallTime === 0\n\n\t\tif (physicalTime > this.wallTime && physicalTime > remote.wallTime) {\n\t\t\tthis.wallTime = physicalTime\n\t\t\tthis.logical = 0\n\t\t} else if (remote.wallTime > this.wallTime) {\n\t\t\tthis.wallTime = remote.wallTime\n\t\t\tthis.logical = remote.logical + 1\n\t\t} else if (this.wallTime === remote.wallTime) {\n\t\t\tthis.logical = Math.max(this.logical, remote.logical) + 1\n\t\t} else {\n\t\t\t// this.wallTime > remote.wallTime && this.wallTime >= physicalTime\n\t\t\tthis.logical++\n\t\t}\n\n\t\t// Skip drift check on cold start (wallTime was 0, uninitialized) to avoid\n\t\t// false positives when the first event is a remote timestamp with a wallTime\n\t\t// that differs significantly from local physical time. After initialization,\n\t\t// all subsequent calls to now() and receive() enforce drift protection normally.\n\t\tif (!wasColdStart) {\n\t\t\tthis.checkDrift(physicalTime)\n\t\t}\n\n\t\treturn { wallTime: this.wallTime, logical: this.logical, nodeId: this.nodeId }\n\t}\n\n\t/**\n\t * Compare two timestamps. Returns negative if a < b, positive if a > b, zero if equal.\n\t * Total order: wallTime first, then logical, then nodeId (lexicographic).\n\t */\n\tstatic compare(a: HLCTimestamp, b: HLCTimestamp): number {\n\t\tif (a.wallTime !== b.wallTime) return a.wallTime - b.wallTime\n\t\tif (a.logical !== b.logical) return a.logical - b.logical\n\t\tif (a.nodeId < b.nodeId) return -1\n\t\tif (a.nodeId > b.nodeId) return 1\n\t\treturn 0\n\t}\n\n\t/**\n\t * Serialize an HLC timestamp to a string that sorts lexicographically.\n\t * Format: zero-padded wallTime:logical:nodeId\n\t */\n\tstatic serialize(ts: HLCTimestamp): string {\n\t\tconst wall = ts.wallTime.toString().padStart(15, '0')\n\t\tconst log = ts.logical.toString().padStart(5, '0')\n\t\treturn `${wall}:${log}:${ts.nodeId}`\n\t}\n\n\t/**\n\t * Deserialize an HLC timestamp from its serialized string form.\n\t */\n\tstatic deserialize(s: string): HLCTimestamp {\n\t\tconst parts = s.split(':')\n\t\tif (parts.length < 3) {\n\t\t\tthrow new Error(`Invalid HLC timestamp string: \"${s}\"`)\n\t\t}\n\t\treturn {\n\t\t\twallTime: Number.parseInt(parts[0] ?? '0', 10),\n\t\t\tlogical: Number.parseInt(parts[1] ?? '0', 10),\n\t\t\t// nodeId may contain colons, so rejoin remaining parts\n\t\t\tnodeId: parts.slice(2).join(':'),\n\t\t}\n\t}\n\n\tprivate checkDrift(physicalTime: number): void {\n\t\tconst drift = this.wallTime - physicalTime\n\t\tif (drift > DRIFT_ERROR_MS) {\n\t\t\tthrow new ClockDriftError(this.wallTime, physicalTime)\n\t\t}\n\t\tif (drift > DRIFT_WARN_MS) {\n\t\t\tthis.onDriftWarning?.(drift)\n\t\t}\n\t}\n}\n","import type { OperationInput } from '../types'\n\n/**\n * Compute the content-addressed ID for an operation using SHA-256.\n * The same operation content always produces the same hash, ensuring deduplication.\n *\n * @param input - The operation input (without id/timestamp, which are assigned separately)\n * @param timestamp - The HLC timestamp serialized as a string\n * @returns A hex-encoded SHA-256 hash\n */\nexport async function computeOperationId(\n\tinput: OperationInput,\n\ttimestamp: string,\n): Promise<string> {\n\t// Only include atomicOps when present — ensures backward compatibility\n\t// (existing operations without atomicOps produce identical hashes).\n\tconst hashInput: Record<string, unknown> = {\n\t\ttype: input.type,\n\t\tcollection: input.collection,\n\t\trecordId: input.recordId,\n\t\tdata: input.data,\n\t\ttimestamp,\n\t\tnodeId: input.nodeId,\n\t}\n\tif (input.atomicOps !== undefined && Object.keys(input.atomicOps).length > 0) {\n\t\thashInput.atomicOps = input.atomicOps\n\t}\n\tconst canonical = canonicalize(hashInput)\n\tconst encoded = new TextEncoder().encode(canonical)\n\tconst hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', encoded)\n\treturn bufferToHex(hashBuffer)\n}\n\n/**\n * Deterministic JSON serialization with sorted keys.\n * Ensures identical objects always produce identical strings regardless of property insertion order.\n *\n * @param obj - The value to serialize\n * @returns A deterministic JSON string\n */\nexport function canonicalize(obj: unknown): string {\n\tif (obj === null) {\n\t\treturn 'null'\n\t}\n\n\tif (obj === undefined) {\n\t\treturn 'null'\n\t}\n\n\tif (typeof obj !== 'object') {\n\t\treturn JSON.stringify(obj)\n\t}\n\n\tif (Array.isArray(obj)) {\n\t\tconst items = obj.map((item) => canonicalize(item))\n\t\treturn `[${items.join(',')}]`\n\t}\n\n\tconst keys = Object.keys(obj as Record<string, unknown>).sort()\n\tconst pairs = keys.map((key) => {\n\t\tconst value = (obj as Record<string, unknown>)[key]\n\t\t// Serialize undefined values as null for deterministic output\n\t\treturn `${JSON.stringify(key)}:${canonicalize(value === undefined ? null : value)}`\n\t})\n\treturn `{${pairs.join(',')}}`\n}\n\nfunction bufferToHex(buffer: ArrayBuffer): string {\n\tconst bytes = new Uint8Array(buffer)\n\treturn Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')\n}\n","import { HybridLogicalClock } from '../clock/hlc'\nimport { OperationError } from '../errors/errors'\nimport type { HLCTimestamp, Operation, OperationInput } from '../types'\nimport { computeOperationId } from './content-hash'\n\n/**\n * Creates an immutable, content-addressed Operation from the given parameters.\n * The operation is deep-frozen after creation — it cannot be modified.\n *\n * @param input - The operation parameters (without id, which is computed)\n * @param clock - The HLC clock to generate the timestamp\n * @returns A frozen Operation with a content-addressed id\n *\n * @example\n * ```typescript\n * const op = await createOperation({\n * nodeId: 'device-1',\n * type: 'insert',\n * collection: 'todos',\n * recordId: 'rec-1',\n * data: { title: 'Ship it' },\n * previousData: null,\n * sequenceNumber: 1,\n * causalDeps: [],\n * schemaVersion: 1,\n * }, clock)\n * ```\n */\nexport async function createOperation(\n\tinput: OperationInput,\n\tclock: HybridLogicalClock,\n): Promise<Operation> {\n\tvalidateOperationParams(input)\n\n\tconst timestamp = clock.now()\n\tconst serializedTs = HybridLogicalClock.serialize(timestamp)\n\tconst id = await computeOperationId(input, serializedTs)\n\n\tconst operation: Operation = {\n\t\tid,\n\t\tnodeId: input.nodeId,\n\t\ttype: input.type,\n\t\tcollection: input.collection,\n\t\trecordId: input.recordId,\n\t\tdata: input.data ? { ...input.data } : null,\n\t\tpreviousData: input.previousData ? { ...input.previousData } : null,\n\t\ttimestamp,\n\t\tsequenceNumber: input.sequenceNumber,\n\t\tcausalDeps: [...input.causalDeps],\n\t\tschemaVersion: input.schemaVersion,\n\t\t...(input.atomicOps !== undefined && Object.keys(input.atomicOps).length > 0\n\t\t\t? { atomicOps: { ...input.atomicOps } }\n\t\t\t: {}),\n\t\t...(input.transactionId !== undefined ? { transactionId: input.transactionId } : {}),\n\t\t...(input.mutationName !== undefined ? { mutationName: input.mutationName } : {}),\n\t}\n\n\treturn deepFreeze(operation)\n}\n\n/**\n * Validates operation input parameters. Throws OperationError with\n * contextual information on validation failure.\n */\nexport function validateOperationParams(input: OperationInput): void {\n\tif (!input.nodeId || typeof input.nodeId !== 'string') {\n\t\tthrow new OperationError('nodeId is required and must be a non-empty string', {\n\t\t\treceived: input.nodeId,\n\t\t})\n\t}\n\n\tif (!input.type || !['insert', 'update', 'delete'].includes(input.type)) {\n\t\tthrow new OperationError('type must be \"insert\", \"update\", or \"delete\"', {\n\t\t\treceived: input.type,\n\t\t})\n\t}\n\n\tif (!input.collection || typeof input.collection !== 'string') {\n\t\tthrow new OperationError('collection is required and must be a non-empty string', {\n\t\t\treceived: input.collection,\n\t\t})\n\t}\n\n\tif (!input.recordId || typeof input.recordId !== 'string') {\n\t\tthrow new OperationError('recordId is required and must be a non-empty string', {\n\t\t\treceived: input.recordId,\n\t\t})\n\t}\n\n\tif (input.type === 'insert' && input.data === null) {\n\t\tthrow new OperationError('insert operations must include data', {\n\t\t\ttype: input.type,\n\t\t\tcollection: input.collection,\n\t\t})\n\t}\n\n\tif (input.type === 'update' && input.data === null) {\n\t\tthrow new OperationError('update operations must include data with changed fields', {\n\t\t\ttype: input.type,\n\t\t\tcollection: input.collection,\n\t\t})\n\t}\n\n\tif (input.type === 'update' && input.previousData === null) {\n\t\tthrow new OperationError(\n\t\t\t'update operations must include previousData for 3-way merge support',\n\t\t\t{\n\t\t\t\ttype: input.type,\n\t\t\t\tcollection: input.collection,\n\t\t\t},\n\t\t)\n\t}\n\n\tif (input.type === 'delete' && input.data !== null) {\n\t\tthrow new OperationError('delete operations must have null data', {\n\t\t\ttype: input.type,\n\t\t\tcollection: input.collection,\n\t\t})\n\t}\n\n\tif (typeof input.sequenceNumber !== 'number' || input.sequenceNumber < 0) {\n\t\tthrow new OperationError('sequenceNumber must be a non-negative number', {\n\t\t\treceived: input.sequenceNumber,\n\t\t})\n\t}\n\n\tif (!Array.isArray(input.causalDeps)) {\n\t\tthrow new OperationError('causalDeps must be an array of operation IDs', {\n\t\t\treceived: typeof input.causalDeps,\n\t\t})\n\t}\n\n\tif (typeof input.schemaVersion !== 'number' || input.schemaVersion < 1) {\n\t\tthrow new OperationError('schemaVersion must be a positive number', {\n\t\t\treceived: input.schemaVersion,\n\t\t})\n\t}\n}\n\n/**\n * Verify the integrity of an operation by recomputing its content hash.\n * Returns true if the id matches the recomputed hash.\n */\nexport async function verifyOperationIntegrity(op: Operation): Promise<boolean> {\n\tconst input: OperationInput = {\n\t\tnodeId: op.nodeId,\n\t\ttype: op.type,\n\t\tcollection: op.collection,\n\t\trecordId: op.recordId,\n\t\tdata: op.data,\n\t\tpreviousData: op.previousData,\n\t\tsequenceNumber: op.sequenceNumber,\n\t\tcausalDeps: op.causalDeps,\n\t\tschemaVersion: op.schemaVersion,\n\t\t...(op.atomicOps !== undefined ? { atomicOps: op.atomicOps } : {}),\n\t}\n\tconst serializedTs = HybridLogicalClock.serialize(op.timestamp)\n\tconst expectedId = await computeOperationId(input, serializedTs)\n\treturn op.id === expectedId\n}\n\n/**\n * Type guard for Operation interface.\n */\nexport function isValidOperation(value: unknown): value is Operation {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst op = value as Record<string, unknown>\n\treturn (\n\t\ttypeof op.id === 'string' &&\n\t\ttypeof op.nodeId === 'string' &&\n\t\t(op.type === 'insert' || op.type === 'update' || op.type === 'delete') &&\n\t\ttypeof op.collection === 'string' &&\n\t\ttypeof op.recordId === 'string' &&\n\t\ttypeof op.sequenceNumber === 'number' &&\n\t\tArray.isArray(op.causalDeps) &&\n\t\ttypeof op.schemaVersion === 'number' &&\n\t\ttypeof op.timestamp === 'object' &&\n\t\top.timestamp !== null\n\t)\n}\n\nfunction deepFreeze<T>(obj: T): T {\n\tif (typeof obj !== 'object' || obj === null) return obj\n\t// Typed arrays (e.g. richtext Yjs blobs) cannot be frozen in JS engines.\n\tif (ArrayBuffer.isView(obj)) return obj\n\tObject.freeze(obj)\n\tfor (const value of Object.values(obj)) {\n\t\tif (typeof value === 'object' && value !== null && !Object.isFrozen(value)) {\n\t\t\tdeepFreeze(value)\n\t\t}\n\t}\n\treturn obj\n}\n","import { HybridLogicalClock } from '../clock/hlc'\nimport { OperationError } from '../errors/errors'\nimport type { Operation } from '../types'\n\n/**\n * Topological sort of operations based on their causal dependency DAG.\n * Uses Kahn's algorithm with a binary heap for O(V log V + E) performance.\n * Deterministic tie-breaking via HLC timestamp ensures identical output\n * regardless of input order.\n *\n * @param operations - The operations to sort\n * @returns Operations in causal order (dependencies before dependents)\n * @throws {OperationError} If a cycle is detected in the dependency graph\n */\nexport function topologicalSort(operations: Operation[]): Operation[] {\n\tif (operations.length <= 1) return [...operations]\n\n\t// Build adjacency list and in-degree map\n\tconst opMap = new Map<string, Operation>()\n\tfor (const op of operations) {\n\t\topMap.set(op.id, op)\n\t}\n\n\t// Only count edges where both ends are in the operation set\n\tconst inDegree = new Map<string, number>()\n\tconst dependents = new Map<string, string[]>()\n\n\tfor (const op of operations) {\n\t\tif (!inDegree.has(op.id)) {\n\t\t\tinDegree.set(op.id, 0)\n\t\t}\n\t\tif (!dependents.has(op.id)) {\n\t\t\tdependents.set(op.id, [])\n\t\t}\n\n\t\tfor (const depId of op.causalDeps) {\n\t\t\tif (opMap.has(depId)) {\n\t\t\t\t// depId -> op.id edge (depId must come before op.id)\n\t\t\t\tinDegree.set(op.id, (inDegree.get(op.id) ?? 0) + 1)\n\t\t\t\tconst deps = dependents.get(depId)\n\t\t\t\tif (deps) {\n\t\t\t\t\tdeps.push(op.id)\n\t\t\t\t} else {\n\t\t\t\t\tdependents.set(depId, [op.id])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Initialize min-heap with nodes that have no in-set dependencies\n\tconst heap = new MinHeap(compareByTimestamp)\n\tfor (const op of operations) {\n\t\tif ((inDegree.get(op.id) ?? 0) === 0) {\n\t\t\theap.push(op)\n\t\t}\n\t}\n\n\tconst result: Operation[] = []\n\n\twhile (heap.size > 0) {\n\t\t// Extract the earliest operation (deterministic tie-breaking by HLC)\n\t\tconst current = heap.pop()\n\t\tresult.push(current)\n\n\t\tconst deps = dependents.get(current.id) ?? []\n\n\t\tfor (const depId of deps) {\n\t\t\tconst deg = (inDegree.get(depId) ?? 0) - 1\n\t\t\tinDegree.set(depId, deg)\n\t\t\tif (deg === 0) {\n\t\t\t\tconst op = opMap.get(depId)\n\t\t\t\tif (op) heap.push(op)\n\t\t\t}\n\t\t}\n\t}\n\n\tif (result.length !== operations.length) {\n\t\tthrow new OperationError(\n\t\t\t`Cycle detected in operation dependency graph. Sorted ${result.length} of ${operations.length} operations.`,\n\t\t\t{\n\t\t\t\tsortedCount: result.length,\n\t\t\t\ttotalCount: operations.length,\n\t\t\t},\n\t\t)\n\t}\n\n\treturn result\n}\n\nfunction compareByTimestamp(a: Operation, b: Operation): number {\n\treturn HybridLogicalClock.compare(a.timestamp, b.timestamp)\n}\n\n/**\n * Binary min-heap for efficient priority queue operations.\n * push: O(log n), pop: O(log n) — replaces the O(n) sorted array approach.\n */\nclass MinHeap {\n\tprivate readonly data: Operation[] = []\n\tprivate readonly cmp: (a: Operation, b: Operation) => number\n\n\tconstructor(comparator: (a: Operation, b: Operation) => number) {\n\t\tthis.cmp = comparator\n\t}\n\n\tget size(): number {\n\t\treturn this.data.length\n\t}\n\n\tpush(item: Operation): void {\n\t\tthis.data.push(item)\n\t\tthis.bubbleUp(this.data.length - 1)\n\t}\n\n\tpop(): Operation {\n\t\tconst top = this.data[0] as Operation\n\t\tconst last = this.data.pop() as Operation\n\t\tif (this.data.length > 0) {\n\t\t\tthis.data[0] = last\n\t\t\tthis.sinkDown(0)\n\t\t}\n\t\treturn top\n\t}\n\n\tprivate bubbleUp(index: number): void {\n\t\tlet current = index\n\t\twhile (current > 0) {\n\t\t\tconst parentIndex = (current - 1) >> 1\n\t\t\tif (this.cmp(this.data[current] as Operation, this.data[parentIndex] as Operation) >= 0) break\n\t\t\tthis.swap(current, parentIndex)\n\t\t\tcurrent = parentIndex\n\t\t}\n\t}\n\n\tprivate sinkDown(index: number): void {\n\t\tconst length = this.data.length\n\t\tlet current = index\n\t\twhile (true) {\n\t\t\tlet smallest = current\n\t\t\tconst left = 2 * current + 1\n\t\t\tconst right = 2 * current + 2\n\n\t\t\tif (\n\t\t\t\tleft < length &&\n\t\t\t\tthis.cmp(this.data[left] as Operation, this.data[smallest] as Operation) < 0\n\t\t\t) {\n\t\t\t\tsmallest = left\n\t\t\t}\n\t\t\tif (\n\t\t\t\tright < length &&\n\t\t\t\tthis.cmp(this.data[right] as Operation, this.data[smallest] as Operation) < 0\n\t\t\t) {\n\t\t\t\tsmallest = right\n\t\t\t}\n\n\t\t\tif (smallest === current) break\n\t\t\tthis.swap(current, smallest)\n\t\t\tcurrent = smallest\n\t\t}\n\t}\n\n\tprivate swap(i: number, j: number): void {\n\t\tconst tmp = this.data[i] as Operation\n\t\tthis.data[i] = this.data[j] as Operation\n\t\tthis.data[j] = tmp\n\t}\n}\n"],"mappings":"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","names":[]}