@korajs/store 0.4.0 → 0.5.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.
- package/dist/adapters/better-sqlite3.d.cts +1 -1
- package/dist/adapters/better-sqlite3.d.ts +1 -1
- package/dist/adapters/indexeddb.cjs +410 -17
- package/dist/adapters/indexeddb.cjs.map +1 -1
- package/dist/adapters/indexeddb.d.cts +23 -5
- package/dist/adapters/indexeddb.d.ts +23 -5
- package/dist/adapters/indexeddb.js +163 -18
- package/dist/adapters/indexeddb.js.map +1 -1
- package/dist/adapters/sqlite-wasm-shared-host.cjs +68 -0
- package/dist/adapters/sqlite-wasm-shared-host.cjs.map +1 -0
- package/dist/adapters/sqlite-wasm-shared-host.d.cts +2 -0
- package/dist/adapters/sqlite-wasm-shared-host.d.ts +2 -0
- package/dist/adapters/sqlite-wasm-shared-host.js +66 -0
- package/dist/adapters/sqlite-wasm-shared-host.js.map +1 -0
- package/dist/adapters/sqlite-wasm-worker.cjs +34 -5
- package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.js +34 -5
- package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
- package/dist/adapters/sqlite-wasm.cjs +249 -2
- package/dist/adapters/sqlite-wasm.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm.d.cts +15 -3
- package/dist/adapters/sqlite-wasm.d.ts +15 -3
- package/dist/adapters/sqlite-wasm.js +2 -2
- package/dist/audit-trace-store-AM4EWQNZ.js +15 -0
- package/dist/backup-JN3LB4YT.js +14 -0
- package/dist/backup-JN3LB4YT.js.map +1 -0
- package/dist/chunk-56LL4XP6.js +205 -0
- package/dist/chunk-56LL4XP6.js.map +1 -0
- package/dist/chunk-6AHYGQQT.js +425 -0
- package/dist/chunk-6AHYGQQT.js.map +1 -0
- package/dist/chunk-7BPETY5Y.js +570 -0
- package/dist/chunk-7BPETY5Y.js.map +1 -0
- package/dist/chunk-AGN3CIPB.js +188 -0
- package/dist/chunk-AGN3CIPB.js.map +1 -0
- package/dist/chunk-EZSTD2XC.js +380 -0
- package/dist/chunk-EZSTD2XC.js.map +1 -0
- package/dist/chunk-MYSJN3DF.js +117 -0
- package/dist/chunk-MYSJN3DF.js.map +1 -0
- package/dist/{chunk-DXKLAQ6P.js → chunk-XO4LMPAH.js} +1 -1
- package/dist/chunk-XO4LMPAH.js.map +1 -0
- package/dist/export-audit-5GV6VRDZ.js +15 -0
- package/dist/export-audit-5GV6VRDZ.js.map +1 -0
- package/dist/index.cjs +2183 -587
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +423 -187
- package/dist/index.d.ts +423 -187
- package/dist/index.js +886 -726
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +789 -0
- package/dist/internal.cjs.map +1 -0
- package/dist/internal.d.cts +154 -0
- package/dist/internal.d.ts +154 -0
- package/dist/internal.js +48 -0
- package/dist/internal.js.map +1 -0
- package/dist/{sqlite-wasm-channel-46AOWNPM.js → sqlite-wasm-channel-HDDW6UBH.js} +2 -2
- package/dist/sqlite-wasm-channel-HDDW6UBH.js.map +1 -0
- package/dist/{sqlite-wasm-channel-Lakjuk2E.d.cts → sqlite-wasm-channel-I9y_jObg.d.cts} +1 -0
- package/dist/{sqlite-wasm-channel-Lakjuk2E.d.ts → sqlite-wasm-channel-I9y_jObg.d.ts} +1 -0
- package/dist/types-BMyHmwvn.d.ts +163 -0
- package/dist/types-CTr00g_d.d.cts +163 -0
- package/dist/types-DepnRDk_.d.cts +212 -0
- package/dist/types-DepnRDk_.d.ts +212 -0
- package/package.json +23 -2
- package/dist/chunk-DXKLAQ6P.js.map +0 -1
- package/dist/chunk-ZP5AXQ3Z.js +0 -179
- package/dist/chunk-ZP5AXQ3Z.js.map +0 -1
- package/dist/types-DF-KDSK1.d.cts +0 -106
- package/dist/types-DF-KDSK1.d.ts +0 -106
- /package/dist/{sqlite-wasm-channel-46AOWNPM.js.map → audit-trace-store-AM4EWQNZ.js.map} +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { OnDeleteAction, RelationDefinition, SchemaDefinition, HybridLogicalClock, Operation, CollectionDefinition, CausalTracker } from '@korajs/core';
|
|
2
|
+
import { S as StorageAdapter, T as Transaction, L as LocalMutationHandler, C as CollectionRecord } from './types-DepnRDk_.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A resolved relation reference: describes a relation that points TO a given collection.
|
|
6
|
+
* When a record in `targetCollection` is deleted, we must handle records in
|
|
7
|
+
* `sourceCollection` that reference it via `foreignKeyField`.
|
|
8
|
+
*/
|
|
9
|
+
interface IncomingRelation {
|
|
10
|
+
/** Name of the relation in the schema */
|
|
11
|
+
relationName: string;
|
|
12
|
+
/** Collection that holds the foreign key (the "from" side) */
|
|
13
|
+
sourceCollection: string;
|
|
14
|
+
/** Field in the source collection that references the target */
|
|
15
|
+
foreignKeyField: string;
|
|
16
|
+
/** What to do when the referenced record is deleted */
|
|
17
|
+
onDelete: OnDeleteAction;
|
|
18
|
+
/** The full relation definition */
|
|
19
|
+
relation: RelationDefinition;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for the RelationEnforcer.
|
|
24
|
+
*/
|
|
25
|
+
interface RelationEnforcerConfig {
|
|
26
|
+
schema: SchemaDefinition;
|
|
27
|
+
adapter: StorageAdapter;
|
|
28
|
+
clock: HybridLogicalClock;
|
|
29
|
+
nodeId: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Result of enforcing referential integrity on a delete operation.
|
|
33
|
+
* Contains all additional operations that were created as side effects
|
|
34
|
+
* (cascaded deletes and set-null updates).
|
|
35
|
+
*/
|
|
36
|
+
interface EnforcementResult {
|
|
37
|
+
/** Additional operations created by cascading deletes and set-null updates */
|
|
38
|
+
operations: Operation[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Enforces referential integrity constraints during local delete operations.
|
|
42
|
+
*
|
|
43
|
+
* When a record is deleted, this enforcer checks all relations that reference
|
|
44
|
+
* the deleted record's collection and applies the appropriate onDelete policy:
|
|
45
|
+
*
|
|
46
|
+
* - **cascade**: Recursively deletes all referencing records
|
|
47
|
+
* - **set-null**: Sets the foreign key to null on all referencing records
|
|
48
|
+
* - **restrict**: Throws a ReferentialIntegrityError if any references exist
|
|
49
|
+
* - **no-action**: Does nothing (the foreign key is left dangling)
|
|
50
|
+
*
|
|
51
|
+
* The enforcer operates within a provided transaction to ensure atomicity.
|
|
52
|
+
* All generated operations (cascaded deletes, set-null updates) share a
|
|
53
|
+
* causal dependency chain through the original delete operation.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const enforcer = new RelationEnforcer({
|
|
58
|
+
* schema, adapter, clock, nodeId,
|
|
59
|
+
* allocateSequenceNumber: async () => ++seq,
|
|
60
|
+
* })
|
|
61
|
+
* const result = await enforcer.enforceDelete(
|
|
62
|
+
* 'projects', 'proj-1', tx, ['delete-op-id']
|
|
63
|
+
* )
|
|
64
|
+
* // result.operations contains any cascaded delete/update ops
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare class RelationEnforcer {
|
|
68
|
+
private readonly lookup;
|
|
69
|
+
private readonly schema;
|
|
70
|
+
private readonly adapter;
|
|
71
|
+
private readonly clock;
|
|
72
|
+
private readonly nodeId;
|
|
73
|
+
constructor(config: RelationEnforcerConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Enforce referential integrity after deleting a record.
|
|
76
|
+
*
|
|
77
|
+
* Must be called within a transaction. The transaction handle is used
|
|
78
|
+
* for all cascaded writes to ensure atomicity.
|
|
79
|
+
*
|
|
80
|
+
* @param collection - The collection the deleted record belongs to
|
|
81
|
+
* @param recordId - The ID of the deleted record
|
|
82
|
+
* @param tx - The active transaction handle
|
|
83
|
+
* @param causalDeps - Causal dependencies for generated operations
|
|
84
|
+
* @returns All additional operations created as side effects
|
|
85
|
+
* @throws {ReferentialIntegrityError} If a 'restrict' policy is violated
|
|
86
|
+
*/
|
|
87
|
+
enforceDelete(collection: string, recordId: string, tx: Transaction, causalDeps: string[]): Promise<EnforcementResult>;
|
|
88
|
+
/**
|
|
89
|
+
* Enforce a single relation's onDelete policy.
|
|
90
|
+
*/
|
|
91
|
+
private enforceRelation;
|
|
92
|
+
/**
|
|
93
|
+
* Cascade: delete all records in the source collection that reference
|
|
94
|
+
* the deleted record, then recursively cascade those deletes.
|
|
95
|
+
*/
|
|
96
|
+
private enforceCascade;
|
|
97
|
+
/**
|
|
98
|
+
* Set-null: update all referencing records to set the foreign key to null.
|
|
99
|
+
*/
|
|
100
|
+
private enforceSetNull;
|
|
101
|
+
/**
|
|
102
|
+
* Restrict: refuse the delete if any referencing records exist.
|
|
103
|
+
*/
|
|
104
|
+
private enforceRestrict;
|
|
105
|
+
/**
|
|
106
|
+
* Get the relation lookup map for external use (e.g., by the merge engine).
|
|
107
|
+
*/
|
|
108
|
+
getRelationLookup(): Map<string, IncomingRelation[]>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Callback invoked after a mutation so the Store can notify subscriptions.
|
|
113
|
+
*/
|
|
114
|
+
type MutationCallback = (collection: string, operation: Operation) => void;
|
|
115
|
+
/**
|
|
116
|
+
* Collection provides CRUD operations on a single schema collection.
|
|
117
|
+
* Delegates to {@link LocalMutationHandler} when configured (unified apply pipeline),
|
|
118
|
+
* otherwise uses shared mutation executors directly.
|
|
119
|
+
*/
|
|
120
|
+
declare class Collection {
|
|
121
|
+
private readonly name;
|
|
122
|
+
private readonly definition;
|
|
123
|
+
private readonly schema;
|
|
124
|
+
private readonly adapter;
|
|
125
|
+
private readonly clock;
|
|
126
|
+
private readonly nodeId;
|
|
127
|
+
private readonly allocateSequenceNumber;
|
|
128
|
+
private readonly onMutation;
|
|
129
|
+
private readonly relationEnforcer;
|
|
130
|
+
private mutationHandler;
|
|
131
|
+
private readonly causalTracker;
|
|
132
|
+
constructor(name: string, definition: CollectionDefinition, schema: SchemaDefinition, adapter: StorageAdapter, clock: HybridLogicalClock, nodeId: string, allocateSequenceNumber: () => Promise<number>, onMutation: MutationCallback, relationEnforcer: RelationEnforcer | null, mutationHandler: LocalMutationHandler | null, causalTracker: CausalTracker | null);
|
|
133
|
+
private mutationContext;
|
|
134
|
+
insert(data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
135
|
+
findById(id: string): Promise<CollectionRecord | null>;
|
|
136
|
+
update(id: string, data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
137
|
+
delete(id: string): Promise<void>;
|
|
138
|
+
getName(): string;
|
|
139
|
+
getDefinition(): CollectionDefinition;
|
|
140
|
+
/** Replace the mutation handler (e.g. after ApplyPipeline is wired in createApp). */
|
|
141
|
+
setMutationHandler(handler: LocalMutationHandler | null): void;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Shared context for executing local collection mutations.
|
|
146
|
+
*/
|
|
147
|
+
interface LocalMutationContext {
|
|
148
|
+
readonly collection: string;
|
|
149
|
+
readonly definition: CollectionDefinition;
|
|
150
|
+
readonly schema: SchemaDefinition;
|
|
151
|
+
readonly adapter: StorageAdapter;
|
|
152
|
+
readonly clock: HybridLogicalClock;
|
|
153
|
+
readonly nodeId: string;
|
|
154
|
+
readonly allocateSequenceNumber: () => Promise<number>;
|
|
155
|
+
readonly onMutation: MutationCallback;
|
|
156
|
+
readonly relationEnforcer: RelationEnforcer | null;
|
|
157
|
+
readonly causalTracker: CausalTracker | null;
|
|
158
|
+
readonly inTransaction: boolean;
|
|
159
|
+
/** Additional parent op ids (e.g. referential cascade from a delete). */
|
|
160
|
+
readonly extraCausalDeps?: string[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export { Collection as C, type LocalMutationContext as L, RelationEnforcer as R };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { OnDeleteAction, RelationDefinition, SchemaDefinition, HybridLogicalClock, Operation, CollectionDefinition, CausalTracker } from '@korajs/core';
|
|
2
|
+
import { S as StorageAdapter, T as Transaction, L as LocalMutationHandler, C as CollectionRecord } from './types-DepnRDk_.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A resolved relation reference: describes a relation that points TO a given collection.
|
|
6
|
+
* When a record in `targetCollection` is deleted, we must handle records in
|
|
7
|
+
* `sourceCollection` that reference it via `foreignKeyField`.
|
|
8
|
+
*/
|
|
9
|
+
interface IncomingRelation {
|
|
10
|
+
/** Name of the relation in the schema */
|
|
11
|
+
relationName: string;
|
|
12
|
+
/** Collection that holds the foreign key (the "from" side) */
|
|
13
|
+
sourceCollection: string;
|
|
14
|
+
/** Field in the source collection that references the target */
|
|
15
|
+
foreignKeyField: string;
|
|
16
|
+
/** What to do when the referenced record is deleted */
|
|
17
|
+
onDelete: OnDeleteAction;
|
|
18
|
+
/** The full relation definition */
|
|
19
|
+
relation: RelationDefinition;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for the RelationEnforcer.
|
|
24
|
+
*/
|
|
25
|
+
interface RelationEnforcerConfig {
|
|
26
|
+
schema: SchemaDefinition;
|
|
27
|
+
adapter: StorageAdapter;
|
|
28
|
+
clock: HybridLogicalClock;
|
|
29
|
+
nodeId: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Result of enforcing referential integrity on a delete operation.
|
|
33
|
+
* Contains all additional operations that were created as side effects
|
|
34
|
+
* (cascaded deletes and set-null updates).
|
|
35
|
+
*/
|
|
36
|
+
interface EnforcementResult {
|
|
37
|
+
/** Additional operations created by cascading deletes and set-null updates */
|
|
38
|
+
operations: Operation[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Enforces referential integrity constraints during local delete operations.
|
|
42
|
+
*
|
|
43
|
+
* When a record is deleted, this enforcer checks all relations that reference
|
|
44
|
+
* the deleted record's collection and applies the appropriate onDelete policy:
|
|
45
|
+
*
|
|
46
|
+
* - **cascade**: Recursively deletes all referencing records
|
|
47
|
+
* - **set-null**: Sets the foreign key to null on all referencing records
|
|
48
|
+
* - **restrict**: Throws a ReferentialIntegrityError if any references exist
|
|
49
|
+
* - **no-action**: Does nothing (the foreign key is left dangling)
|
|
50
|
+
*
|
|
51
|
+
* The enforcer operates within a provided transaction to ensure atomicity.
|
|
52
|
+
* All generated operations (cascaded deletes, set-null updates) share a
|
|
53
|
+
* causal dependency chain through the original delete operation.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const enforcer = new RelationEnforcer({
|
|
58
|
+
* schema, adapter, clock, nodeId,
|
|
59
|
+
* allocateSequenceNumber: async () => ++seq,
|
|
60
|
+
* })
|
|
61
|
+
* const result = await enforcer.enforceDelete(
|
|
62
|
+
* 'projects', 'proj-1', tx, ['delete-op-id']
|
|
63
|
+
* )
|
|
64
|
+
* // result.operations contains any cascaded delete/update ops
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare class RelationEnforcer {
|
|
68
|
+
private readonly lookup;
|
|
69
|
+
private readonly schema;
|
|
70
|
+
private readonly adapter;
|
|
71
|
+
private readonly clock;
|
|
72
|
+
private readonly nodeId;
|
|
73
|
+
constructor(config: RelationEnforcerConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Enforce referential integrity after deleting a record.
|
|
76
|
+
*
|
|
77
|
+
* Must be called within a transaction. The transaction handle is used
|
|
78
|
+
* for all cascaded writes to ensure atomicity.
|
|
79
|
+
*
|
|
80
|
+
* @param collection - The collection the deleted record belongs to
|
|
81
|
+
* @param recordId - The ID of the deleted record
|
|
82
|
+
* @param tx - The active transaction handle
|
|
83
|
+
* @param causalDeps - Causal dependencies for generated operations
|
|
84
|
+
* @returns All additional operations created as side effects
|
|
85
|
+
* @throws {ReferentialIntegrityError} If a 'restrict' policy is violated
|
|
86
|
+
*/
|
|
87
|
+
enforceDelete(collection: string, recordId: string, tx: Transaction, causalDeps: string[]): Promise<EnforcementResult>;
|
|
88
|
+
/**
|
|
89
|
+
* Enforce a single relation's onDelete policy.
|
|
90
|
+
*/
|
|
91
|
+
private enforceRelation;
|
|
92
|
+
/**
|
|
93
|
+
* Cascade: delete all records in the source collection that reference
|
|
94
|
+
* the deleted record, then recursively cascade those deletes.
|
|
95
|
+
*/
|
|
96
|
+
private enforceCascade;
|
|
97
|
+
/**
|
|
98
|
+
* Set-null: update all referencing records to set the foreign key to null.
|
|
99
|
+
*/
|
|
100
|
+
private enforceSetNull;
|
|
101
|
+
/**
|
|
102
|
+
* Restrict: refuse the delete if any referencing records exist.
|
|
103
|
+
*/
|
|
104
|
+
private enforceRestrict;
|
|
105
|
+
/**
|
|
106
|
+
* Get the relation lookup map for external use (e.g., by the merge engine).
|
|
107
|
+
*/
|
|
108
|
+
getRelationLookup(): Map<string, IncomingRelation[]>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Callback invoked after a mutation so the Store can notify subscriptions.
|
|
113
|
+
*/
|
|
114
|
+
type MutationCallback = (collection: string, operation: Operation) => void;
|
|
115
|
+
/**
|
|
116
|
+
* Collection provides CRUD operations on a single schema collection.
|
|
117
|
+
* Delegates to {@link LocalMutationHandler} when configured (unified apply pipeline),
|
|
118
|
+
* otherwise uses shared mutation executors directly.
|
|
119
|
+
*/
|
|
120
|
+
declare class Collection {
|
|
121
|
+
private readonly name;
|
|
122
|
+
private readonly definition;
|
|
123
|
+
private readonly schema;
|
|
124
|
+
private readonly adapter;
|
|
125
|
+
private readonly clock;
|
|
126
|
+
private readonly nodeId;
|
|
127
|
+
private readonly allocateSequenceNumber;
|
|
128
|
+
private readonly onMutation;
|
|
129
|
+
private readonly relationEnforcer;
|
|
130
|
+
private mutationHandler;
|
|
131
|
+
private readonly causalTracker;
|
|
132
|
+
constructor(name: string, definition: CollectionDefinition, schema: SchemaDefinition, adapter: StorageAdapter, clock: HybridLogicalClock, nodeId: string, allocateSequenceNumber: () => Promise<number>, onMutation: MutationCallback, relationEnforcer: RelationEnforcer | null, mutationHandler: LocalMutationHandler | null, causalTracker: CausalTracker | null);
|
|
133
|
+
private mutationContext;
|
|
134
|
+
insert(data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
135
|
+
findById(id: string): Promise<CollectionRecord | null>;
|
|
136
|
+
update(id: string, data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
137
|
+
delete(id: string): Promise<void>;
|
|
138
|
+
getName(): string;
|
|
139
|
+
getDefinition(): CollectionDefinition;
|
|
140
|
+
/** Replace the mutation handler (e.g. after ApplyPipeline is wired in createApp). */
|
|
141
|
+
setMutationHandler(handler: LocalMutationHandler | null): void;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Shared context for executing local collection mutations.
|
|
146
|
+
*/
|
|
147
|
+
interface LocalMutationContext {
|
|
148
|
+
readonly collection: string;
|
|
149
|
+
readonly definition: CollectionDefinition;
|
|
150
|
+
readonly schema: SchemaDefinition;
|
|
151
|
+
readonly adapter: StorageAdapter;
|
|
152
|
+
readonly clock: HybridLogicalClock;
|
|
153
|
+
readonly nodeId: string;
|
|
154
|
+
readonly allocateSequenceNumber: () => Promise<number>;
|
|
155
|
+
readonly onMutation: MutationCallback;
|
|
156
|
+
readonly relationEnforcer: RelationEnforcer | null;
|
|
157
|
+
readonly causalTracker: CausalTracker | null;
|
|
158
|
+
readonly inTransaction: boolean;
|
|
159
|
+
/** Additional parent op ids (e.g. referential cascade from a delete). */
|
|
160
|
+
readonly extraCausalDeps?: string[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export { Collection as C, type LocalMutationContext as L, RelationEnforcer as R };
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { SchemaDefinition, Operation, KoraEventEmitter } from '@korajs/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transaction interface for executing multiple operations atomically.
|
|
5
|
+
*/
|
|
6
|
+
interface Transaction {
|
|
7
|
+
execute(sql: string, params?: unknown[]): Promise<void>;
|
|
8
|
+
query<T>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Migration plan containing SQL statements and optional data transforms.
|
|
12
|
+
*/
|
|
13
|
+
interface MigrationPlan {
|
|
14
|
+
statements: string[];
|
|
15
|
+
transforms?: Array<(row: Record<string, unknown>) => Record<string, unknown>>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Storage adapter interface. All storage backends must implement this.
|
|
19
|
+
* Operations are async to support both sync (better-sqlite3) and async (IndexedDB, WASM) backends.
|
|
20
|
+
*/
|
|
21
|
+
interface StorageAdapter {
|
|
22
|
+
/** Open or create the database */
|
|
23
|
+
open(schema: SchemaDefinition): Promise<void>;
|
|
24
|
+
/** Close the database and release resources */
|
|
25
|
+
close(): Promise<void>;
|
|
26
|
+
/** Execute a write query (INSERT, UPDATE, DELETE) within a transaction */
|
|
27
|
+
execute(sql: string, params?: unknown[]): Promise<void>;
|
|
28
|
+
/** Execute a read query (SELECT) */
|
|
29
|
+
query<T>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
30
|
+
/** Execute multiple operations atomically */
|
|
31
|
+
transaction(fn: (tx: Transaction) => Promise<void>): Promise<void>;
|
|
32
|
+
/** Apply a schema migration */
|
|
33
|
+
migrate(from: number, to: number, migration: MigrationPlan): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Buffered SQL + operation produced during a transaction (before commit).
|
|
37
|
+
*/
|
|
38
|
+
interface TransactionBufferedEntry {
|
|
39
|
+
operation: Operation;
|
|
40
|
+
commands: Array<{
|
|
41
|
+
sql: string;
|
|
42
|
+
params: unknown[];
|
|
43
|
+
}>;
|
|
44
|
+
collection: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Batch passed to {@link LocalMutationHandler.commitTransaction} on commit.
|
|
48
|
+
*/
|
|
49
|
+
interface TransactionCommitBatch {
|
|
50
|
+
entries: TransactionBufferedEntry[];
|
|
51
|
+
transactionId: string;
|
|
52
|
+
mutationName?: string;
|
|
53
|
+
}
|
|
54
|
+
interface TransactionCommitResult {
|
|
55
|
+
operations: Operation[];
|
|
56
|
+
affectedCollections: Set<string>;
|
|
57
|
+
}
|
|
58
|
+
interface LocalMutationHandler {
|
|
59
|
+
insert(collection: string, data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
60
|
+
update(collection: string, id: string, data: Record<string, unknown>): Promise<CollectionRecord>;
|
|
61
|
+
delete(collection: string, id: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Commit a buffered transaction through the unified apply pipeline.
|
|
64
|
+
* When omitted, the store uses the built-in SQL commit path.
|
|
65
|
+
*/
|
|
66
|
+
commitTransaction?(batch: TransactionCommitBatch): Promise<TransactionCommitResult>;
|
|
67
|
+
}
|
|
68
|
+
type StoreIsolation = 'shared' | 'per-tab';
|
|
69
|
+
interface StoreConfig {
|
|
70
|
+
schema: SchemaDefinition;
|
|
71
|
+
adapter: StorageAdapter;
|
|
72
|
+
/** Database name used for per-tab node id keys. Defaults to 'kora-db'. */
|
|
73
|
+
dbName?: string;
|
|
74
|
+
/**
|
|
75
|
+
* `shared` (default): one node id per database in `_kora_meta`.
|
|
76
|
+
* `per-tab`: unique node id per browser tab via sessionStorage.
|
|
77
|
+
*/
|
|
78
|
+
isolation?: StoreIsolation;
|
|
79
|
+
/** Optional node ID. If omitted, one is generated or loaded from the database. */
|
|
80
|
+
nodeId?: string;
|
|
81
|
+
/** Optional event emitter. When provided, local mutations emit 'operation:created' events. */
|
|
82
|
+
emitter?: KoraEventEmitter;
|
|
83
|
+
/** Routes local mutations through a unified apply pipeline when provided. */
|
|
84
|
+
localMutationHandler?: LocalMutationHandler;
|
|
85
|
+
/** Called when a reactive query subscription is registered (for sync query subsets). */
|
|
86
|
+
onQuerySubscribed?: (descriptor: QueryDescriptor) => () => void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Operators for where clause conditions.
|
|
90
|
+
*/
|
|
91
|
+
interface WhereOperators {
|
|
92
|
+
$eq?: unknown;
|
|
93
|
+
$ne?: unknown;
|
|
94
|
+
$gt?: number | string;
|
|
95
|
+
$gte?: number | string;
|
|
96
|
+
$lt?: number | string;
|
|
97
|
+
$lte?: number | string;
|
|
98
|
+
$in?: unknown[];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Where clause: field name to value (shorthand for $eq) or WhereOperators.
|
|
102
|
+
*/
|
|
103
|
+
type WhereClause = Record<string, unknown | WhereOperators>;
|
|
104
|
+
/**
|
|
105
|
+
* Order direction for sorting query results.
|
|
106
|
+
*/
|
|
107
|
+
type OrderByDirection = 'asc' | 'desc';
|
|
108
|
+
/**
|
|
109
|
+
* Order-by clause: field name and optional direction.
|
|
110
|
+
*/
|
|
111
|
+
interface OrderByClause {
|
|
112
|
+
field: string;
|
|
113
|
+
direction: OrderByDirection;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Internal representation of a query to be compiled to SQL.
|
|
117
|
+
*/
|
|
118
|
+
interface QueryDescriptor {
|
|
119
|
+
collection: string;
|
|
120
|
+
where: WhereClause;
|
|
121
|
+
orderBy: OrderByClause[];
|
|
122
|
+
limit?: number;
|
|
123
|
+
offset?: number;
|
|
124
|
+
/** Relation names to include in results (for relational queries). */
|
|
125
|
+
include?: string[];
|
|
126
|
+
/** Resolved collection names for included relations (for subscription tracking). */
|
|
127
|
+
includeCollections?: string[];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Callback for reactive subscriptions. Receives the current result set.
|
|
131
|
+
*/
|
|
132
|
+
type SubscriptionCallback<T> = (results: T[]) => void;
|
|
133
|
+
/**
|
|
134
|
+
* Serialized row in the operations log table.
|
|
135
|
+
*/
|
|
136
|
+
interface OperationRow {
|
|
137
|
+
id: string;
|
|
138
|
+
node_id: string;
|
|
139
|
+
type: string;
|
|
140
|
+
record_id: string;
|
|
141
|
+
data: string | null;
|
|
142
|
+
previous_data: string | null;
|
|
143
|
+
timestamp: string;
|
|
144
|
+
sequence_number: number;
|
|
145
|
+
causal_deps: string;
|
|
146
|
+
schema_version: number;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Record type returned from collection queries.
|
|
150
|
+
* Includes the id and mapped metadata fields.
|
|
151
|
+
*/
|
|
152
|
+
interface CollectionRecord {
|
|
153
|
+
id: string;
|
|
154
|
+
createdAt: number;
|
|
155
|
+
updatedAt: number;
|
|
156
|
+
[key: string]: unknown;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Internal row shape returned from SQL queries on collection tables.
|
|
161
|
+
*/
|
|
162
|
+
interface RawCollectionRow {
|
|
163
|
+
id: string;
|
|
164
|
+
_created_at: number;
|
|
165
|
+
_updated_at: number;
|
|
166
|
+
_version?: string;
|
|
167
|
+
_deleted: number;
|
|
168
|
+
[key: string]: unknown;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* A registered subscription tracked by the SubscriptionManager.
|
|
172
|
+
*/
|
|
173
|
+
interface Subscription<T = CollectionRecord> {
|
|
174
|
+
id: string;
|
|
175
|
+
descriptor: QueryDescriptor;
|
|
176
|
+
callback: SubscriptionCallback<T>;
|
|
177
|
+
executeFn: () => Promise<T[]>;
|
|
178
|
+
lastResults: T[];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Options for applying a remote operation to materialized storage.
|
|
183
|
+
*/
|
|
184
|
+
interface ApplyRemoteOptions {
|
|
185
|
+
/** When true, a winning remote update clears soft-delete on the row. */
|
|
186
|
+
reactivateIfDeleted?: boolean;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Snapshot of a materialized row, including soft-deleted records.
|
|
190
|
+
*/
|
|
191
|
+
interface MaterializedRowSnapshot {
|
|
192
|
+
/** Deserialized application record (excludes tombstone metadata). */
|
|
193
|
+
record: CollectionRecord;
|
|
194
|
+
/** Whether the row is soft-deleted (_deleted = 1). */
|
|
195
|
+
deleted: boolean;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Metadata row from _kora_meta table.
|
|
199
|
+
*/
|
|
200
|
+
interface MetaRow {
|
|
201
|
+
key: string;
|
|
202
|
+
value: string;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Version vector row from _kora_version_vector table.
|
|
206
|
+
*/
|
|
207
|
+
interface VersionVectorRow {
|
|
208
|
+
node_id: string;
|
|
209
|
+
sequence_number: number;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export type { ApplyRemoteOptions as A, CollectionRecord as C, LocalMutationHandler as L, MigrationPlan as M, OperationRow as O, QueryDescriptor as Q, RawCollectionRow as R, StorageAdapter as S, Transaction as T, VersionVectorRow as V, WhereClause as W, MetaRow as a, Subscription as b, SubscriptionCallback as c, OrderByDirection as d, StoreConfig as e, MaterializedRowSnapshot as f, OrderByClause as g, StoreIsolation as h, TransactionBufferedEntry as i, TransactionCommitBatch as j, TransactionCommitResult as k, WhereOperators as l };
|