@prabhask5/stellar-engine 1.1.18 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +448 -321
- package/dist/bin/commands.d.ts +14 -0
- package/dist/bin/commands.d.ts.map +1 -0
- package/dist/bin/commands.js +68 -0
- package/dist/bin/commands.js.map +1 -0
- package/dist/bin/install-pwa.d.ts +20 -6
- package/dist/bin/install-pwa.d.ts.map +1 -1
- package/dist/bin/install-pwa.js +111 -184
- package/dist/bin/install-pwa.js.map +1 -1
- package/dist/config.d.ts +67 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +265 -24
- package/dist/config.js.map +1 -1
- package/dist/crdt/awareness.d.ts +128 -0
- package/dist/crdt/awareness.d.ts.map +1 -0
- package/dist/crdt/awareness.js +284 -0
- package/dist/crdt/awareness.js.map +1 -0
- package/dist/crdt/channel.d.ts +165 -0
- package/dist/crdt/channel.d.ts.map +1 -0
- package/dist/crdt/channel.js +522 -0
- package/dist/crdt/channel.js.map +1 -0
- package/dist/crdt/config.d.ts +58 -0
- package/dist/crdt/config.d.ts.map +1 -0
- package/dist/crdt/config.js +123 -0
- package/dist/crdt/config.js.map +1 -0
- package/dist/crdt/helpers.d.ts +104 -0
- package/dist/crdt/helpers.d.ts.map +1 -0
- package/dist/crdt/helpers.js +116 -0
- package/dist/crdt/helpers.js.map +1 -0
- package/dist/crdt/offline.d.ts +58 -0
- package/dist/crdt/offline.d.ts.map +1 -0
- package/dist/crdt/offline.js +130 -0
- package/dist/crdt/offline.js.map +1 -0
- package/dist/crdt/persistence.d.ts +65 -0
- package/dist/crdt/persistence.d.ts.map +1 -0
- package/dist/crdt/persistence.js +171 -0
- package/dist/crdt/persistence.js.map +1 -0
- package/dist/crdt/provider.d.ts +109 -0
- package/dist/crdt/provider.d.ts.map +1 -0
- package/dist/crdt/provider.js +543 -0
- package/dist/crdt/provider.js.map +1 -0
- package/dist/crdt/store.d.ts +111 -0
- package/dist/crdt/store.d.ts.map +1 -0
- package/dist/crdt/store.js +158 -0
- package/dist/crdt/store.js.map +1 -0
- package/dist/crdt/types.d.ts +281 -0
- package/dist/crdt/types.d.ts.map +1 -0
- package/dist/crdt/types.js +26 -0
- package/dist/crdt/types.js.map +1 -0
- package/dist/database.d.ts +66 -1
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +133 -7
- package/dist/database.js.map +1 -1
- package/dist/diagnostics.d.ts +75 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +114 -2
- package/dist/diagnostics.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +21 -1
- package/dist/engine.js.map +1 -1
- package/dist/entries/crdt.d.ts +32 -0
- package/dist/entries/crdt.d.ts.map +1 -0
- package/dist/entries/crdt.js +52 -0
- package/dist/entries/crdt.js.map +1 -0
- package/dist/entries/types.d.ts +5 -3
- package/dist/entries/types.d.ts.map +1 -1
- package/dist/entries/utils.d.ts +1 -0
- package/dist/entries/utils.d.ts.map +1 -1
- package/dist/entries/utils.js +8 -0
- package/dist/entries/utils.js.map +1 -1
- package/dist/entries/vite.d.ts +1 -1
- package/dist/entries/vite.d.ts.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +150 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +891 -0
- package/dist/schema.js.map +1 -0
- package/dist/sw/build/vite-plugin.d.ts +93 -18
- package/dist/sw/build/vite-plugin.d.ts.map +1 -1
- package/dist/sw/build/vite-plugin.js +356 -22
- package/dist/sw/build/vite-plugin.js.map +1 -1
- package/dist/types.d.ts +139 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -3
- package/dist/operations.d.ts +0 -73
- package/dist/operations.d.ts.map +0 -1
- package/dist/operations.js +0 -227
- package/dist/operations.js.map +0 -1
- package/dist/reconnectHandler.d.ts +0 -16
- package/dist/reconnectHandler.d.ts.map +0 -1
- package/dist/reconnectHandler.js +0 -21
- package/dist/reconnectHandler.js.map +0 -1
package/dist/config.d.ts
CHANGED
|
@@ -23,37 +23,67 @@
|
|
|
23
23
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
24
24
|
import type { Session } from '@supabase/supabase-js';
|
|
25
25
|
import type Dexie from 'dexie';
|
|
26
|
-
import type { SingleUserGateType } from './types';
|
|
26
|
+
import type { SingleUserGateType, SchemaDefinition, AuthConfig } from './types';
|
|
27
|
+
import type { CRDTConfig } from './crdt/types';
|
|
27
28
|
import type { DemoConfig } from './demo';
|
|
28
29
|
import { type DatabaseConfig } from './database';
|
|
29
30
|
/**
|
|
30
31
|
* Top-level configuration for the sync engine.
|
|
31
32
|
*
|
|
32
|
-
* Passed to {@link initEngine} at app startup.
|
|
33
|
-
*
|
|
33
|
+
* Passed to {@link initEngine} at app startup. Supports two configuration modes:
|
|
34
|
+
*
|
|
35
|
+
* 1. **Schema-driven** (recommended) — Provide a `schema` object. The engine
|
|
36
|
+
* auto-generates `tables`, Dexie stores, versioning, and database naming.
|
|
37
|
+
* 2. **Manual** (backward compat) — Provide explicit `tables` and `database`.
|
|
38
|
+
*
|
|
39
|
+
* The two modes are mutually exclusive (`schema` vs `tables` + `database`).
|
|
34
40
|
*
|
|
35
41
|
* @example
|
|
42
|
+
* // Schema-driven (new, recommended):
|
|
43
|
+
* initEngine({
|
|
44
|
+
* prefix: 'myapp',
|
|
45
|
+
* schema: {
|
|
46
|
+
* goals: 'goal_list_id, order',
|
|
47
|
+
* focus_settings: { singleton: true },
|
|
48
|
+
* },
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* // Manual (backward compat):
|
|
36
52
|
* initEngine({
|
|
37
53
|
* prefix: 'myapp',
|
|
38
|
-
* tables: [
|
|
39
|
-
*
|
|
40
|
-
* ],
|
|
41
|
-
* database: { name: 'myapp-db', versions: [{ version: 1, stores: { goals: 'id,user_id' } }] },
|
|
42
|
-
* syncDebounceMs: 1000,
|
|
54
|
+
* tables: [...],
|
|
55
|
+
* database: { name: 'myapp-db', versions: [...] },
|
|
43
56
|
* });
|
|
44
57
|
*/
|
|
45
58
|
export interface SyncEngineConfig {
|
|
46
|
-
/** Per-table sync configuration
|
|
59
|
+
/** Per-table sync configuration. Auto-populated when using `schema`. */
|
|
47
60
|
tables: TableConfig[];
|
|
48
61
|
/** Application prefix — used for localStorage keys, debug logging, etc. */
|
|
49
62
|
prefix: string;
|
|
63
|
+
/**
|
|
64
|
+
* Declarative schema definition — replaces both `tables` and `database`.
|
|
65
|
+
*
|
|
66
|
+
* Each key is a Supabase table name (snake_case). Values are either a string
|
|
67
|
+
* of Dexie indexes or a {@link SchemaTableConfig} object for full control.
|
|
68
|
+
* Mutually exclusive with `tables` + `database`.
|
|
69
|
+
*
|
|
70
|
+
* @see {@link SchemaDefinition} for the full type definition
|
|
71
|
+
*/
|
|
72
|
+
schema?: SchemaDefinition;
|
|
73
|
+
/**
|
|
74
|
+
* Override the auto-generated database name when using `schema`.
|
|
75
|
+
*
|
|
76
|
+
* By default, the database is named `${prefix}DB` (e.g., `stellarDB`).
|
|
77
|
+
* Use this to keep an existing database name for data continuity.
|
|
78
|
+
*/
|
|
79
|
+
databaseName?: string;
|
|
50
80
|
/** Provide a pre-created Dexie instance (backward compat). Mutually exclusive with `database`. */
|
|
51
81
|
db?: Dexie;
|
|
52
82
|
/** Provide a pre-created Supabase client (backward compat). Engine creates one internally if not provided. */
|
|
53
83
|
supabase?: SupabaseClient;
|
|
54
84
|
/** Engine creates and owns the Dexie instance when this is provided. */
|
|
55
85
|
database?: DatabaseConfig;
|
|
56
|
-
/** Authentication configuration. */
|
|
86
|
+
/** Authentication configuration (nested/internal form). */
|
|
57
87
|
auth?: {
|
|
58
88
|
/** Single-user mode gate configuration. */
|
|
59
89
|
singleUser?: {
|
|
@@ -104,6 +134,18 @@ export interface SyncEngineConfig {
|
|
|
104
134
|
* @see {@link DemoConfig} for the configuration shape
|
|
105
135
|
*/
|
|
106
136
|
demo?: DemoConfig;
|
|
137
|
+
/**
|
|
138
|
+
* CRDT collaborative editing configuration.
|
|
139
|
+
*
|
|
140
|
+
* When provided, enables the CRDT subsystem — creates IndexedDB tables for
|
|
141
|
+
* CRDT document storage and allows use of the `@prabhask5/stellar-engine/crdt` API.
|
|
142
|
+
* When omitted, no CRDT tables are created and CRDT imports will throw.
|
|
143
|
+
*
|
|
144
|
+
* Pass `true` as shorthand for `{}` (all defaults).
|
|
145
|
+
*
|
|
146
|
+
* @see {@link CRDTConfig} for available configuration options
|
|
147
|
+
*/
|
|
148
|
+
crdt?: CRDTConfig | true;
|
|
107
149
|
}
|
|
108
150
|
/**
|
|
109
151
|
* Per-table sync configuration.
|
|
@@ -154,7 +196,21 @@ export interface TableConfig {
|
|
|
154
196
|
* database: { name: 'myapp-db', versions: [...] },
|
|
155
197
|
* });
|
|
156
198
|
*/
|
|
157
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Input type for {@link initEngine}.
|
|
201
|
+
*
|
|
202
|
+
* Differs from {@link SyncEngineConfig} in two ways:
|
|
203
|
+
* - `tables` is optional (auto-generated when `schema` is provided)
|
|
204
|
+
* - `auth` accepts either the flat {@link AuthConfig} or the nested internal form
|
|
205
|
+
*
|
|
206
|
+
* The flat auth form is detected by the absence of a `singleUser` key and is
|
|
207
|
+
* normalized to the nested structure before being stored on the config singleton.
|
|
208
|
+
*/
|
|
209
|
+
export type InitEngineInput = Omit<SyncEngineConfig, 'tables' | 'auth'> & {
|
|
210
|
+
tables?: TableConfig[];
|
|
211
|
+
auth?: AuthConfig | SyncEngineConfig['auth'];
|
|
212
|
+
};
|
|
213
|
+
export declare function initEngine(config: InitEngineInput): void;
|
|
158
214
|
/**
|
|
159
215
|
* Wait for the database to be fully opened and upgraded.
|
|
160
216
|
*
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -25,7 +25,8 @@ import { _setDeviceIdPrefix } from './deviceId';
|
|
|
25
25
|
import { _setClientPrefix } from './supabase/client';
|
|
26
26
|
import { _setConfigPrefix } from './runtime/runtimeConfig';
|
|
27
27
|
import { registerDemoConfig, _setDemoPrefix, isDemoMode } from './demo';
|
|
28
|
-
import { createDatabase, _setManagedDb } from './database';
|
|
28
|
+
import { createDatabase, _setManagedDb, SYSTEM_INDEXES, computeSchemaVersion } from './database';
|
|
29
|
+
import { _initCRDT } from './crdt/config';
|
|
29
30
|
import { snakeToCamel } from './utils';
|
|
30
31
|
// =============================================================================
|
|
31
32
|
// Module State
|
|
@@ -34,28 +35,32 @@ import { snakeToCamel } from './utils';
|
|
|
34
35
|
let engineConfig = null;
|
|
35
36
|
/** Promise that resolves when the database is fully opened and upgraded. */
|
|
36
37
|
let _dbReady = null;
|
|
37
|
-
// =============================================================================
|
|
38
|
-
// Initialization
|
|
39
|
-
// =============================================================================
|
|
40
|
-
/**
|
|
41
|
-
* Initialize the sync engine with the provided configuration.
|
|
42
|
-
*
|
|
43
|
-
* Must be called once at app startup, before any other engine function.
|
|
44
|
-
* Propagates the `prefix` to all internal modules (debug, deviceId,
|
|
45
|
-
* Supabase client, runtime config) and creates or registers the Dexie
|
|
46
|
-
* database instance.
|
|
47
|
-
*
|
|
48
|
-
* @param config - The full engine configuration object.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* // In your app's root layout or entry point:
|
|
52
|
-
* initEngine({
|
|
53
|
-
* prefix: 'myapp',
|
|
54
|
-
* tables: [...],
|
|
55
|
-
* database: { name: 'myapp-db', versions: [...] },
|
|
56
|
-
* });
|
|
57
|
-
*/
|
|
58
38
|
export function initEngine(config) {
|
|
39
|
+
/* Normalize `crdt: true` shorthand to `crdt: {}`. */
|
|
40
|
+
if (config.crdt === true) {
|
|
41
|
+
config.crdt = {};
|
|
42
|
+
}
|
|
43
|
+
/* Normalize flat auth config to the nested structure used internally. */
|
|
44
|
+
if (config.auth) {
|
|
45
|
+
config.auth = normalizeAuthConfig(config.auth);
|
|
46
|
+
}
|
|
47
|
+
/*
|
|
48
|
+
* Schema-driven mode: auto-generate `tables` and `database` from the
|
|
49
|
+
* declarative schema definition.
|
|
50
|
+
*/
|
|
51
|
+
if (config.schema) {
|
|
52
|
+
if (config.tables || config.database) {
|
|
53
|
+
throw new Error('initEngine: `schema` is mutually exclusive with `tables` and `database`. ' +
|
|
54
|
+
'Use either the schema-driven API or the manual API, not both.');
|
|
55
|
+
}
|
|
56
|
+
config.tables = generateTablesFromSchema(config.schema);
|
|
57
|
+
config.database = generateDatabaseFromSchema(config.schema, config.prefix, config.databaseName, !!config.crdt);
|
|
58
|
+
}
|
|
59
|
+
/* Validate that tables are configured (either manually or via schema). */
|
|
60
|
+
if (!config.tables || config.tables.length === 0) {
|
|
61
|
+
throw new Error('initEngine: No tables configured. Provide either `schema` or `tables`.');
|
|
62
|
+
}
|
|
63
|
+
/* At this point tables is guaranteed to be populated — safe to cast. */
|
|
59
64
|
engineConfig = config;
|
|
60
65
|
/* Propagate prefix to all internal modules that use localStorage keys. */
|
|
61
66
|
if (config.prefix) {
|
|
@@ -69,13 +74,18 @@ export function initEngine(config) {
|
|
|
69
74
|
if (config.demo) {
|
|
70
75
|
registerDemoConfig(config.demo);
|
|
71
76
|
}
|
|
77
|
+
/* Initialize CRDT subsystem if configured. */
|
|
78
|
+
if (config.crdt) {
|
|
79
|
+
_initCRDT(config.crdt, config.prefix);
|
|
80
|
+
}
|
|
72
81
|
/* If demo mode is active, switch to a separate sandboxed database. */
|
|
73
82
|
if (isDemoMode() && config.database) {
|
|
74
83
|
config.database = { ...config.database, name: config.database.name + '_demo' };
|
|
75
84
|
}
|
|
76
|
-
/* Handle database creation — either managed or provided.
|
|
85
|
+
/* Handle database creation — either managed or provided.
|
|
86
|
+
* Pass crdtEnabled flag so CRDT IndexedDB tables are conditionally included. */
|
|
77
87
|
if (config.database) {
|
|
78
|
-
_dbReady = createDatabase(config.database).then((db) => {
|
|
88
|
+
_dbReady = createDatabase(config.database, !!config.crdt).then((db) => {
|
|
79
89
|
/* Store on config for backward compat (engine.ts reads config.db). */
|
|
80
90
|
config.db = db;
|
|
81
91
|
});
|
|
@@ -158,4 +168,235 @@ export function getTableColumns(supabaseName) {
|
|
|
158
168
|
}
|
|
159
169
|
return table.columns;
|
|
160
170
|
}
|
|
171
|
+
// =============================================================================
|
|
172
|
+
// Schema → Config Generation
|
|
173
|
+
// =============================================================================
|
|
174
|
+
/**
|
|
175
|
+
* Generate `TableConfig[]` from a declarative {@link SchemaDefinition}.
|
|
176
|
+
*
|
|
177
|
+
* Each schema key becomes a `TableConfig` with:
|
|
178
|
+
* - `supabaseName` = the schema key (snake_case)
|
|
179
|
+
* - `columns` = `'*'` (SELECT all by default — no egress micro-optimization)
|
|
180
|
+
* - `ownershipFilter` = `'user_id'` (default, since RLS always filters by user)
|
|
181
|
+
* - `isSingleton`, `excludeFromConflict`, `numericMergeFields`, `onRemoteChange`
|
|
182
|
+
* from the object form (if provided)
|
|
183
|
+
*
|
|
184
|
+
* @param schema - The declarative schema definition.
|
|
185
|
+
* @returns An array of `TableConfig` objects ready for engine consumption.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* generateTablesFromSchema({
|
|
189
|
+
* goals: 'goal_list_id, order',
|
|
190
|
+
* focus_settings: { singleton: true },
|
|
191
|
+
* });
|
|
192
|
+
* // → [
|
|
193
|
+
* // { supabaseName: 'goals', columns: '*', ownershipFilter: 'user_id' },
|
|
194
|
+
* // { supabaseName: 'focus_settings', columns: '*', ownershipFilter: 'user_id', isSingleton: true },
|
|
195
|
+
* // ]
|
|
196
|
+
*/
|
|
197
|
+
function generateTablesFromSchema(schema) {
|
|
198
|
+
const tables = [];
|
|
199
|
+
for (const [tableName, definition] of Object.entries(schema)) {
|
|
200
|
+
/* String form is sugar for { indexes: theString }. */
|
|
201
|
+
const config = typeof definition === 'string' ? { indexes: definition } : definition;
|
|
202
|
+
const tableConfig = {
|
|
203
|
+
supabaseName: tableName,
|
|
204
|
+
columns: config.columns || '*',
|
|
205
|
+
ownershipFilter: config.ownership || 'user_id'
|
|
206
|
+
};
|
|
207
|
+
if (config.singleton)
|
|
208
|
+
tableConfig.isSingleton = true;
|
|
209
|
+
if (config.excludeFromConflict)
|
|
210
|
+
tableConfig.excludeFromConflict = config.excludeFromConflict;
|
|
211
|
+
if (config.numericMergeFields)
|
|
212
|
+
tableConfig.numericMergeFields = config.numericMergeFields;
|
|
213
|
+
if (config.onRemoteChange)
|
|
214
|
+
tableConfig.onRemoteChange = config.onRemoteChange;
|
|
215
|
+
tables.push(tableConfig);
|
|
216
|
+
}
|
|
217
|
+
return tables;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Generate a `DatabaseConfig` from a declarative {@link SchemaDefinition}.
|
|
221
|
+
*
|
|
222
|
+
* Builds the Dexie store schema for each table by combining the app-specific
|
|
223
|
+
* indexes from the schema with the {@link SYSTEM_INDEXES} constant. Uses
|
|
224
|
+
* {@link computeSchemaVersion} for automatic version management.
|
|
225
|
+
*
|
|
226
|
+
* @param schema - The declarative schema definition.
|
|
227
|
+
* @param prefix - Application prefix for database naming and versioning.
|
|
228
|
+
* @param databaseName - Optional override for the database name.
|
|
229
|
+
* @param crdtEnabled - Whether the CRDT subsystem is enabled.
|
|
230
|
+
* @returns A `DatabaseConfig` ready for `createDatabase()`.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* generateDatabaseFromSchema(
|
|
234
|
+
* { goals: 'goal_list_id, order' },
|
|
235
|
+
* 'stellar',
|
|
236
|
+
* undefined,
|
|
237
|
+
* false
|
|
238
|
+
* );
|
|
239
|
+
* // → {
|
|
240
|
+
* // name: 'stellarDB',
|
|
241
|
+
* // versions: [{ version: 1, stores: { goals: 'id, user_id, ..., goal_list_id, order' } }]
|
|
242
|
+
* // }
|
|
243
|
+
*/
|
|
244
|
+
function generateDatabaseFromSchema(schema, prefix, databaseName, crdtEnabled = false) {
|
|
245
|
+
const stores = {};
|
|
246
|
+
for (const [tableName, definition] of Object.entries(schema)) {
|
|
247
|
+
const config = typeof definition === 'string' ? { indexes: definition } : definition;
|
|
248
|
+
/* Determine the Dexie table name (camelCase by default, or explicit override). */
|
|
249
|
+
const dexieName = config.dexieName || snakeToCamel(tableName);
|
|
250
|
+
/* Merge system indexes with app-specific indexes. */
|
|
251
|
+
const appIndexes = (config.indexes || '').trim();
|
|
252
|
+
stores[dexieName] = appIndexes ? `${SYSTEM_INDEXES}, ${appIndexes}` : SYSTEM_INDEXES;
|
|
253
|
+
}
|
|
254
|
+
/* Compute auto-version based on the merged store schema.
|
|
255
|
+
* The CRDT flag affects the schema hash because CRDT system tables are merged
|
|
256
|
+
* by buildDexie() — if CRDT is toggled, the version should bump. */
|
|
257
|
+
const hashInput = crdtEnabled ? { ...stores, __crdt: 'enabled' } : stores;
|
|
258
|
+
const result = computeSchemaVersion(prefix, hashInput);
|
|
259
|
+
/*
|
|
260
|
+
* Build the versions array. When an upgrade is detected, declare BOTH
|
|
261
|
+
* the previous version and the current version so Dexie has a proper
|
|
262
|
+
* upgrade path (v(N-1) → vN). This avoids the UpgradeError that occurs
|
|
263
|
+
* when only the new version is declared and the browser already has the
|
|
264
|
+
* old version's IndexedDB schema.
|
|
265
|
+
*
|
|
266
|
+
* Dexie handles additive changes (new tables, new indexes) natively.
|
|
267
|
+
* For the previous version we use its original stores so Dexie can diff
|
|
268
|
+
* and apply the structural changes.
|
|
269
|
+
*/
|
|
270
|
+
const versions = [];
|
|
271
|
+
if (result.previousStores && result.previousVersion) {
|
|
272
|
+
versions.push({ version: result.previousVersion, stores: result.previousStores });
|
|
273
|
+
}
|
|
274
|
+
/*
|
|
275
|
+
* Generate an upgrade callback when any table declares `renamedFrom`.
|
|
276
|
+
* The callback copies data from the old Dexie table to the new one,
|
|
277
|
+
* applying any `renamedColumns` transformations along the way.
|
|
278
|
+
*/
|
|
279
|
+
const upgradeCallback = buildRenameUpgradeCallback(schema);
|
|
280
|
+
if (upgradeCallback) {
|
|
281
|
+
versions.push({ version: result.version, stores, upgrade: upgradeCallback });
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
versions.push({ version: result.version, stores });
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
name: databaseName || `${prefix}DB`,
|
|
288
|
+
versions
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Build a Dexie upgrade callback that handles table renames.
|
|
293
|
+
*
|
|
294
|
+
* When a table declares `renamedFrom`, the callback copies all rows from
|
|
295
|
+
* the old table name to the new one, applying any `renamedColumns` field
|
|
296
|
+
* name transformations. Dexie's schema diff handles creating the new table
|
|
297
|
+
* and removing the old one — this callback only handles data migration.
|
|
298
|
+
*
|
|
299
|
+
* @param schema - The declarative schema definition.
|
|
300
|
+
* @returns An upgrade function, or `null` if no renames are declared.
|
|
301
|
+
* @internal
|
|
302
|
+
*/
|
|
303
|
+
function buildRenameUpgradeCallback(schema) {
|
|
304
|
+
/* Collect all rename operations. */
|
|
305
|
+
const renames = [];
|
|
306
|
+
for (const [tableName, definition] of Object.entries(schema)) {
|
|
307
|
+
const config = typeof definition === 'string' ? { indexes: definition } : definition;
|
|
308
|
+
if (!config.renamedFrom)
|
|
309
|
+
continue;
|
|
310
|
+
const oldDexie = config.dexieName ? config.dexieName : snakeToCamel(config.renamedFrom);
|
|
311
|
+
const newDexie = config.dexieName || snakeToCamel(tableName);
|
|
312
|
+
/* Only generate a callback if the Dexie name actually changed. */
|
|
313
|
+
if (oldDexie !== newDexie) {
|
|
314
|
+
renames.push({
|
|
315
|
+
oldDexie,
|
|
316
|
+
newDexie,
|
|
317
|
+
columnMap: config.renamedColumns
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (renames.length === 0)
|
|
322
|
+
return null;
|
|
323
|
+
return async (tx) => {
|
|
324
|
+
for (const { oldDexie, newDexie, columnMap } of renames) {
|
|
325
|
+
try {
|
|
326
|
+
const oldTable = tx.table(oldDexie);
|
|
327
|
+
const newTable = tx.table(newDexie);
|
|
328
|
+
const rows = await oldTable.toArray();
|
|
329
|
+
for (const row of rows) {
|
|
330
|
+
/* Apply column renames if specified. */
|
|
331
|
+
if (columnMap) {
|
|
332
|
+
for (const [newCol, oldCol] of Object.entries(columnMap)) {
|
|
333
|
+
if (oldCol in row) {
|
|
334
|
+
row[newCol] = row[oldCol];
|
|
335
|
+
delete row[oldCol];
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
await newTable.put(row);
|
|
340
|
+
}
|
|
341
|
+
/* Clear the old table — Dexie's schema diff will remove it. */
|
|
342
|
+
await oldTable.clear();
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
/* Old table may not exist (e.g., fresh install) — skip silently. */
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Normalize an auth config to the internal nested structure.
|
|
352
|
+
*
|
|
353
|
+
* Detects whether the config is in the new flat form ({@link AuthConfig}) or
|
|
354
|
+
* the legacy nested form (has a `singleUser` key). Flat form is converted to
|
|
355
|
+
* nested; nested form is passed through unchanged.
|
|
356
|
+
*
|
|
357
|
+
* @param auth - The auth config (flat or nested).
|
|
358
|
+
* @returns The normalized nested auth config.
|
|
359
|
+
* @internal
|
|
360
|
+
*/
|
|
361
|
+
function normalizeAuthConfig(auth) {
|
|
362
|
+
if (!auth)
|
|
363
|
+
return auth;
|
|
364
|
+
/* Detect legacy nested form by the presence of `singleUser` key. */
|
|
365
|
+
if ('singleUser' in auth) {
|
|
366
|
+
return auth;
|
|
367
|
+
}
|
|
368
|
+
/* Flat form (AuthConfig) → convert to nested structure. */
|
|
369
|
+
const flat = auth;
|
|
370
|
+
const nested = {};
|
|
371
|
+
/* Map flat singleUser fields to nested singleUser object. */
|
|
372
|
+
const gateType = flat.gateType || 'code';
|
|
373
|
+
const codeLength = flat.codeLength || 6;
|
|
374
|
+
nested.singleUser = {
|
|
375
|
+
gateType,
|
|
376
|
+
...(gateType === 'code' ? { codeLength } : {})
|
|
377
|
+
};
|
|
378
|
+
/* Map flat boolean flags to nested object structures. */
|
|
379
|
+
const emailConfirmation = flat.emailConfirmation !== undefined ? flat.emailConfirmation : true;
|
|
380
|
+
nested.emailConfirmation = { enabled: emailConfirmation };
|
|
381
|
+
const deviceVerification = flat.deviceVerification !== undefined ? flat.deviceVerification : true;
|
|
382
|
+
nested.deviceVerification = {
|
|
383
|
+
enabled: deviceVerification,
|
|
384
|
+
trustDurationDays: flat.trustDurationDays || 90
|
|
385
|
+
};
|
|
386
|
+
/* Pass through remaining fields with defaults. */
|
|
387
|
+
nested.confirmRedirectPath = flat.confirmRedirectPath || '/confirm';
|
|
388
|
+
nested.enableOfflineAuth =
|
|
389
|
+
flat.enableOfflineAuth !== undefined ? flat.enableOfflineAuth : true;
|
|
390
|
+
if (flat.sessionValidationIntervalMs !== undefined) {
|
|
391
|
+
nested.sessionValidationIntervalMs =
|
|
392
|
+
flat.sessionValidationIntervalMs;
|
|
393
|
+
}
|
|
394
|
+
if (flat.profileExtractor) {
|
|
395
|
+
nested.profileExtractor = flat.profileExtractor;
|
|
396
|
+
}
|
|
397
|
+
if (flat.profileToMetadata) {
|
|
398
|
+
nested.profileToMetadata = flat.profileToMetadata;
|
|
399
|
+
}
|
|
400
|
+
return nested;
|
|
401
|
+
}
|
|
161
402
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CRDT Presence / Awareness Management
|
|
3
|
+
*
|
|
4
|
+
* Bridges Supabase Presence ↔ local presence state for collaborative cursor
|
|
5
|
+
* and user tracking. Each open document has its own set of collaborators.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Tracking local cursor/selection state per document
|
|
9
|
+
* - Debouncing cursor updates to avoid flooding the Presence channel
|
|
10
|
+
* - Maintaining a list of active collaborators per document
|
|
11
|
+
* - Providing subscription-based notifications for collaborator changes
|
|
12
|
+
* - Deterministic color assignment from userId hash
|
|
13
|
+
*
|
|
14
|
+
* The Supabase Presence integration is handled through the same Realtime
|
|
15
|
+
* channel used for Broadcast. Presence state is tracked separately from
|
|
16
|
+
* Yjs document updates — they use different Supabase Realtime features
|
|
17
|
+
* (Presence vs Broadcast) on the same channel.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link ./types.ts} for {@link UserPresenceState}
|
|
20
|
+
* @see {@link ./channel.ts} for the underlying Broadcast channel
|
|
21
|
+
* @see {@link ./provider.ts} for the lifecycle orchestrator
|
|
22
|
+
*/
|
|
23
|
+
import type { UserPresenceState } from './types';
|
|
24
|
+
/**
|
|
25
|
+
* Assign a deterministic color to a user based on their userId.
|
|
26
|
+
*
|
|
27
|
+
* Uses a simple hash of the userId to index into the 12-color palette.
|
|
28
|
+
* The same userId always gets the same color, so collaborators appear
|
|
29
|
+
* consistent across sessions and devices.
|
|
30
|
+
*
|
|
31
|
+
* @param userId - The user's UUID.
|
|
32
|
+
* @returns A hex color string from the palette.
|
|
33
|
+
*/
|
|
34
|
+
export declare function assignColor(userId: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Initialize presence tracking for a document.
|
|
37
|
+
*
|
|
38
|
+
* Called by the provider when a document is opened. Sets up the collaborator
|
|
39
|
+
* map and announces the local user's presence.
|
|
40
|
+
*
|
|
41
|
+
* @param documentId - The document to join.
|
|
42
|
+
* @param isConnected - Whether the Broadcast channel is connected.
|
|
43
|
+
* @param initialPresence - The local user's initial presence info.
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
export declare function joinPresence(documentId: string, isConnected: boolean, initialPresence: {
|
|
47
|
+
name: string;
|
|
48
|
+
avatarUrl?: string;
|
|
49
|
+
}): void;
|
|
50
|
+
/**
|
|
51
|
+
* Leave presence tracking for a document.
|
|
52
|
+
*
|
|
53
|
+
* Called by the provider when a document is closed. Cleans up the collaborator
|
|
54
|
+
* map and notifies listeners.
|
|
55
|
+
*
|
|
56
|
+
* @param documentId - The document to leave.
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export declare function leavePresence(documentId: string): void;
|
|
60
|
+
/**
|
|
61
|
+
* Handle a remote user joining the document.
|
|
62
|
+
*
|
|
63
|
+
* Called when a Supabase Presence `join` event is received.
|
|
64
|
+
*
|
|
65
|
+
* @param documentId - The document.
|
|
66
|
+
* @param presence - The remote user's presence state.
|
|
67
|
+
* @internal
|
|
68
|
+
*/
|
|
69
|
+
export declare function handlePresenceJoin(documentId: string, presence: UserPresenceState): void;
|
|
70
|
+
/**
|
|
71
|
+
* Handle a remote user leaving the document.
|
|
72
|
+
*
|
|
73
|
+
* @param documentId - The document.
|
|
74
|
+
* @param userId - The user's UUID.
|
|
75
|
+
* @param deviceId - The user's device ID.
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
export declare function handlePresenceLeave(documentId: string, userId: string, deviceId: string): void;
|
|
79
|
+
/**
|
|
80
|
+
* Update the local user's cursor and selection in a document.
|
|
81
|
+
*
|
|
82
|
+
* Debounced to `cursorDebounceMs` (default 50ms) to avoid flooding the
|
|
83
|
+
* Presence channel with rapid cursor movements.
|
|
84
|
+
*
|
|
85
|
+
* @param documentId - The document to update cursor for.
|
|
86
|
+
* @param cursor - Editor-specific cursor position (opaque to the engine).
|
|
87
|
+
* @param selection - Editor-specific selection range (opaque to the engine).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* // In your editor's cursor change handler:
|
|
91
|
+
* editor.on('selectionUpdate', ({ editor }) => {
|
|
92
|
+
* updateCursor('doc-1', editor.state.selection.anchor, editor.state.selection);
|
|
93
|
+
* });
|
|
94
|
+
*/
|
|
95
|
+
export declare function updateCursor(documentId: string, cursor: unknown, selection?: unknown): void;
|
|
96
|
+
/**
|
|
97
|
+
* Get the current list of collaborators for a document.
|
|
98
|
+
*
|
|
99
|
+
* Excludes the local user (they don't need to see their own cursor).
|
|
100
|
+
*
|
|
101
|
+
* @param documentId - The document to get collaborators for.
|
|
102
|
+
* @returns Array of presence states for remote collaborators.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const collaborators = getCollaborators('doc-1');
|
|
106
|
+
* // [{ userId: '...', name: 'Alice', color: '#E57373', cursor: {...} }]
|
|
107
|
+
*/
|
|
108
|
+
export declare function getCollaborators(documentId: string): UserPresenceState[];
|
|
109
|
+
/**
|
|
110
|
+
* Subscribe to collaborator changes for a document.
|
|
111
|
+
*
|
|
112
|
+
* The callback is invoked whenever a collaborator joins, leaves, or updates
|
|
113
|
+
* their cursor position. The callback receives the current list of remote
|
|
114
|
+
* collaborators (excluding the local user).
|
|
115
|
+
*
|
|
116
|
+
* @param documentId - The document to subscribe to.
|
|
117
|
+
* @param callback - Called with the updated collaborator list.
|
|
118
|
+
* @returns An unsubscribe function.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* const unsub = onCollaboratorsChange('doc-1', (collaborators) => {
|
|
122
|
+
* avatarList = collaborators.map(c => ({ name: c.name, color: c.color }));
|
|
123
|
+
* });
|
|
124
|
+
* // Later:
|
|
125
|
+
* unsub();
|
|
126
|
+
*/
|
|
127
|
+
export declare function onCollaboratorsChange(documentId: string, callback: (collaborators: UserPresenceState[]) => void): () => void;
|
|
128
|
+
//# sourceMappingURL=awareness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/crdt/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA6CjD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMlD;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,eAAe,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAItD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAcxF;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAY9F;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAgC3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAmBxE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,aAAa,EAAE,iBAAiB,EAAE,KAAK,IAAI,GACrD,MAAM,IAAI,CAcZ"}
|