syncorejs 0.1.0 → 0.2.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.
Files changed (200) hide show
  1. package/dist/{core/src/cli.d.ts → _vendor/cli/app.d.mts} +4 -2
  2. package/dist/_vendor/cli/app.d.mts.map +1 -0
  3. package/dist/_vendor/cli/app.mjs +997 -0
  4. package/dist/_vendor/cli/app.mjs.map +1 -0
  5. package/dist/_vendor/cli/context.mjs +180 -0
  6. package/dist/_vendor/cli/context.mjs.map +1 -0
  7. package/dist/_vendor/cli/dev-session.mjs +49 -0
  8. package/dist/_vendor/cli/dev-session.mjs.map +1 -0
  9. package/dist/_vendor/cli/doctor.mjs +80 -0
  10. package/dist/_vendor/cli/doctor.mjs.map +1 -0
  11. package/dist/_vendor/cli/errors.mjs +22 -0
  12. package/dist/_vendor/cli/errors.mjs.map +1 -0
  13. package/dist/_vendor/cli/help.mjs +26 -0
  14. package/dist/_vendor/cli/help.mjs.map +1 -0
  15. package/dist/_vendor/cli/index.d.mts +2 -0
  16. package/dist/_vendor/cli/index.mjs +23 -0
  17. package/dist/_vendor/cli/index.mjs.map +1 -0
  18. package/dist/_vendor/cli/messages.mjs +32 -0
  19. package/dist/_vendor/cli/messages.mjs.map +1 -0
  20. package/dist/_vendor/cli/preflight.mjs +35 -0
  21. package/dist/_vendor/cli/preflight.mjs.map +1 -0
  22. package/dist/_vendor/cli/project.mjs +583 -0
  23. package/dist/_vendor/cli/project.mjs.map +1 -0
  24. package/dist/_vendor/cli/render.mjs +133 -0
  25. package/dist/_vendor/cli/render.mjs.map +1 -0
  26. package/dist/_vendor/cli/targets.mjs +87 -0
  27. package/dist/_vendor/cli/targets.mjs.map +1 -0
  28. package/dist/_vendor/core/cli.d.mts +59 -1
  29. package/dist/_vendor/core/cli.d.mts.map +1 -1
  30. package/dist/_vendor/core/cli.mjs +528 -75
  31. package/dist/_vendor/core/cli.mjs.map +1 -1
  32. package/dist/_vendor/core/index.d.mts +12 -4
  33. package/dist/_vendor/core/index.d.mts.map +1 -0
  34. package/dist/_vendor/core/index.mjs +4 -3
  35. package/dist/_vendor/core/index.mjs.map +1 -1
  36. package/dist/_vendor/core/runtime/devtools.d.mts +32 -6
  37. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  38. package/dist/_vendor/core/runtime/devtools.mjs +397 -182
  39. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  40. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  41. package/dist/_vendor/core/runtime/runtime.d.mts +89 -7
  42. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  43. package/dist/_vendor/core/runtime/runtime.mjs +303 -32
  44. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  45. package/dist/_vendor/devtools-protocol/index.d.ts +189 -82
  46. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  47. package/dist/_vendor/devtools-protocol/index.js +39 -0
  48. package/dist/_vendor/devtools-protocol/index.js.map +1 -0
  49. package/dist/_vendor/next/config.d.ts.map +1 -1
  50. package/dist/_vendor/next/config.js +2 -5
  51. package/dist/_vendor/next/config.js.map +1 -1
  52. package/dist/_vendor/platform-expo/index.d.ts +15 -5
  53. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  54. package/dist/_vendor/platform-expo/index.js +33 -3
  55. package/dist/_vendor/platform-expo/index.js.map +1 -1
  56. package/dist/_vendor/platform-expo/react.js.map +1 -1
  57. package/dist/_vendor/platform-node/index.d.mts +10 -5
  58. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  59. package/dist/_vendor/platform-node/index.mjs +145 -35
  60. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  61. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  62. package/dist/_vendor/platform-web/external-change.d.ts +39 -0
  63. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -0
  64. package/dist/_vendor/platform-web/external-change.js +61 -0
  65. package/dist/_vendor/platform-web/external-change.js.map +1 -0
  66. package/dist/_vendor/platform-web/index.d.ts +27 -5
  67. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  68. package/dist/_vendor/platform-web/index.js +310 -44
  69. package/dist/_vendor/platform-web/index.js.map +1 -1
  70. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  71. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  72. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  73. package/dist/_vendor/platform-web/react.js.map +1 -1
  74. package/dist/_vendor/platform-web/sqljs.js +22 -2
  75. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  76. package/dist/_vendor/schema/definition.js.map +1 -1
  77. package/dist/_vendor/schema/planner.js.map +1 -1
  78. package/dist/_vendor/schema/validators.js.map +1 -1
  79. package/dist/browser-react.d.ts +1 -1
  80. package/dist/browser-react.js +1 -1
  81. package/dist/browser.d.ts +6 -7
  82. package/dist/browser.d.ts.map +1 -1
  83. package/dist/browser.js +4 -5
  84. package/dist/browser.js.map +1 -1
  85. package/dist/cli.d.ts +1 -1
  86. package/dist/cli.js +12 -3
  87. package/dist/cli.js.map +1 -1
  88. package/dist/expo-react.d.ts +1 -1
  89. package/dist/expo-react.js +1 -1
  90. package/dist/expo.d.ts +1 -2
  91. package/dist/expo.js +1 -2
  92. package/dist/index.d.ts +3 -7
  93. package/dist/index.js +3 -8
  94. package/dist/next-config.d.ts +1 -2
  95. package/dist/next-config.js +1 -2
  96. package/dist/next.d.ts +1 -3
  97. package/dist/next.js +1 -3
  98. package/dist/node-ipc-react.d.ts +1 -1
  99. package/dist/node-ipc-react.js +1 -1
  100. package/dist/node-ipc.d.ts +1 -2
  101. package/dist/node-ipc.js +1 -2
  102. package/dist/node.d.ts +1 -4
  103. package/dist/node.js +1 -3
  104. package/dist/react.d.ts +1 -2
  105. package/dist/react.js +1 -2
  106. package/dist/svelte.d.ts +1 -2
  107. package/dist/svelte.js +1 -2
  108. package/package.json +6 -3
  109. package/dist/core/src/cli.d.ts.map +0 -1
  110. package/dist/core/src/cli.js +0 -1196
  111. package/dist/core/src/cli.js.map +0 -1
  112. package/dist/core/src/index.js +0 -7
  113. package/dist/core/src/runtime/devtools.d.ts +0 -7
  114. package/dist/core/src/runtime/devtools.d.ts.map +0 -1
  115. package/dist/core/src/runtime/devtools.js +0 -300
  116. package/dist/core/src/runtime/devtools.js.map +0 -1
  117. package/dist/core/src/runtime/functions.d.ts +0 -123
  118. package/dist/core/src/runtime/functions.d.ts.map +0 -1
  119. package/dist/core/src/runtime/functions.js +0 -71
  120. package/dist/core/src/runtime/functions.js.map +0 -1
  121. package/dist/core/src/runtime/id.d.ts +0 -13
  122. package/dist/core/src/runtime/id.d.ts.map +0 -1
  123. package/dist/core/src/runtime/id.js +0 -28
  124. package/dist/core/src/runtime/id.js.map +0 -1
  125. package/dist/core/src/runtime/runtime.d.ts +0 -371
  126. package/dist/core/src/runtime/runtime.d.ts.map +0 -1
  127. package/dist/core/src/runtime/runtime.js +0 -1143
  128. package/dist/core/src/runtime/runtime.js.map +0 -1
  129. package/dist/devtools-protocol/src/index.d.ts +0 -201
  130. package/dist/devtools-protocol/src/index.d.ts.map +0 -1
  131. package/dist/next/src/config.d.ts +0 -17
  132. package/dist/next/src/config.d.ts.map +0 -1
  133. package/dist/next/src/config.js +0 -73
  134. package/dist/next/src/config.js.map +0 -1
  135. package/dist/next/src/index.d.ts +0 -80
  136. package/dist/next/src/index.d.ts.map +0 -1
  137. package/dist/next/src/index.js +0 -82
  138. package/dist/next/src/index.js.map +0 -1
  139. package/dist/platform-expo/src/index.d.ts +0 -96
  140. package/dist/platform-expo/src/index.d.ts.map +0 -1
  141. package/dist/platform-expo/src/index.js +0 -198
  142. package/dist/platform-expo/src/index.js.map +0 -1
  143. package/dist/platform-expo/src/react.d.ts +0 -26
  144. package/dist/platform-expo/src/react.d.ts.map +0 -1
  145. package/dist/platform-expo/src/react.js +0 -30
  146. package/dist/platform-expo/src/react.js.map +0 -1
  147. package/dist/platform-node/src/index.d.ts +0 -145
  148. package/dist/platform-node/src/index.d.ts.map +0 -1
  149. package/dist/platform-node/src/index.js +0 -407
  150. package/dist/platform-node/src/index.js.map +0 -1
  151. package/dist/platform-node/src/ipc-react.d.ts +0 -25
  152. package/dist/platform-node/src/ipc-react.d.ts.map +0 -1
  153. package/dist/platform-node/src/ipc-react.js +0 -21
  154. package/dist/platform-node/src/ipc-react.js.map +0 -1
  155. package/dist/platform-node/src/ipc.d.ts +0 -76
  156. package/dist/platform-node/src/ipc.d.ts.map +0 -1
  157. package/dist/platform-node/src/ipc.js +0 -344
  158. package/dist/platform-node/src/ipc.js.map +0 -1
  159. package/dist/platform-web/src/index.d.ts +0 -106
  160. package/dist/platform-web/src/index.d.ts.map +0 -1
  161. package/dist/platform-web/src/index.js +0 -311
  162. package/dist/platform-web/src/index.js.map +0 -1
  163. package/dist/platform-web/src/indexeddb.js +0 -125
  164. package/dist/platform-web/src/indexeddb.js.map +0 -1
  165. package/dist/platform-web/src/opfs.js +0 -146
  166. package/dist/platform-web/src/opfs.js.map +0 -1
  167. package/dist/platform-web/src/persistence.d.ts +0 -20
  168. package/dist/platform-web/src/persistence.d.ts.map +0 -1
  169. package/dist/platform-web/src/persistence.js +0 -23
  170. package/dist/platform-web/src/persistence.js.map +0 -1
  171. package/dist/platform-web/src/react.d.ts +0 -35
  172. package/dist/platform-web/src/react.d.ts.map +0 -1
  173. package/dist/platform-web/src/react.js +0 -42
  174. package/dist/platform-web/src/react.js.map +0 -1
  175. package/dist/platform-web/src/sqljs.js +0 -133
  176. package/dist/platform-web/src/sqljs.js.map +0 -1
  177. package/dist/platform-web/src/worker.d.ts +0 -79
  178. package/dist/platform-web/src/worker.d.ts.map +0 -1
  179. package/dist/platform-web/src/worker.js +0 -308
  180. package/dist/platform-web/src/worker.js.map +0 -1
  181. package/dist/react/src/index.d.ts +0 -59
  182. package/dist/react/src/index.d.ts.map +0 -1
  183. package/dist/react/src/index.js +0 -151
  184. package/dist/react/src/index.js.map +0 -1
  185. package/dist/schema/src/definition.d.ts +0 -98
  186. package/dist/schema/src/definition.d.ts.map +0 -1
  187. package/dist/schema/src/definition.js +0 -84
  188. package/dist/schema/src/definition.js.map +0 -1
  189. package/dist/schema/src/planner.d.ts +0 -42
  190. package/dist/schema/src/planner.d.ts.map +0 -1
  191. package/dist/schema/src/planner.js +0 -131
  192. package/dist/schema/src/planner.js.map +0 -1
  193. package/dist/schema/src/validators.d.ts +0 -194
  194. package/dist/schema/src/validators.d.ts.map +0 -1
  195. package/dist/schema/src/validators.js +0 -158
  196. package/dist/schema/src/validators.js.map +0 -1
  197. package/dist/svelte/src/index.d.ts +0 -44
  198. package/dist/svelte/src/index.d.ts.map +0 -1
  199. package/dist/svelte/src/index.js +0 -75
  200. package/dist/svelte/src/index.js.map +0 -1
@@ -1,19 +1,28 @@
1
1
  import { Directory, File, Paths } from "expo-file-system";
2
2
  import { defaultDatabaseDirectory, openDatabaseSync } from "expo-sqlite";
3
3
  import { SyncoreRuntime } from "../core/index.mjs";
4
+ import { BroadcastChannelExternalChangeSignal, createDefaultSyncChannelName } from "../platform-web/index.js";
4
5
  //#region src/index.ts
5
6
  /**
6
7
  * Create an Expo Syncore runtime backed by `expo-sqlite` and local file storage.
7
8
  */
8
9
  function createExpoSyncoreRuntime(options) {
9
10
  const databaseDirectory = options.databaseDirectory ?? (typeof defaultDatabaseDirectory === "string" ? defaultDatabaseDirectory : void 0);
10
- const driver = options.driver ?? new ExpoSqliteDriver(openDatabaseSync(options.databaseName ?? "syncore.db", void 0, databaseDirectory));
11
+ const driver = options.driver ?? new ExpoSqliteDriver(openDatabaseSync(options.databaseName ?? "syncore.db", void 0, databaseDirectory), {
12
+ databaseName: options.databaseName ?? "syncore.db",
13
+ ...databaseDirectory ? { databaseDirectory } : {}
14
+ });
11
15
  const storage = options.storage ?? new ExpoFileStorageAdapter(options.storageDirectoryName ?? "syncore-storage");
16
+ const isWebEnvironment = typeof window !== "undefined" && typeof document !== "undefined";
17
+ const webExternalChangeSignal = isWebEnvironment && !options.externalChangeSignal ? new BroadcastChannelExternalChangeSignal({ channelName: createDefaultSyncChannelName(options.databaseName ?? "syncore.db") }) : void 0;
18
+ const webExternalChangeApplier = isWebEnvironment && !options.externalChangeApplier && driver instanceof ExpoSqliteDriver ? new ExpoWebExternalChangeApplier(driver) : void 0;
12
19
  return new SyncoreRuntime({
13
20
  schema: options.schema,
14
21
  functions: options.functions,
15
22
  driver,
16
23
  storage,
24
+ ...isWebEnvironment && options.externalChangeSignal ? { externalChangeSignal: options.externalChangeSignal } : isWebEnvironment && webExternalChangeSignal ? { externalChangeSignal: webExternalChangeSignal } : {},
25
+ ...isWebEnvironment && options.externalChangeApplier ? { externalChangeApplier: options.externalChangeApplier } : isWebEnvironment && webExternalChangeApplier ? { externalChangeApplier: webExternalChangeApplier } : {},
17
26
  platform: options.platform ?? "expo",
18
27
  ...options.capabilities ? { capabilities: options.capabilities } : {},
19
28
  ...options.devtools ? { devtools: options.devtools } : {},
@@ -39,7 +48,7 @@ function createExpoSyncoreBootstrap(options) {
39
48
  };
40
49
  return {
41
50
  getRuntime() {
42
- return ensureRuntime();
51
+ throw new Error("createExpoSyncoreBootstrap().getRuntime() is not available synchronously. Use getClient() instead.");
43
52
  },
44
53
  async getClient() {
45
54
  if (!started) {
@@ -66,8 +75,12 @@ function createExpoSyncoreBootstrap(options) {
66
75
  var ExpoSqliteDriver = class {
67
76
  transactionDepth = 0;
68
77
  closed = false;
69
- constructor(database) {
78
+ databaseName;
79
+ databaseDirectory;
80
+ constructor(database, options) {
70
81
  this.database = database;
82
+ this.databaseName = options?.databaseName ?? "syncore.db";
83
+ this.databaseDirectory = options?.databaseDirectory;
71
84
  }
72
85
  async exec(sql) {
73
86
  this.ensureOpen();
@@ -130,6 +143,23 @@ var ExpoSqliteDriver = class {
130
143
  ensureOpen() {
131
144
  if (this.closed) throw new Error("The Expo SQLite driver is already closed.");
132
145
  }
146
+ async reopen() {
147
+ this.ensureOpen();
148
+ await this.database.closeAsync();
149
+ this.database = openDatabaseSync(this.databaseName, void 0, this.databaseDirectory);
150
+ }
151
+ };
152
+ var ExpoWebExternalChangeApplier = class {
153
+ constructor(driver) {
154
+ this.driver = driver;
155
+ }
156
+ async applyExternalChange(event) {
157
+ if (event.scope === "database" || event.scope === "all") await this.driver.reopen();
158
+ return {
159
+ databaseChanged: event.scope === "database" || event.scope === "all",
160
+ storageChanged: event.scope === "storage" || event.scope === "all"
161
+ };
162
+ }
133
163
  };
134
164
  /**
135
165
  * Syncore file/blob storage backed by the Expo file system.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { Directory, File, Paths } from \"expo-file-system\";\r\nimport {\r\n defaultDatabaseDirectory,\r\n openDatabaseSync,\r\n type SQLiteDatabase\r\n} from \"expo-sqlite\";\r\nimport {\r\n type AnySyncoreSchema,\r\n type DevtoolsSink,\r\n SyncoreRuntime,\r\n type SchedulerOptions,\r\n type SyncoreCapabilities,\r\n type SyncoreExperimentalPlugin,\r\n type SyncoreRuntimeOptions,\r\n type SyncoreSqlDriver,\r\n type SyncoreStorageAdapter,\r\n type StorageObject,\r\n type StorageWriteInput\r\n} from \"@syncore/core\";\r\n\r\nexport type ExpoSyncoreSchema = AnySyncoreSchema;\r\n\r\n/**\r\n * Options for constructing an Expo Syncore runtime.\r\n *\r\n * Use this when you want Syncore to persist locally with `expo-sqlite` and the\r\n * Expo file system.\r\n */\r\nexport interface CreateExpoRuntimeOptions {\r\n /** The schema for the local Syncore app. */\r\n schema: ExpoSyncoreSchema;\r\n\r\n /** The generated function registry for the local Syncore app. */\r\n functions: SyncoreRuntimeOptions<ExpoSyncoreSchema>[\"functions\"];\r\n\r\n /** Optional platform capabilities exposed to function handlers. */\r\n capabilities?: SyncoreCapabilities;\r\n\r\n /** Optional custom SQL driver. Defaults to `expo-sqlite`. */\r\n driver?: SyncoreSqlDriver;\r\n\r\n /** Optional experimental plugins for runtime hooks. */\r\n experimentalPlugins?: Array<SyncoreExperimentalPlugin<ExpoSyncoreSchema>>;\r\n\r\n /** Optional custom file/blob storage adapter. */\r\n storage?: SyncoreStorageAdapter;\r\n\r\n /** The SQLite database filename to open locally. */\r\n databaseName?: string;\r\n\r\n /** Optional directory for the SQLite database file. */\r\n databaseDirectory?: string;\r\n\r\n /** Directory name used for local file/blob storage. */\r\n storageDirectoryName?: string;\r\n\r\n /** Optional runtime platform label shown in devtools snapshots. */\r\n platform?: string;\r\n\r\n /** Optional devtools sink used during development. */\r\n devtools?: DevtoolsSink;\r\n\r\n /** Optional scheduler configuration for jobs and recurring work. */\r\n scheduler?: SchedulerOptions;\r\n}\r\n\r\n/**\r\n * A reusable bootstrap that lazily creates, starts, and stops an Expo Syncore runtime.\r\n */\r\nexport interface ExpoSyncoreBootstrap {\r\n /** Return the local runtime instance, creating it if needed. */\r\n getRuntime(): SyncoreRuntime<ExpoSyncoreSchema>;\r\n\r\n /** Start the runtime if needed and return a ready client. */\r\n getClient(): Promise<\r\n ReturnType<SyncoreRuntime<ExpoSyncoreSchema>[\"createClient\"]>\r\n >;\r\n\r\n /** Stop the current runtime instance if one exists. */\r\n stop(): Promise<void>;\r\n\r\n /** Fully discard the runtime so the next call recreates it. */\r\n reset(): Promise<void>;\r\n}\r\n\r\n/**\r\n * Create an Expo Syncore runtime backed by `expo-sqlite` and local file storage.\r\n */\r\nexport function createExpoSyncoreRuntime(\r\n options: CreateExpoRuntimeOptions\r\n): SyncoreRuntime<ExpoSyncoreSchema> {\r\n const databaseDirectory =\r\n options.databaseDirectory ??\r\n (typeof defaultDatabaseDirectory === \"string\"\r\n ? defaultDatabaseDirectory\r\n : undefined);\r\n const driver =\r\n options.driver ??\r\n new ExpoSqliteDriver(\r\n openDatabaseSync(\r\n options.databaseName ?? \"syncore.db\",\r\n undefined,\r\n databaseDirectory\r\n )\r\n );\r\n const storage =\r\n options.storage ??\r\n new ExpoFileStorageAdapter(\r\n options.storageDirectoryName ?? \"syncore-storage\"\r\n );\r\n\r\n return new SyncoreRuntime({\r\n schema: options.schema,\r\n functions: options.functions,\r\n driver,\r\n storage,\r\n platform: options.platform ?? \"expo\",\r\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\r\n ...(options.devtools ? { devtools: options.devtools } : {}),\r\n ...(options.experimentalPlugins\r\n ? { experimentalPlugins: options.experimentalPlugins }\r\n : {}),\r\n ...(options.scheduler ? { scheduler: options.scheduler } : {})\r\n });\r\n}\r\n\r\n/**\r\n * Create a same-process Syncore client from a started Expo runtime.\r\n */\r\nexport function createExpoSyncoreClient(\r\n runtime: SyncoreRuntime<ExpoSyncoreSchema>\r\n) {\r\n return runtime.createClient();\r\n}\r\n\r\n/**\r\n * Create a reusable Expo bootstrap that lazily starts the local runtime.\r\n */\r\nexport function createExpoSyncoreBootstrap(\r\n options: CreateExpoRuntimeOptions\r\n): ExpoSyncoreBootstrap {\r\n let runtime: SyncoreRuntime<ExpoSyncoreSchema> | null = null;\r\n let started: Promise<\r\n ReturnType<SyncoreRuntime<ExpoSyncoreSchema>[\"createClient\"]>\r\n > | null = null;\r\n\r\n const ensureRuntime = () => {\r\n runtime ??= createExpoSyncoreRuntime(options);\r\n return runtime;\r\n };\r\n\r\n return {\r\n getRuntime() {\r\n return ensureRuntime();\r\n },\r\n async getClient() {\r\n if (!started) {\r\n const activeRuntime = ensureRuntime();\r\n started = activeRuntime\r\n .start()\r\n .then(() => activeRuntime.createClient());\r\n }\r\n return started;\r\n },\r\n async stop() {\r\n if (!runtime) {\r\n return;\r\n }\r\n await runtime.stop();\r\n started = null;\r\n },\r\n async reset() {\r\n if (runtime) {\r\n await runtime.stop();\r\n }\r\n runtime = null;\r\n started = null;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Syncore SQL driver implementation backed by `expo-sqlite`.\r\n */\r\nexport class ExpoSqliteDriver implements SyncoreSqlDriver {\r\n private transactionDepth = 0;\r\n private closed = false;\r\n\r\n constructor(private readonly database: SQLiteDatabase) {}\r\n\r\n async exec(sql: string): Promise<void> {\r\n this.ensureOpen();\r\n await this.database.execAsync(sql);\r\n }\r\n\r\n async run(\r\n sql: string,\r\n params: unknown[] = []\r\n ): Promise<{ changes: number; lastInsertRowid?: number | string }> {\r\n this.ensureOpen();\r\n const result = await this.database.runAsync(sql, normalizeParams(params));\r\n return {\r\n changes: result.changes,\r\n lastInsertRowid: result.lastInsertRowId\r\n };\r\n }\r\n\r\n async get<T>(sql: string, params: unknown[] = []): Promise<T | undefined> {\r\n this.ensureOpen();\r\n const row = await this.database.getFirstAsync<T>(\r\n sql,\r\n normalizeParams(params)\r\n );\r\n return row ?? undefined;\r\n }\r\n\r\n async all<T>(sql: string, params: unknown[] = []): Promise<T[]> {\r\n this.ensureOpen();\r\n return this.database.getAllAsync<T>(sql, normalizeParams(params));\r\n }\r\n\r\n async withTransaction<T>(callback: () => Promise<T>): Promise<T> {\r\n this.ensureOpen();\r\n if (this.transactionDepth > 0) {\r\n return this.withSavepoint(`nested_${this.transactionDepth}`, callback);\r\n }\r\n\r\n this.transactionDepth += 1;\r\n await this.database.execAsync(\"BEGIN IMMEDIATE\");\r\n try {\r\n const result = await callback();\r\n await this.database.execAsync(\"COMMIT\");\r\n return result;\r\n } catch (error) {\r\n await this.database.execAsync(\"ROLLBACK\");\r\n throw error;\r\n } finally {\r\n this.transactionDepth -= 1;\r\n }\r\n }\r\n\r\n async withSavepoint<T>(name: string, callback: () => Promise<T>): Promise<T> {\r\n this.ensureOpen();\r\n const safeName = name.replaceAll(/[^a-zA-Z0-9_]/g, \"_\");\r\n this.transactionDepth += 1;\r\n await this.database.execAsync(`SAVEPOINT ${safeName}`);\r\n try {\r\n const result = await callback();\r\n await this.database.execAsync(`RELEASE SAVEPOINT ${safeName}`);\r\n return result;\r\n } catch (error) {\r\n await this.database.execAsync(`ROLLBACK TO SAVEPOINT ${safeName}`);\r\n await this.database.execAsync(`RELEASE SAVEPOINT ${safeName}`);\r\n throw error;\r\n } finally {\r\n this.transactionDepth -= 1;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this.closed) {\r\n return;\r\n }\r\n await this.database.closeAsync();\r\n this.closed = true;\r\n }\r\n\r\n private ensureOpen(): void {\r\n if (this.closed) {\r\n throw new Error(\"The Expo SQLite driver is already closed.\");\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Syncore file/blob storage backed by the Expo file system.\r\n */\r\nexport class ExpoFileStorageAdapter implements SyncoreStorageAdapter {\r\n private readonly rootDirectory: Directory;\r\n\r\n constructor(storageDirectoryName: string) {\r\n this.rootDirectory = new Directory(Paths.document, storageDirectoryName);\r\n if (!this.rootDirectory.exists) {\r\n this.rootDirectory.create({ idempotent: true, intermediates: true });\r\n }\r\n }\r\n\r\n async put(id: string, input: StorageWriteInput): Promise<StorageObject> {\r\n const file = new File(this.rootDirectory, id);\r\n if (!file.exists) {\r\n file.create({ intermediates: true, overwrite: true });\r\n }\r\n const bytes = normalizeBinary(input.data);\r\n file.write(bytes);\r\n return {\r\n id,\r\n path: file.uri,\r\n size: bytes.byteLength,\r\n contentType: input.contentType ?? null\r\n };\r\n }\r\n\r\n async get(id: string): Promise<StorageObject | null> {\r\n const file = new File(this.rootDirectory, id);\r\n if (!file.exists) {\r\n return null;\r\n }\r\n return {\r\n id,\r\n path: file.uri,\r\n size: file.size,\r\n contentType: file.type || null\r\n };\r\n }\r\n\r\n async read(id: string): Promise<Uint8Array | null> {\r\n const file = new File(this.rootDirectory, id);\r\n if (!file.exists) {\r\n return null;\r\n }\r\n return file.bytes();\r\n }\r\n\r\n async delete(id: string): Promise<void> {\r\n const file = new File(this.rootDirectory, id);\r\n if (file.exists) {\r\n file.delete();\r\n }\r\n }\r\n}\r\n\r\nfunction normalizeParams(\r\n values: unknown[]\r\n): Array<string | number | Uint8Array | null> {\r\n return values.map((value) => {\r\n if (typeof value === \"boolean\") {\r\n return value ? 1 : 0;\r\n }\r\n if (\r\n value === null ||\r\n typeof value === \"string\" ||\r\n typeof value === \"number\" ||\r\n value instanceof Uint8Array\r\n ) {\r\n return value;\r\n }\r\n if (value instanceof ArrayBuffer) {\r\n return new Uint8Array(value);\r\n }\r\n return JSON.stringify(value);\r\n });\r\n}\r\n\r\nfunction normalizeBinary(data: StorageWriteInput[\"data\"]): Uint8Array {\r\n if (typeof data === \"string\") {\r\n return new TextEncoder().encode(data);\r\n }\r\n if (data instanceof Uint8Array) {\r\n return data;\r\n }\r\n return new Uint8Array(data);\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { Directory, File, Paths } from \"expo-file-system\";\nimport {\n defaultDatabaseDirectory,\n openDatabaseSync,\n type SQLiteDatabase\n} from \"expo-sqlite\";\nimport {\n type AnySyncoreSchema,\n type DevtoolsSink,\n type SyncoreExternalChangeApplier,\n type SyncoreExternalChangeSignal,\n SyncoreRuntime,\n type SchedulerOptions,\n type SyncoreCapabilities,\n type SyncoreExperimentalPlugin,\n type SyncoreRuntimeOptions,\n type SyncoreSqlDriver,\n type SyncoreStorageAdapter,\n type StorageObject,\n type StorageWriteInput\n} from \"@syncore/core\";\nimport {\n BroadcastChannelExternalChangeSignal,\n createDefaultSyncChannelName\n} from \"@syncore/platform-web\";\n\nexport type ExpoSyncoreSchema = AnySyncoreSchema;\n\n/**\n * Options for constructing an Expo Syncore runtime.\n *\n * Use this when you want Syncore to persist locally with `expo-sqlite` and the\n * Expo file system.\n */\nexport interface CreateExpoRuntimeOptions {\n /** The schema for the local Syncore app. */\n schema: ExpoSyncoreSchema;\n\n /** The generated function registry for the local Syncore app. */\n functions: SyncoreRuntimeOptions<ExpoSyncoreSchema>[\"functions\"];\n\n /** Optional platform capabilities exposed to function handlers. */\n capabilities?: SyncoreCapabilities;\n\n /** Optional custom SQL driver. Defaults to `expo-sqlite`. */\n driver?: SyncoreSqlDriver;\n\n /** Optional experimental plugins for runtime hooks. */\n experimentalPlugins?: Array<SyncoreExperimentalPlugin<ExpoSyncoreSchema>>;\n\n /** Optional custom file/blob storage adapter. */\n storage?: SyncoreStorageAdapter;\n\n /** The SQLite database filename to open locally. */\n databaseName?: string;\n\n /** Optional directory for the SQLite database file. */\n databaseDirectory?: string;\n\n /** Directory name used for local file/blob storage. */\n storageDirectoryName?: string;\n\n /** Optional runtime platform label shown in devtools snapshots. */\n platform?: string;\n\n /** Optional devtools sink used during development. */\n devtools?: DevtoolsSink;\n\n /** Optional scheduler configuration for jobs and recurring work. */\n scheduler?: SchedulerOptions;\n\n /** Optional shared signal used to synchronize browser instances. */\n externalChangeSignal?: SyncoreExternalChangeSignal;\n\n /** Optional applier used to reconcile browser-side external changes. */\n externalChangeApplier?: SyncoreExternalChangeApplier;\n}\n\n/**\n * A reusable bootstrap that lazily creates, starts, and stops an Expo Syncore runtime.\n */\nexport interface ExpoSyncoreBootstrap {\n /** Synchronous access is unavailable; use `getClient()` instead. */\n getRuntime(): never;\n\n /** Start the runtime if needed and return a ready client. */\n getClient(): Promise<\n ReturnType<SyncoreRuntime<ExpoSyncoreSchema>[\"createClient\"]>\n >;\n\n /** Stop the current runtime instance if one exists. */\n stop(): Promise<void>;\n\n /** Fully discard the runtime so the next call recreates it. */\n reset(): Promise<void>;\n}\n\n/**\n * Create an Expo Syncore runtime backed by `expo-sqlite` and local file storage.\n */\nexport function createExpoSyncoreRuntime(\n options: CreateExpoRuntimeOptions\n): SyncoreRuntime<ExpoSyncoreSchema> {\n const databaseDirectory =\n options.databaseDirectory ??\n (typeof defaultDatabaseDirectory === \"string\"\n ? defaultDatabaseDirectory\n : undefined);\n const driver =\n options.driver ??\n new ExpoSqliteDriver(\n openDatabaseSync(\n options.databaseName ?? \"syncore.db\",\n undefined,\n databaseDirectory\n ),\n {\n databaseName: options.databaseName ?? \"syncore.db\",\n ...(databaseDirectory ? { databaseDirectory } : {})\n }\n );\n const storage =\n options.storage ??\n new ExpoFileStorageAdapter(\n options.storageDirectoryName ?? \"syncore-storage\"\n );\n const isWebEnvironment =\n typeof window !== \"undefined\" && typeof document !== \"undefined\";\n const webExternalChangeSignal =\n isWebEnvironment && !options.externalChangeSignal\n ? new BroadcastChannelExternalChangeSignal({\n channelName: createDefaultSyncChannelName(\n options.databaseName ?? \"syncore.db\"\n )\n })\n : undefined;\n const webExternalChangeApplier =\n isWebEnvironment &&\n !options.externalChangeApplier &&\n driver instanceof ExpoSqliteDriver\n ? new ExpoWebExternalChangeApplier(driver)\n : undefined;\n\n return new SyncoreRuntime({\n schema: options.schema,\n functions: options.functions,\n driver,\n storage,\n ...(isWebEnvironment && options.externalChangeSignal\n ? { externalChangeSignal: options.externalChangeSignal }\n : isWebEnvironment && webExternalChangeSignal\n ? { externalChangeSignal: webExternalChangeSignal }\n : {}),\n ...(isWebEnvironment && options.externalChangeApplier\n ? { externalChangeApplier: options.externalChangeApplier }\n : isWebEnvironment && webExternalChangeApplier\n ? { externalChangeApplier: webExternalChangeApplier }\n : {}),\n platform: options.platform ?? \"expo\",\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\n ...(options.devtools ? { devtools: options.devtools } : {}),\n ...(options.experimentalPlugins\n ? { experimentalPlugins: options.experimentalPlugins }\n : {}),\n ...(options.scheduler ? { scheduler: options.scheduler } : {})\n });\n}\n\n/**\n * Create a same-process Syncore client from a started Expo runtime.\n */\nexport function createExpoSyncoreClient(\n runtime: SyncoreRuntime<ExpoSyncoreSchema>\n) {\n return runtime.createClient();\n}\n\n/**\n * Create a reusable Expo bootstrap that lazily starts the local runtime.\n */\nexport function createExpoSyncoreBootstrap(\n options: CreateExpoRuntimeOptions\n): ExpoSyncoreBootstrap {\n let runtime: SyncoreRuntime<ExpoSyncoreSchema> | null = null;\n let started: Promise<\n ReturnType<SyncoreRuntime<ExpoSyncoreSchema>[\"createClient\"]>\n > | null = null;\n\n const ensureRuntime = () => {\n runtime ??= createExpoSyncoreRuntime(options);\n return runtime;\n };\n\n return {\n getRuntime() {\n throw new Error(\n \"createExpoSyncoreBootstrap().getRuntime() is not available synchronously. Use getClient() instead.\"\n );\n },\n async getClient() {\n if (!started) {\n const activeRuntime = ensureRuntime();\n started = activeRuntime\n .start()\n .then(() => activeRuntime.createClient());\n }\n return started;\n },\n async stop() {\n if (!runtime) {\n return;\n }\n await runtime.stop();\n started = null;\n },\n async reset() {\n if (runtime) {\n await runtime.stop();\n }\n runtime = null;\n started = null;\n }\n };\n}\n\n/**\n * Syncore SQL driver implementation backed by `expo-sqlite`.\n */\nexport class ExpoSqliteDriver implements SyncoreSqlDriver {\n private transactionDepth = 0;\n private closed = false;\n private readonly databaseName: string;\n private readonly databaseDirectory: string | undefined;\n\n constructor(\n private database: SQLiteDatabase,\n options?: {\n databaseName?: string;\n databaseDirectory?: string;\n }\n ) {\n this.databaseName = options?.databaseName ?? \"syncore.db\";\n this.databaseDirectory = options?.databaseDirectory;\n }\n\n async exec(sql: string): Promise<void> {\n this.ensureOpen();\n await this.database.execAsync(sql);\n }\n\n async run(\n sql: string,\n params: unknown[] = []\n ): Promise<{ changes: number; lastInsertRowid?: number | string }> {\n this.ensureOpen();\n const result = await this.database.runAsync(sql, normalizeParams(params));\n return {\n changes: result.changes,\n lastInsertRowid: result.lastInsertRowId\n };\n }\n\n async get<T>(sql: string, params: unknown[] = []): Promise<T | undefined> {\n this.ensureOpen();\n const row = await this.database.getFirstAsync<T>(\n sql,\n normalizeParams(params)\n );\n return row ?? undefined;\n }\n\n async all<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n this.ensureOpen();\n return this.database.getAllAsync<T>(sql, normalizeParams(params));\n }\n\n async withTransaction<T>(callback: () => Promise<T>): Promise<T> {\n this.ensureOpen();\n if (this.transactionDepth > 0) {\n return this.withSavepoint(`nested_${this.transactionDepth}`, callback);\n }\n\n this.transactionDepth += 1;\n await this.database.execAsync(\"BEGIN IMMEDIATE\");\n try {\n const result = await callback();\n await this.database.execAsync(\"COMMIT\");\n return result;\n } catch (error) {\n await this.database.execAsync(\"ROLLBACK\");\n throw error;\n } finally {\n this.transactionDepth -= 1;\n }\n }\n\n async withSavepoint<T>(name: string, callback: () => Promise<T>): Promise<T> {\n this.ensureOpen();\n const safeName = name.replaceAll(/[^a-zA-Z0-9_]/g, \"_\");\n this.transactionDepth += 1;\n await this.database.execAsync(`SAVEPOINT ${safeName}`);\n try {\n const result = await callback();\n await this.database.execAsync(`RELEASE SAVEPOINT ${safeName}`);\n return result;\n } catch (error) {\n await this.database.execAsync(`ROLLBACK TO SAVEPOINT ${safeName}`);\n await this.database.execAsync(`RELEASE SAVEPOINT ${safeName}`);\n throw error;\n } finally {\n this.transactionDepth -= 1;\n }\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n await this.database.closeAsync();\n this.closed = true;\n }\n\n private ensureOpen(): void {\n if (this.closed) {\n throw new Error(\"The Expo SQLite driver is already closed.\");\n }\n }\n\n async reopen(): Promise<void> {\n this.ensureOpen();\n await this.database.closeAsync();\n this.database = openDatabaseSync(\n this.databaseName,\n undefined,\n this.databaseDirectory\n );\n }\n}\n\nclass ExpoWebExternalChangeApplier implements SyncoreExternalChangeApplier {\n constructor(private readonly driver: ExpoSqliteDriver) {}\n\n async applyExternalChange(event: { scope: \"database\" | \"storage\" | \"all\" }) {\n if (event.scope === \"database\" || event.scope === \"all\") {\n await this.driver.reopen();\n }\n return {\n databaseChanged: event.scope === \"database\" || event.scope === \"all\",\n storageChanged: event.scope === \"storage\" || event.scope === \"all\"\n };\n }\n}\n\n/**\n * Syncore file/blob storage backed by the Expo file system.\n */\nexport class ExpoFileStorageAdapter implements SyncoreStorageAdapter {\n private readonly rootDirectory: Directory;\n\n constructor(storageDirectoryName: string) {\n this.rootDirectory = new Directory(Paths.document, storageDirectoryName);\n if (!this.rootDirectory.exists) {\n this.rootDirectory.create({ idempotent: true, intermediates: true });\n }\n }\n\n async put(id: string, input: StorageWriteInput): Promise<StorageObject> {\n const file = new File(this.rootDirectory, id);\n if (!file.exists) {\n file.create({ intermediates: true, overwrite: true });\n }\n const bytes = normalizeBinary(input.data);\n file.write(bytes);\n return {\n id,\n path: file.uri,\n size: bytes.byteLength,\n contentType: input.contentType ?? null\n };\n }\n\n async get(id: string): Promise<StorageObject | null> {\n const file = new File(this.rootDirectory, id);\n if (!file.exists) {\n return null;\n }\n return {\n id,\n path: file.uri,\n size: file.size,\n contentType: file.type || null\n };\n }\n\n async read(id: string): Promise<Uint8Array | null> {\n const file = new File(this.rootDirectory, id);\n if (!file.exists) {\n return null;\n }\n return file.bytes();\n }\n\n async delete(id: string): Promise<void> {\n const file = new File(this.rootDirectory, id);\n if (file.exists) {\n file.delete();\n }\n }\n}\n\nfunction normalizeParams(\n values: unknown[]\n): Array<string | number | Uint8Array | null> {\n return values.map((value) => {\n if (typeof value === \"boolean\") {\n return value ? 1 : 0;\n }\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n value instanceof Uint8Array\n ) {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n return JSON.stringify(value);\n });\n}\n\nfunction normalizeBinary(data: StorageWriteInput[\"data\"]): Uint8Array {\n if (typeof data === \"string\") {\n return new TextEncoder().encode(data);\n }\n if (data instanceof Uint8Array) {\n return data;\n }\n return new Uint8Array(data);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\r\nimport type { ReactNode } from \"react\";\r\nimport { SyncoreProvider } from \"@syncore/react\";\r\nimport type { SyncoreClient } from \"@syncore/core\";\r\nimport type { ExpoSyncoreBootstrap } from \"./index.js\";\r\n\r\ntype ExpoSyncoreClient = SyncoreClient;\r\n\r\n/**\r\n * Props for {@link SyncoreExpoProvider}.\r\n */\r\nexport interface SyncoreExpoProviderProps {\r\n /** The bootstrap created with `createExpoSyncoreBootstrap`. */\r\n bootstrap: ExpoSyncoreBootstrap;\r\n\r\n /** The React subtree that should receive the Syncore client. */\r\n children: ReactNode;\r\n\r\n /** Optional fallback content rendered while the local runtime starts. */\r\n fallback?: ReactNode;\r\n}\r\n\r\n/**\r\n * Start an Expo Syncore bootstrap and provide its client to React descendants.\r\n */\r\nexport function SyncoreExpoProvider({\r\n bootstrap,\r\n children,\r\n fallback = null\r\n}: SyncoreExpoProviderProps): ReactNode {\r\n const [client, setClient] = useState<ExpoSyncoreClient | null>(null);\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n void bootstrap.getClient().then((nextClient: ExpoSyncoreClient) => {\r\n if (!cancelled) {\r\n setClient(nextClient);\r\n }\r\n });\r\n\r\n return () => {\r\n cancelled = true;\r\n setClient(null);\r\n void bootstrap.stop();\r\n };\r\n }, [bootstrap]);\r\n\r\n if (!client) {\r\n return fallback;\r\n }\r\n\r\n return <SyncoreProvider client={client}>{children}</SyncoreProvider>;\r\n}\r\n"],"mappings":";;;;;;;AAyBA,SAAgB,oBAAoB,EAClC,WACA,UACA,WAAW,QAC2B;CACtC,MAAM,CAAC,QAAQ,aAAa,SAAmC,KAAK;AAEpE,iBAAgB;EACd,IAAI,YAAY;AACX,YAAU,WAAW,CAAC,MAAM,eAAkC;AACjE,OAAI,CAAC,UACH,WAAU,WAAW;IAEvB;AAEF,eAAa;AACX,eAAY;AACZ,aAAU,KAAK;AACV,aAAU,MAAM;;IAEtB,CAAC,UAAU,CAAC;AAEf,KAAI,CAAC,OACH,QAAO;AAGT,QAAO,oBAAC,iBAAD;EAAyB;EAAS;EAA2B,CAAA"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { SyncoreProvider } from \"@syncore/react\";\nimport type { SyncoreClient } from \"@syncore/core\";\nimport type { ExpoSyncoreBootstrap } from \"./index.js\";\n\ntype ExpoSyncoreClient = SyncoreClient;\n\n/**\n * Props for {@link SyncoreExpoProvider}.\n */\nexport interface SyncoreExpoProviderProps {\n /** The bootstrap created with `createExpoSyncoreBootstrap`. */\n bootstrap: ExpoSyncoreBootstrap;\n\n /** The React subtree that should receive the Syncore client. */\n children: ReactNode;\n\n /** Optional fallback content rendered while the local runtime starts. */\n fallback?: ReactNode;\n}\n\n/**\n * Start an Expo Syncore bootstrap and provide its client to React descendants.\n */\nexport function SyncoreExpoProvider({\n bootstrap,\n children,\n fallback = null\n}: SyncoreExpoProviderProps): ReactNode {\n const [client, setClient] = useState<ExpoSyncoreClient | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n void bootstrap.getClient().then((nextClient: ExpoSyncoreClient) => {\n if (!cancelled) {\n setClient(nextClient);\n }\n });\n\n return () => {\n cancelled = true;\n setClient(null);\n void bootstrap.stop();\n };\n }, [bootstrap]);\n\n if (!client) {\n return fallback;\n }\n\n return <SyncoreProvider client={client}>{children}</SyncoreProvider>;\n}\n"],"mappings":";;;;;;;AAyBA,SAAgB,oBAAoB,EAClC,WACA,UACA,WAAW,QAC2B;CACtC,MAAM,CAAC,QAAQ,aAAa,SAAmC,KAAK;AAEpE,iBAAgB;EACd,IAAI,YAAY;AACX,YAAU,WAAW,CAAC,MAAM,eAAkC;AACjE,OAAI,CAAC,UACH,WAAU,WAAW;IAEvB;AAEF,eAAa;AACX,eAAY;AACZ,aAAU,KAAK;AACV,aAAU,MAAM;;IAEtB,CAAC,UAAU,CAAC;AAEf,KAAI,CAAC,OACH,QAAO;AAGT,QAAO,oBAAC,iBAAD;EAAyB;EAAS;EAA2B,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { AttachNodeIpcRuntimeOptions, AttachedNodeIpcRuntime, NodeIpcSyncoreSchema, RendererQueryWatch, SyncoreIpcMessageEndpoint, SyncoreMainProcessBridge, SyncoreRendererBridge, SyncoreRendererClient, SyncoreWindowBridge, attachNodeIpcRuntime, createNodeIpcMessageEndpoint, createRendererSyncoreBridgeClient, createRendererSyncoreClient, createRendererSyncoreWindowClient, installSyncoreWindowBridge } from "./ipc.mjs";
2
2
  import * as _syncore_core0 from "../core/index.d.mts";
3
- import { AnySyncoreSchema, DevtoolsRequestHandler, DevtoolsSink, SchedulerOptions, StorageObject, StorageWriteInput, SyncoreCapabilities, SyncoreExperimentalPlugin, SyncoreRuntime, SyncoreRuntimeOptions, SyncoreSqlDriver, SyncoreStorageAdapter } from "../core/index.d.mts";
4
- import { SyncoreDevtoolsEvent, SyncoreDevtoolsSnapshot, SyncoreDevtoolsSnapshot as SyncoreDevtoolsSnapshot$1 } from "../devtools-protocol/index.d.ts";
3
+ import { AnySyncoreSchema, DevtoolsCommandHandler, DevtoolsSink, DevtoolsSubscriptionHost, SchedulerOptions, StorageObject, StorageWriteInput, SyncoreCapabilities, SyncoreExperimentalPlugin, SyncoreRuntime, SyncoreRuntimeOptions, SyncoreSqlDriver, SyncoreStorageAdapter } from "../core/index.d.mts";
4
+ import { SyncoreActiveQueryInfo, SyncoreDevtoolsEvent, SyncoreRuntimeSummary } from "../devtools-protocol/index.d.ts";
5
5
 
6
6
  //#region src/index.d.ts
7
7
  type NodeSyncoreSchema = AnySyncoreSchema;
@@ -133,13 +133,18 @@ interface NodeWebSocketDevtoolsSinkOptions {
133
133
  appName?: string;
134
134
  origin?: string;
135
135
  sessionLabel?: string;
136
+ targetKind?: "client" | "project";
137
+ storageProtocol?: string;
138
+ databaseLabel?: string;
139
+ storageIdentity?: string;
136
140
  }
137
141
  interface NodeWebSocketDevtoolsSink extends DevtoolsSink {
138
- attachRuntime(getSnapshot: () => SyncoreDevtoolsSnapshot$1): void;
139
- attachRequestHandler(handler: DevtoolsRequestHandler): void;
142
+ attachRuntime(runtime: SyncoreRuntime<AnySyncoreSchema>): void;
143
+ attachCommandHandler(handler: DevtoolsCommandHandler): void;
144
+ attachSubscriptionHost(host: DevtoolsSubscriptionHost): void;
140
145
  dispose(): void;
141
146
  }
142
147
  declare function createNodeWebSocketDevtoolsSink(options: NodeWebSocketDevtoolsSinkOptions): NodeWebSocketDevtoolsSink;
143
148
  //#endregion
144
- export { AttachNodeIpcRuntimeOptions, AttachedNodeIpcRuntime, CreateElectronSyncoreBridgeOptions, CreateNodeRuntimeOptions, CreateSyncoreRendererWindowClientOptions, ManagedNodeSyncoreClient, NodeFileStorageAdapter, NodeIpcSyncoreSchema, NodeSqliteDriver, NodeSyncoreSchema, NodeWebSocketDevtoolsSink, NodeWebSocketDevtoolsSinkOptions, RendererQueryWatch, type SyncoreDevtoolsEvent, type SyncoreDevtoolsSnapshot, SyncoreElectronBridgeWindow, SyncoreElectronIpcBinding, SyncoreElectronIpcMain, SyncoreIpcMessageEndpoint, SyncoreMainProcessBridge, SyncoreRendererBridge, SyncoreRendererClient, SyncoreWindowBridge, WithNodeSyncoreClientOptions, attachNodeIpcRuntime, bindElectronWindowToSyncoreRuntime, createElectronSyncoreBridge, createManagedNodeSyncoreClient, createNodeIpcMessageEndpoint, createNodeSyncoreClient, createNodeSyncoreRuntime, createNodeWebSocketDevtoolsSink, createRendererSyncoreBridgeClient, createRendererSyncoreClient, createRendererSyncoreWindowClient, installSyncoreWindowBridge, withNodeSyncoreClient };
149
+ export { AttachNodeIpcRuntimeOptions, AttachedNodeIpcRuntime, CreateElectronSyncoreBridgeOptions, CreateNodeRuntimeOptions, CreateSyncoreRendererWindowClientOptions, ManagedNodeSyncoreClient, NodeFileStorageAdapter, NodeIpcSyncoreSchema, NodeSqliteDriver, NodeSyncoreSchema, NodeWebSocketDevtoolsSink, NodeWebSocketDevtoolsSinkOptions, RendererQueryWatch, type SyncoreActiveQueryInfo, type SyncoreDevtoolsEvent, SyncoreElectronBridgeWindow, SyncoreElectronIpcBinding, SyncoreElectronIpcMain, SyncoreIpcMessageEndpoint, SyncoreMainProcessBridge, SyncoreRendererBridge, SyncoreRendererClient, type SyncoreRuntimeSummary, SyncoreWindowBridge, WithNodeSyncoreClientOptions, attachNodeIpcRuntime, bindElectronWindowToSyncoreRuntime, createElectronSyncoreBridge, createManagedNodeSyncoreClient, createNodeIpcMessageEndpoint, createNodeSyncoreClient, createNodeSyncoreRuntime, createNodeWebSocketDevtoolsSink, createRendererSyncoreBridgeClient, createRendererSyncoreClient, createRendererSyncoreWindowClient, installSyncoreWindowBridge, withNodeSyncoreClient };
145
150
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
@@ -1,15 +1,97 @@
1
1
  import { SyncoreRendererClient, attachNodeIpcRuntime, createNodeIpcMessageEndpoint, createRendererSyncoreBridgeClient, createRendererSyncoreClient, createRendererSyncoreWindowClient, installSyncoreWindowBridge } from "./ipc.mjs";
2
+ import { createRequire } from "node:module";
2
3
  import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
3
4
  import path from "node:path";
4
5
  import { DatabaseSync } from "node:sqlite";
5
6
  import WebSocket from "ws";
6
- import { SyncoreRuntime, createDevtoolsRequestHandler } from "../core/index.mjs";
7
+ import { SyncoreRuntime, createDevtoolsCommandHandler, createDevtoolsSubscriptionHost } from "../core/index.mjs";
7
8
  //#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
+ };
8
57
  function normalizeData(input) {
9
58
  if (typeof input === "string") return Buffer.from(input);
10
59
  if (input instanceof Uint8Array) return input;
11
60
  return new Uint8Array(input);
12
61
  }
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
+ }
13
95
  function toSqlParameters(params) {
14
96
  return params;
15
97
  }
@@ -138,7 +220,11 @@ function createNodeSyncoreRuntime(options) {
138
220
  url: resolvedDevtoolsUrl,
139
221
  ...options.appName ? { appName: options.appName } : {},
140
222
  ...options.origin ? { origin: options.origin } : {},
141
- ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}
223
+ ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
224
+ targetKind: "client",
225
+ storageProtocol: "file",
226
+ databaseLabel: path.basename(options.databasePath),
227
+ storageIdentity: `file::${path.resolve(options.databasePath)}`
142
228
  }) : void 0;
143
229
  const runtimeOptions = {
144
230
  schema: options.schema,
@@ -153,13 +239,21 @@ function createNodeSyncoreRuntime(options) {
153
239
  if (resolvedDevtools) runtimeOptions.devtools = resolvedDevtools;
154
240
  if (options.scheduler) runtimeOptions.scheduler = options.scheduler;
155
241
  const runtime = new SyncoreRuntime(runtimeOptions);
156
- websocketDevtools?.attachRuntime(() => runtime.getDevtoolsSnapshot());
242
+ websocketDevtools?.attachRuntime(runtime);
157
243
  if (websocketDevtools) {
158
- websocketDevtools.attachRequestHandler(createDevtoolsRequestHandler({
244
+ websocketDevtools.attachCommandHandler(createDevtoolsCommandHandler({
245
+ driver: runtimeOptions.driver,
246
+ schema: options.schema,
247
+ functions: options.functions,
248
+ runtime,
249
+ sql: nodeDevtoolsSqlSupport
250
+ }));
251
+ websocketDevtools.attachSubscriptionHost(createDevtoolsSubscriptionHost({
159
252
  driver: runtimeOptions.driver,
160
253
  schema: options.schema,
161
254
  functions: options.functions,
162
- runtime
255
+ runtime,
256
+ sql: nodeDevtoolsSqlSupport
163
257
  }));
164
258
  const stop = runtime.stop.bind(runtime);
165
259
  runtime.stop = async () => {
@@ -264,8 +358,9 @@ function createNodeWebSocketDevtoolsSink(options) {
264
358
  let socket;
265
359
  let disposed = false;
266
360
  let connectTimer;
267
- let getSnapshot;
268
- let onRequest;
361
+ let getSummary;
362
+ let onCommand;
363
+ let subscriptionHost;
269
364
  const pendingMessages = [];
270
365
  let latestHello;
271
366
  const connect = () => {
@@ -278,11 +373,11 @@ function createNodeWebSocketDevtoolsSink(options) {
278
373
  platform: latestHello.platform,
279
374
  ...options.appName ? { appName: options.appName } : {},
280
375
  ...options.origin ? { origin: options.origin } : {},
281
- ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}
282
- });
283
- if (getSnapshot) sendNow({
284
- type: "snapshot",
285
- snapshot: withSnapshotMeta(getSnapshot(), options)
376
+ ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
377
+ ...options.targetKind ? { targetKind: options.targetKind } : {},
378
+ ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
379
+ ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
380
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
286
381
  });
287
382
  flushPendingMessages();
288
383
  });
@@ -291,21 +386,21 @@ function createNodeWebSocketDevtoolsSink(options) {
291
386
  if (rawPayload.length === 0) return;
292
387
  const message = JSON.parse(rawPayload);
293
388
  if (message.type === "ping") send({ type: "pong" });
294
- else if (message.type === "request" && onRequest) onRequest(message.payload).then((responsePayload) => {
295
- const runtimeId = latestHello?.runtimeId ?? getSnapshot?.().runtimeId;
389
+ else if (message.type === "command" && onCommand) onCommand(message.payload).then((responsePayload) => {
390
+ const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
296
391
  if (!runtimeId) return;
297
392
  send({
298
- type: "response",
299
- requestId: message.requestId,
393
+ type: "command.result",
394
+ commandId: message.commandId,
300
395
  runtimeId,
301
396
  payload: responsePayload
302
397
  });
303
398
  }).catch((err) => {
304
- const runtimeId = latestHello?.runtimeId ?? getSnapshot?.().runtimeId;
399
+ const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
305
400
  if (!runtimeId) return;
306
401
  send({
307
- type: "response",
308
- requestId: message.requestId,
402
+ type: "command.result",
403
+ commandId: message.commandId,
309
404
  runtimeId,
310
405
  payload: {
311
406
  kind: "error",
@@ -313,6 +408,17 @@ function createNodeWebSocketDevtoolsSink(options) {
313
408
  }
314
409
  });
315
410
  });
411
+ else if (message.type === "subscribe" && subscriptionHost) subscriptionHost.subscribe(message.subscriptionId, message.payload, (payload) => {
412
+ const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
413
+ if (!runtimeId) return;
414
+ send({
415
+ type: "subscription.data",
416
+ subscriptionId: message.subscriptionId,
417
+ runtimeId,
418
+ payload
419
+ });
420
+ });
421
+ else if (message.type === "unsubscribe") subscriptionHost?.unsubscribe(message.subscriptionId);
316
422
  });
317
423
  socket.on("close", scheduleReconnect);
318
424
  socket.on("error", scheduleReconnect);
@@ -355,41 +461,45 @@ function createNodeWebSocketDevtoolsSink(options) {
355
461
  platform: event.platform,
356
462
  ...options.appName ? { appName: options.appName } : {},
357
463
  ...options.origin ? { origin: options.origin } : {},
358
- ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}
464
+ ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
465
+ ...options.targetKind ? { targetKind: options.targetKind } : {},
466
+ ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
467
+ ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
468
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
359
469
  });
360
470
  }
361
471
  send({
362
472
  type: "event",
363
473
  event
364
474
  });
365
- if (getSnapshot) send({
366
- type: "snapshot",
367
- snapshot: withSnapshotMeta(getSnapshot(), options)
368
- });
369
475
  },
370
- attachRuntime(snapshotGetter) {
371
- getSnapshot = snapshotGetter;
372
- if (socket?.readyState === WebSocket.OPEN) send({
373
- type: "snapshot",
374
- snapshot: withSnapshotMeta(getSnapshot(), options)
375
- });
476
+ attachRuntime(runtime) {
477
+ getSummary = () => withRuntimeSummaryMeta(runtime.getRuntimeSummary(), options);
478
+ },
479
+ attachCommandHandler(handler) {
480
+ onCommand = handler;
376
481
  },
377
- attachRequestHandler(handler) {
378
- onRequest = handler;
482
+ attachSubscriptionHost(host) {
483
+ subscriptionHost = host;
379
484
  },
380
485
  dispose() {
381
486
  disposed = true;
382
487
  if (connectTimer) clearTimeout(connectTimer);
488
+ subscriptionHost?.dispose();
383
489
  socket?.close();
384
490
  }
385
491
  };
386
492
  }
387
- function withSnapshotMeta(snapshot, options) {
493
+ function withRuntimeSummaryMeta(summary, options) {
388
494
  return {
389
- ...snapshot,
495
+ ...summary,
390
496
  ...options.appName ? { appName: options.appName } : {},
391
497
  ...options.origin ? { origin: options.origin } : {},
392
- ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}
498
+ ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
499
+ ...options.targetKind ? { targetKind: options.targetKind } : {},
500
+ ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
501
+ ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
502
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
393
503
  };
394
504
  }
395
505
  function shouldAutoConnectNodeDevtools() {