syncorejs 0.2.1 → 0.2.3

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.
Files changed (169) hide show
  1. package/README.md +2 -1
  2. package/dist/_vendor/cli/app.d.mts.map +1 -1
  3. package/dist/_vendor/cli/app.mjs +330 -46
  4. package/dist/_vendor/cli/app.mjs.map +1 -1
  5. package/dist/_vendor/cli/context.mjs +27 -9
  6. package/dist/_vendor/cli/context.mjs.map +1 -1
  7. package/dist/_vendor/cli/dev-session.mjs.map +1 -1
  8. package/dist/_vendor/cli/doctor.mjs +513 -46
  9. package/dist/_vendor/cli/doctor.mjs.map +1 -1
  10. package/dist/_vendor/cli/errors.mjs.map +1 -1
  11. package/dist/_vendor/cli/help.mjs.map +1 -1
  12. package/dist/_vendor/cli/index.mjs +9 -2
  13. package/dist/_vendor/cli/index.mjs.map +1 -1
  14. package/dist/_vendor/cli/messages.mjs +5 -4
  15. package/dist/_vendor/cli/messages.mjs.map +1 -1
  16. package/dist/_vendor/cli/preflight.mjs.map +1 -1
  17. package/dist/_vendor/cli/project.mjs +125 -27
  18. package/dist/_vendor/cli/project.mjs.map +1 -1
  19. package/dist/_vendor/cli/render.mjs +57 -9
  20. package/dist/_vendor/cli/render.mjs.map +1 -1
  21. package/dist/_vendor/cli/targets.mjs +4 -3
  22. package/dist/_vendor/cli/targets.mjs.map +1 -1
  23. package/dist/_vendor/core/cli.d.mts +20 -4
  24. package/dist/_vendor/core/cli.d.mts.map +1 -1
  25. package/dist/_vendor/core/cli.mjs +458 -133
  26. package/dist/_vendor/core/cli.mjs.map +1 -1
  27. package/dist/_vendor/core/devtools-auth.mjs +60 -0
  28. package/dist/_vendor/core/devtools-auth.mjs.map +1 -0
  29. package/dist/_vendor/core/index.d.mts +5 -3
  30. package/dist/_vendor/core/index.mjs +22 -2
  31. package/dist/_vendor/core/index.mjs.map +1 -1
  32. package/dist/_vendor/core/runtime/components.d.mts +111 -0
  33. package/dist/_vendor/core/runtime/components.d.mts.map +1 -0
  34. package/dist/_vendor/core/runtime/components.mjs +186 -0
  35. package/dist/_vendor/core/runtime/components.mjs.map +1 -0
  36. package/dist/_vendor/core/runtime/devtools.d.mts +4 -4
  37. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  38. package/dist/_vendor/core/runtime/devtools.mjs +178 -60
  39. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  40. package/dist/_vendor/core/runtime/functions.d.mts +398 -16
  41. package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
  42. package/dist/_vendor/core/runtime/functions.mjs +74 -3
  43. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  44. package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
  45. package/dist/_vendor/core/runtime/id.mjs.map +1 -1
  46. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +83 -0
  47. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -0
  48. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +720 -0
  49. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -0
  50. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +234 -0
  51. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -0
  52. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +255 -0
  53. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -0
  54. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +200 -0
  55. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -0
  56. package/dist/_vendor/core/runtime/internal/engines/shared.mjs +252 -0
  57. package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -0
  58. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +145 -0
  59. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -0
  60. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +221 -0
  61. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -0
  62. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs +32 -0
  63. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -0
  64. package/dist/_vendor/core/runtime/internal/systemMeta.mjs +61 -0
  65. package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -0
  66. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +41 -0
  67. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -0
  68. package/dist/_vendor/core/runtime/runtime.d.mts +1187 -202
  69. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  70. package/dist/_vendor/core/runtime/runtime.mjs +73 -1365
  71. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  72. package/dist/_vendor/core/transport.d.mts +113 -0
  73. package/dist/_vendor/core/transport.d.mts.map +1 -0
  74. package/dist/_vendor/core/transport.mjs +428 -0
  75. package/dist/_vendor/core/transport.mjs.map +1 -0
  76. package/dist/_vendor/devtools-protocol/index.d.ts +187 -4
  77. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  78. package/dist/_vendor/devtools-protocol/index.js +25 -9
  79. package/dist/_vendor/devtools-protocol/index.js.map +1 -1
  80. package/dist/_vendor/next/config.d.ts +3 -4
  81. package/dist/_vendor/next/config.d.ts.map +1 -1
  82. package/dist/_vendor/next/config.js +37 -19
  83. package/dist/_vendor/next/config.js.map +1 -1
  84. package/dist/_vendor/next/index.d.ts +109 -29
  85. package/dist/_vendor/next/index.d.ts.map +1 -1
  86. package/dist/_vendor/next/index.js +104 -26
  87. package/dist/_vendor/next/index.js.map +1 -1
  88. package/dist/_vendor/platform-expo/index.d.ts +156 -37
  89. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  90. package/dist/_vendor/platform-expo/index.js +80 -12
  91. package/dist/_vendor/platform-expo/index.js.map +1 -1
  92. package/dist/_vendor/platform-expo/react.d.ts.map +1 -1
  93. package/dist/_vendor/platform-expo/react.js +11 -10
  94. package/dist/_vendor/platform-expo/react.js.map +1 -1
  95. package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
  96. package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
  97. package/dist/_vendor/platform-node/index.d.mts +192 -24
  98. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  99. package/dist/_vendor/platform-node/index.mjs +236 -97
  100. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  101. package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -1
  102. package/dist/_vendor/platform-node/ipc-react.mjs +15 -2
  103. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  104. package/dist/_vendor/platform-node/ipc.d.mts +11 -35
  105. package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
  106. package/dist/_vendor/platform-node/ipc.mjs +3 -273
  107. package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
  108. package/dist/_vendor/platform-web/external-change.d.ts +43 -1
  109. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
  110. package/dist/_vendor/platform-web/external-change.js +32 -1
  111. package/dist/_vendor/platform-web/external-change.js.map +1 -1
  112. package/dist/_vendor/platform-web/index.d.ts +323 -51
  113. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  114. package/dist/_vendor/platform-web/index.js +233 -30
  115. package/dist/_vendor/platform-web/index.js.map +1 -1
  116. package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
  117. package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
  118. package/dist/_vendor/platform-web/indexeddb.js +10 -0
  119. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  120. package/dist/_vendor/platform-web/opfs.d.ts +13 -0
  121. package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
  122. package/dist/_vendor/platform-web/opfs.js +12 -0
  123. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  124. package/dist/_vendor/platform-web/persistence.d.ts +54 -0
  125. package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
  126. package/dist/_vendor/platform-web/persistence.js +15 -0
  127. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  128. package/dist/_vendor/platform-web/react.d.ts +1 -2
  129. package/dist/_vendor/platform-web/react.d.ts.map +1 -1
  130. package/dist/_vendor/platform-web/react.js +27 -13
  131. package/dist/_vendor/platform-web/react.js.map +1 -1
  132. package/dist/_vendor/platform-web/sqljs.js +10 -1
  133. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  134. package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
  135. package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
  136. package/dist/_vendor/platform-web/worker.d.ts +71 -44
  137. package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
  138. package/dist/_vendor/platform-web/worker.js +40 -271
  139. package/dist/_vendor/platform-web/worker.js.map +1 -1
  140. package/dist/_vendor/react/index.d.ts +222 -23
  141. package/dist/_vendor/react/index.d.ts.map +1 -1
  142. package/dist/_vendor/react/index.js +476 -63
  143. package/dist/_vendor/react/index.js.map +1 -1
  144. package/dist/_vendor/schema/definition.d.ts +151 -37
  145. package/dist/_vendor/schema/definition.d.ts.map +1 -1
  146. package/dist/_vendor/schema/definition.js +102 -20
  147. package/dist/_vendor/schema/definition.js.map +1 -1
  148. package/dist/_vendor/schema/index.d.ts +4 -4
  149. package/dist/_vendor/schema/index.js +2 -2
  150. package/dist/_vendor/schema/planner.d.ts +19 -2
  151. package/dist/_vendor/schema/planner.d.ts.map +1 -1
  152. package/dist/_vendor/schema/planner.js +79 -3
  153. package/dist/_vendor/schema/planner.js.map +1 -1
  154. package/dist/_vendor/schema/validators.d.ts +279 -83
  155. package/dist/_vendor/schema/validators.d.ts.map +1 -1
  156. package/dist/_vendor/schema/validators.js +330 -38
  157. package/dist/_vendor/schema/validators.js.map +1 -1
  158. package/dist/_vendor/svelte/index.d.ts +245 -19
  159. package/dist/_vendor/svelte/index.d.ts.map +1 -1
  160. package/dist/_vendor/svelte/index.js +443 -20
  161. package/dist/_vendor/svelte/index.js.map +1 -1
  162. package/dist/browser.d.ts.map +1 -1
  163. package/dist/cli.js +3 -1
  164. package/dist/cli.js.map +1 -1
  165. package/dist/components.d.ts +2 -0
  166. package/dist/components.js +2 -0
  167. package/dist/index.d.ts +3 -2
  168. package/dist/index.js +2 -1
  169. package/package.json +29 -21
@@ -1,105 +1,43 @@
1
1
  import { SyncoreRendererClient, attachNodeIpcRuntime, createNodeIpcMessageEndpoint, createRendererSyncoreBridgeClient, createRendererSyncoreClient, createRendererSyncoreWindowClient, installSyncoreWindowBridge } from "./ipc.mjs";
2
- import { createRequire } from "node:module";
3
2
  import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
3
+ import { createHash } from "node:crypto";
4
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
5
  import path from "node:path";
5
6
  import { DatabaseSync } from "node:sqlite";
6
7
  import WebSocket from "ws";
8
+ import { SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION, SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION, SYNCORE_DEVTOOLS_PROTOCOL_VERSION } from "../devtools-protocol/index.js";
7
9
  import { SyncoreRuntime, createDevtoolsCommandHandler, createDevtoolsSubscriptionHost } from "../core/index.mjs";
8
10
  //#region src/index.ts
9
- const { Parser: NodeSqlParser } = createRequire(import.meta.url)("node-sql-parser");
10
- const nodeSqlParser = new NodeSqlParser();
11
- const nodeDevtoolsSqlSupport = {
12
- analyzeSqlStatement(query) {
13
- const ast = nodeSqlParser.astify(query, { database: "sqlite" });
14
- if (Array.isArray(ast)) throw new Error("Only a single SQL statement is supported.");
15
- switch (ast.type) {
16
- case "select": return buildReadAnalysis(ast);
17
- case "update":
18
- case "delete":
19
- case "insert":
20
- case "replace": return buildWriteAnalysis(extractTables(ast.table), false);
21
- case "create":
22
- case "drop":
23
- case "alter": return buildWriteAnalysis(extractTables(ast.table), true);
24
- default: throw new Error(`Unsupported SQL statement type: ${String(ast.type)}`);
25
- }
26
- },
27
- ensureSqlMode(analysis, expected) {
28
- if (expected === "watch") {
29
- if (analysis.mode !== "read") throw new Error("Live mode supports read-only SQL only.");
30
- return;
31
- }
32
- if (analysis.mode !== expected) {
33
- if (expected === "read") throw new Error("Use SQL Write for mutating statements.");
34
- throw new Error("Use SQL Read or SQL Live for read-only statements.");
35
- }
36
- },
37
- runReadonlyQuery(databasePath, query) {
38
- const analysis = this.analyzeSqlStatement(query);
39
- this.ensureSqlMode(analysis, "read");
40
- const database = new DatabaseSync(databasePath, { readOnly: true });
41
- try {
42
- const statement = database.prepare(query);
43
- const rows = statement.all();
44
- const columnsMeta = statement.columns();
45
- const columns = columnsMeta.map((column) => column.name);
46
- const observedTables = Array.from(new Set(columnsMeta.map((column) => column.table).filter((table) => typeof table === "string")));
47
- return {
48
- columns,
49
- rows: rows.map((row) => columns.map((column) => row[column])),
50
- observedTables: observedTables.length > 0 ? observedTables : analysis.readTables
51
- };
52
- } finally {
53
- database.close();
54
- }
55
- }
56
- };
11
+ const DEVTOOLS_META_DIRECTORY = ".syncore-devtools";
12
+ const DATA_SOURCE_ALIAS_PREFIX = "data-source-alias";
57
13
  function normalizeData(input) {
58
14
  if (typeof input === "string") return Buffer.from(input);
59
15
  if (input instanceof Uint8Array) return input;
60
16
  return new Uint8Array(input);
61
17
  }
62
- function buildReadAnalysis(ast) {
63
- const readTables = Array.from(new Set(extractReadTables(ast)));
64
- return {
65
- mode: "read",
66
- readTables,
67
- writeTables: [],
68
- schemaChanged: false,
69
- observedScopes: readTables.length > 0 ? readTables.map((table) => `table:${table}`) : ["all"]
70
- };
71
- }
72
- function buildWriteAnalysis(tables, schemaChanged) {
73
- const uniqueTables = Array.from(new Set(tables));
74
- return {
75
- mode: schemaChanged ? "ddl" : "write",
76
- readTables: [],
77
- writeTables: uniqueTables,
78
- schemaChanged,
79
- observedScopes: schemaChanged ? ["schema.tables", ...uniqueTables.map((table) => `table:${table}`)] : uniqueTables.length > 0 ? uniqueTables.map((table) => `table:${table}`) : ["all"]
80
- };
81
- }
82
- function extractReadTables(ast) {
83
- return (ast.from ?? []).flatMap((entry) => {
84
- if (entry.table) return [entry.table];
85
- if (entry.expr?.ast) return extractReadTables(entry.expr.ast);
86
- return [];
87
- }).filter((table) => table !== "dual");
88
- }
89
- function extractTables(table) {
90
- if (Array.isArray(table)) return table.map((entry) => entry?.table).filter((value) => typeof value === "string");
91
- if (table && typeof table === "object") return typeof table.table === "string" ? [table.table] : [];
92
- if (typeof table === "string") return [table];
93
- return [];
94
- }
95
18
  function toSqlParameters(params) {
96
19
  return params;
97
20
  }
21
+ /**
22
+ * SQLite driver backed by Node.js’s built-in `node:sqlite` module (Node 22+).
23
+ *
24
+ * Opens the database at `databasePath` with `WAL` journal mode and foreign-key
25
+ * enforcement enabled. The file is created if it does not exist.
26
+ *
27
+ * ```ts
28
+ * const driver = new NodeSqliteDriver("./data/app.db");
29
+ * ```
30
+ *
31
+ * In most cases you should use {@link createNodeSyncoreRuntime} which
32
+ * instantiates this driver automatically from your `databasePath` option.
33
+ */
98
34
  var NodeSqliteDriver = class {
35
+ databasePath;
99
36
  database;
100
37
  transactionDepth = 0;
101
- constructor(filename) {
102
- this.database = new DatabaseSync(filename);
38
+ constructor(databasePath) {
39
+ this.databasePath = databasePath;
40
+ this.database = new DatabaseSync(databasePath);
103
41
  this.database.exec("PRAGMA foreign_keys = ON;");
104
42
  this.database.exec("PRAGMA journal_mode = WAL;");
105
43
  }
@@ -151,7 +89,21 @@ var NodeSqliteDriver = class {
151
89
  this.database.close();
152
90
  }
153
91
  };
92
+ /**
93
+ * Blob storage adapter that reads and writes files in a local directory.
94
+ *
95
+ * Each stored object is saved as a flat file named by its ID inside
96
+ * `directory`. The directory is created automatically on first write.
97
+ *
98
+ * ```ts
99
+ * const storage = new NodeFileStorageAdapter("./data/storage");
100
+ * ```
101
+ *
102
+ * In most cases you should use {@link createNodeSyncoreRuntime} which
103
+ * instantiates this adapter automatically from your `storageDirectory` option.
104
+ */
154
105
  var NodeFileStorageAdapter = class {
106
+ directory;
155
107
  constructor(directory) {
156
108
  this.directory = directory;
157
109
  }
@@ -211,11 +163,137 @@ var NodeFileStorageAdapter = class {
211
163
  }
212
164
  }
213
165
  };
166
+ const SESSION_ADJECTIVES = [
167
+ "Acrobatic",
168
+ "Bold",
169
+ "Cosmic",
170
+ "Daring",
171
+ "Electric",
172
+ "Fierce",
173
+ "Golden",
174
+ "Hidden",
175
+ "Iron",
176
+ "Jade",
177
+ "Keen",
178
+ "Lunar",
179
+ "Mystic",
180
+ "Noble",
181
+ "Orbital",
182
+ "Primal",
183
+ "Quick",
184
+ "Radiant",
185
+ "Shadow",
186
+ "Turbo",
187
+ "Ultra",
188
+ "Vivid",
189
+ "Wicked",
190
+ "Xenon",
191
+ "Zen",
192
+ "Arctic",
193
+ "Binary",
194
+ "Cyber",
195
+ "Digital",
196
+ "Ember",
197
+ "Frozen",
198
+ "Galactic",
199
+ "Hyper",
200
+ "Infra",
201
+ "Jumbo",
202
+ "Kinetic",
203
+ "Liquid",
204
+ "Magnetic",
205
+ "Neon",
206
+ "Onyx",
207
+ "Phantom",
208
+ "Quantum",
209
+ "Rapid",
210
+ "Sonic",
211
+ "Titan",
212
+ "Velvet",
213
+ "Wild",
214
+ "Blazing",
215
+ "Crystal",
216
+ "Dynamic"
217
+ ];
218
+ const SESSION_NOUNS = [
219
+ "Phoenix",
220
+ "Dragon",
221
+ "Developer",
222
+ "Hacker",
223
+ "Wizard",
224
+ "Runner",
225
+ "Ranger",
226
+ "Maverick",
227
+ "Spartan",
228
+ "Viking",
229
+ "Sentinel",
230
+ "Guardian",
231
+ "Nomad",
232
+ "Cipher",
233
+ "Vector",
234
+ "Matrix",
235
+ "Prism",
236
+ "Nebula",
237
+ "Comet",
238
+ "Pulse",
239
+ "Vertex",
240
+ "Flux",
241
+ "Storm",
242
+ "Blaze",
243
+ "Frost",
244
+ "Thunder",
245
+ "Drift"
246
+ ];
247
+ function generateUniqueSessionName() {
248
+ return `${SESSION_ADJECTIVES[Math.floor(Math.random() * SESSION_ADJECTIVES.length)]} ${SESSION_NOUNS[Math.floor(Math.random() * SESSION_NOUNS.length)]}`;
249
+ }
250
+ function resolvePersistedDataSourceAlias(storageDirectory, storageIdentity) {
251
+ const metaDirectory = path.join(storageDirectory, DEVTOOLS_META_DIRECTORY);
252
+ const aliasId = createHash("sha256").update(storageIdentity).digest("hex").slice(0, 16);
253
+ const aliasPath = path.join(metaDirectory, `${DATA_SOURCE_ALIAS_PREFIX}-${aliasId}.txt`);
254
+ try {
255
+ const existing = readFileSync(aliasPath, "utf8").trim();
256
+ if (existing.length > 0) return existing;
257
+ } catch {}
258
+ const nextValue = generateUniqueSessionName();
259
+ try {
260
+ mkdirSync(metaDirectory, { recursive: true });
261
+ writeFileSync(aliasPath, nextValue, "utf8");
262
+ } catch {}
263
+ return nextValue;
264
+ }
214
265
  /**
215
- * Create a Node or Electron runtime backed by SQLite and local file storage.
266
+ * Create a Syncore runtime for Node.js (or Electron’s main process) backed by
267
+ * the built-in `node:sqlite` driver and local file storage.
268
+ *
269
+ * This is the recommended entry point for Node and Electron apps. It wires up
270
+ * the SQL driver, storage adapter, devtools WebSocket connection, and
271
+ * cross-process change signals automatically.
272
+ *
273
+ * ```ts
274
+ * import path from "node:path";
275
+ * import { createNodeSyncoreRuntime } from "syncorejs/node";
276
+ * import schema from "./syncore/schema";
277
+ * import { functions } from "./syncore/_generated/functions";
278
+ *
279
+ * const runtime = createNodeSyncoreRuntime({
280
+ * databasePath: path.join(app.getPath("userData"), "db.sqlite"),
281
+ * storageDirectory: path.join(app.getPath("userData"), "storage"),
282
+ * schema,
283
+ * functions,
284
+ * });
285
+ *
286
+ * await runtime.start();
287
+ * const client = runtime.createClient();
288
+ * ```
289
+ *
290
+ * @param options - Configuration object. See {@link CreateNodeRuntimeOptions}.
291
+ * @returns A configured (but not yet started) {@link SyncoreRuntime}. Call
292
+ * `await runtime.start()` before using the client.
216
293
  */
217
294
  function createNodeSyncoreRuntime(options) {
218
295
  const resolvedDevtoolsUrl = options.devtoolsUrl ?? resolveDefaultNodeDevtoolsUrl();
296
+ const storageIdentity = `file::${path.resolve(options.databasePath)}`;
219
297
  const websocketDevtools = options.devtools === void 0 && resolvedDevtoolsUrl && shouldAutoConnectNodeDevtools() ? createNodeWebSocketDevtoolsSink({
220
298
  url: resolvedDevtoolsUrl,
221
299
  ...options.appName ? { appName: options.appName } : {},
@@ -224,19 +302,23 @@ function createNodeSyncoreRuntime(options) {
224
302
  targetKind: "client",
225
303
  storageProtocol: "file",
226
304
  databaseLabel: path.basename(options.databasePath),
227
- storageIdentity: `file::${path.resolve(options.databasePath)}`
305
+ dataSourceAlias: resolvePersistedDataSourceAlias(options.storageDirectory, storageIdentity),
306
+ storageIdentity,
307
+ runtimeRole: "app",
308
+ capabilities: createNodeDevtoolsCapabilities()
228
309
  }) : void 0;
229
310
  const runtimeOptions = {
230
311
  schema: options.schema,
231
312
  functions: options.functions,
313
+ ...options.components ? { components: options.components } : {},
232
314
  driver: new NodeSqliteDriver(options.databasePath),
233
315
  storage: new NodeFileStorageAdapter(options.storageDirectory),
234
316
  platform: options.platform ?? "node"
235
317
  };
236
318
  if (options.capabilities) runtimeOptions.capabilities = options.capabilities;
237
- if (options.experimentalPlugins) runtimeOptions.experimentalPlugins = options.experimentalPlugins;
238
319
  const resolvedDevtools = options.devtools === false ? void 0 : options.devtools ?? websocketDevtools;
239
320
  if (resolvedDevtools) runtimeOptions.devtools = resolvedDevtools;
321
+ if (websocketDevtools?.externalChangeSignal) runtimeOptions.externalChangeSignal = websocketDevtools.externalChangeSignal;
240
322
  if (options.scheduler) runtimeOptions.scheduler = options.scheduler;
241
323
  const runtime = new SyncoreRuntime(runtimeOptions);
242
324
  websocketDevtools?.attachRuntime(runtime);
@@ -245,15 +327,13 @@ function createNodeSyncoreRuntime(options) {
245
327
  driver: runtimeOptions.driver,
246
328
  schema: options.schema,
247
329
  functions: options.functions,
248
- runtime,
249
- sql: nodeDevtoolsSqlSupport
330
+ admin: runtime.getAdmin()
250
331
  }));
251
332
  websocketDevtools.attachSubscriptionHost(createDevtoolsSubscriptionHost({
252
333
  driver: runtimeOptions.driver,
253
334
  schema: options.schema,
254
335
  functions: options.functions,
255
- runtime,
256
- sql: nodeDevtoolsSqlSupport
336
+ admin: runtime.getAdmin()
257
337
  }));
258
338
  const stop = runtime.stop.bind(runtime);
259
339
  runtime.stop = async () => {
@@ -323,7 +403,8 @@ function bindElectronWindowToSyncoreRuntime(options) {
323
403
  if (!options.onRendererMessage) {
324
404
  if (!options.ipcMain) throw new Error("bindElectronWindowToSyncoreRuntime requires either onRendererMessage() or ipcMain.");
325
405
  const listeners = /* @__PURE__ */ new Set();
326
- const handleRendererMessage = (_event, message) => {
406
+ const handleRendererMessage = (event, message) => {
407
+ if (event.sender !== options.window.webContents) return;
327
408
  for (const listener of listeners) listener(message);
328
409
  };
329
410
  options.ipcMain.on(channel, handleRendererMessage);
@@ -361,6 +442,7 @@ function createNodeWebSocketDevtoolsSink(options) {
361
442
  let getSummary;
362
443
  let onCommand;
363
444
  let subscriptionHost;
445
+ const externalChangeListeners = /* @__PURE__ */ new Set();
364
446
  const pendingMessages = [];
365
447
  let latestHello;
366
448
  const connect = () => {
@@ -369,15 +451,21 @@ function createNodeWebSocketDevtoolsSink(options) {
369
451
  socket.on("open", () => {
370
452
  if (latestHello) sendNow({
371
453
  type: "hello",
454
+ protocolVersion: SYNCORE_DEVTOOLS_PROTOCOL_VERSION,
455
+ minSupportedProtocolVersion: SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,
456
+ maxSupportedProtocolVersion: SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,
372
457
  runtimeId: latestHello.runtimeId,
373
458
  platform: latestHello.platform,
374
459
  ...options.appName ? { appName: options.appName } : {},
375
460
  ...options.origin ? { origin: options.origin } : {},
376
461
  ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
377
462
  ...options.targetKind ? { targetKind: options.targetKind } : {},
463
+ ...options.runtimeRole ? { runtimeRole: options.runtimeRole } : {},
378
464
  ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
379
465
  ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
380
- ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
466
+ ...options.dataSourceAlias ? { dataSourceAlias: options.dataSourceAlias } : {},
467
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {},
468
+ capabilities: options.capabilities ?? createNodeDevtoolsCapabilities()
381
469
  });
382
470
  flushPendingMessages();
383
471
  });
@@ -386,6 +474,7 @@ function createNodeWebSocketDevtoolsSink(options) {
386
474
  if (rawPayload.length === 0) return;
387
475
  const message = JSON.parse(rawPayload);
388
476
  if (message.type === "ping") send({ type: "pong" });
477
+ else if (message.type === "external.change") for (const listener of externalChangeListeners) listener(message.event);
389
478
  else if (message.type === "command" && onCommand) onCommand(message.payload).then((responsePayload) => {
390
479
  const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
391
480
  if (!runtimeId) return;
@@ -448,7 +537,7 @@ function createNodeWebSocketDevtoolsSink(options) {
448
537
  pendingMessages.push(message);
449
538
  };
450
539
  connect();
451
- return {
540
+ const sink = {
452
541
  emit(event) {
453
542
  if (event.type === "runtime.connected") {
454
543
  latestHello = {
@@ -457,15 +546,21 @@ function createNodeWebSocketDevtoolsSink(options) {
457
546
  };
458
547
  send({
459
548
  type: "hello",
549
+ protocolVersion: SYNCORE_DEVTOOLS_PROTOCOL_VERSION,
550
+ minSupportedProtocolVersion: SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,
551
+ maxSupportedProtocolVersion: SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,
460
552
  runtimeId: event.runtimeId,
461
553
  platform: event.platform,
462
554
  ...options.appName ? { appName: options.appName } : {},
463
555
  ...options.origin ? { origin: options.origin } : {},
464
556
  ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
465
557
  ...options.targetKind ? { targetKind: options.targetKind } : {},
558
+ ...options.runtimeRole ? { runtimeRole: options.runtimeRole } : {},
466
559
  ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
467
560
  ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
468
- ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
561
+ ...options.dataSourceAlias ? { dataSourceAlias: options.dataSourceAlias } : {},
562
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {},
563
+ capabilities: options.capabilities ?? createNodeDevtoolsCapabilities()
469
564
  });
470
565
  }
471
566
  send({
@@ -474,7 +569,7 @@ function createNodeWebSocketDevtoolsSink(options) {
474
569
  });
475
570
  },
476
571
  attachRuntime(runtime) {
477
- getSummary = () => withRuntimeSummaryMeta(runtime.getRuntimeSummary(), options);
572
+ getSummary = () => withRuntimeSummaryMeta(runtime.getAdmin().getRuntimeSummary(), options);
478
573
  },
479
574
  attachCommandHandler(handler) {
480
575
  onCommand = handler;
@@ -489,6 +584,28 @@ function createNodeWebSocketDevtoolsSink(options) {
489
584
  socket?.close();
490
585
  }
491
586
  };
587
+ if (options.storageIdentity) sink.externalChangeSignal = {
588
+ subscribe(listener) {
589
+ externalChangeListeners.add(listener);
590
+ return () => {
591
+ externalChangeListeners.delete(listener);
592
+ };
593
+ },
594
+ publish(event) {
595
+ const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
596
+ if (!runtimeId) return;
597
+ send({
598
+ type: "external.change",
599
+ runtimeId,
600
+ storageIdentity: options.storageIdentity,
601
+ event
602
+ });
603
+ },
604
+ close() {
605
+ externalChangeListeners.clear();
606
+ }
607
+ };
608
+ return sink;
492
609
  }
493
610
  function withRuntimeSummaryMeta(summary, options) {
494
611
  return {
@@ -497,9 +614,31 @@ function withRuntimeSummaryMeta(summary, options) {
497
614
  ...options.origin ? { origin: options.origin } : {},
498
615
  ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
499
616
  ...options.targetKind ? { targetKind: options.targetKind } : {},
617
+ ...options.runtimeRole ? { runtimeRole: options.runtimeRole } : {},
500
618
  ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
501
619
  ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
502
- ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
620
+ ...options.dataSourceAlias ? { dataSourceAlias: options.dataSourceAlias } : {},
621
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {},
622
+ capabilities: options.capabilities ?? createNodeDevtoolsCapabilities()
623
+ };
624
+ }
625
+ function createNodeDevtoolsCapabilities() {
626
+ return {
627
+ sql: {
628
+ read: false,
629
+ write: false,
630
+ live: false,
631
+ reason: "SQL Console is provided by the Project Target for this data source."
632
+ },
633
+ data: {
634
+ browse: true,
635
+ mutate: true,
636
+ importExport: true
637
+ },
638
+ scheduler: {
639
+ read: true,
640
+ edit: true
641
+ }
503
642
  };
504
643
  }
505
644
  function shouldAutoConnectNodeDevtools() {