syncorejs 0.2.2 → 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 (140) hide show
  1. package/dist/_vendor/cli/app.d.mts.map +1 -1
  2. package/dist/_vendor/cli/app.mjs +8 -5
  3. package/dist/_vendor/cli/app.mjs.map +1 -1
  4. package/dist/_vendor/cli/context.mjs.map +1 -1
  5. package/dist/_vendor/cli/dev-session.mjs.map +1 -1
  6. package/dist/_vendor/cli/doctor.mjs.map +1 -1
  7. package/dist/_vendor/cli/errors.mjs.map +1 -1
  8. package/dist/_vendor/cli/help.mjs.map +1 -1
  9. package/dist/_vendor/cli/index.mjs +9 -2
  10. package/dist/_vendor/cli/index.mjs.map +1 -1
  11. package/dist/_vendor/cli/messages.mjs.map +1 -1
  12. package/dist/_vendor/cli/preflight.mjs.map +1 -1
  13. package/dist/_vendor/cli/project.mjs +20 -20
  14. package/dist/_vendor/cli/project.mjs.map +1 -1
  15. package/dist/_vendor/cli/render.mjs.map +1 -1
  16. package/dist/_vendor/cli/targets.mjs.map +1 -1
  17. package/dist/_vendor/core/cli.d.mts +8 -2
  18. package/dist/_vendor/core/cli.d.mts.map +1 -1
  19. package/dist/_vendor/core/cli.mjs +238 -64
  20. package/dist/_vendor/core/cli.mjs.map +1 -1
  21. package/dist/_vendor/core/devtools-auth.mjs.map +1 -1
  22. package/dist/_vendor/core/runtime/components.d.mts.map +1 -1
  23. package/dist/_vendor/core/runtime/components.mjs.map +1 -1
  24. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  25. package/dist/_vendor/core/runtime/devtools.mjs +130 -23
  26. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  27. package/dist/_vendor/core/runtime/functions.d.mts +388 -6
  28. package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
  29. package/dist/_vendor/core/runtime/functions.mjs +72 -1
  30. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  31. package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
  32. package/dist/_vendor/core/runtime/id.mjs.map +1 -1
  33. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +11 -5
  34. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -1
  35. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +123 -20
  36. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -1
  37. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +56 -8
  38. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -1
  39. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +49 -14
  40. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -1
  41. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +4 -7
  42. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -1
  43. package/dist/_vendor/core/runtime/internal/engines/shared.mjs +76 -1
  44. package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -1
  45. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +1 -0
  46. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -1
  47. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +4 -3
  48. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -1
  49. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -1
  50. package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -1
  51. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +4 -0
  52. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -1
  53. package/dist/_vendor/core/runtime/runtime.d.mts +1040 -9
  54. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  55. package/dist/_vendor/core/runtime/runtime.mjs +63 -0
  56. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  57. package/dist/_vendor/core/transport.d.mts +2 -0
  58. package/dist/_vendor/core/transport.d.mts.map +1 -1
  59. package/dist/_vendor/core/transport.mjs +33 -24
  60. package/dist/_vendor/core/transport.mjs.map +1 -1
  61. package/dist/_vendor/devtools-protocol/index.d.ts +149 -4
  62. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  63. package/dist/_vendor/devtools-protocol/index.js.map +1 -1
  64. package/dist/_vendor/next/config.d.ts +3 -4
  65. package/dist/_vendor/next/config.d.ts.map +1 -1
  66. package/dist/_vendor/next/config.js +37 -19
  67. package/dist/_vendor/next/config.js.map +1 -1
  68. package/dist/_vendor/next/index.d.ts +109 -29
  69. package/dist/_vendor/next/index.d.ts.map +1 -1
  70. package/dist/_vendor/next/index.js +77 -17
  71. package/dist/_vendor/next/index.js.map +1 -1
  72. package/dist/_vendor/platform-expo/index.d.ts +146 -27
  73. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  74. package/dist/_vendor/platform-expo/index.js +76 -10
  75. package/dist/_vendor/platform-expo/index.js.map +1 -1
  76. package/dist/_vendor/platform-expo/react.js.map +1 -1
  77. package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
  78. package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
  79. package/dist/_vendor/platform-node/index.d.mts +173 -9
  80. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  81. package/dist/_vendor/platform-node/index.mjs +225 -94
  82. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  83. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  84. package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
  85. package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
  86. package/dist/_vendor/platform-web/external-change.d.ts +41 -0
  87. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
  88. package/dist/_vendor/platform-web/external-change.js +30 -0
  89. package/dist/_vendor/platform-web/external-change.js.map +1 -1
  90. package/dist/_vendor/platform-web/index.d.ts +307 -35
  91. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  92. package/dist/_vendor/platform-web/index.js +189 -23
  93. package/dist/_vendor/platform-web/index.js.map +1 -1
  94. package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
  95. package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
  96. package/dist/_vendor/platform-web/indexeddb.js +10 -0
  97. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  98. package/dist/_vendor/platform-web/opfs.d.ts +13 -0
  99. package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
  100. package/dist/_vendor/platform-web/opfs.js +12 -0
  101. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  102. package/dist/_vendor/platform-web/persistence.d.ts +54 -0
  103. package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
  104. package/dist/_vendor/platform-web/persistence.js +15 -0
  105. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  106. package/dist/_vendor/platform-web/react.d.ts +1 -2
  107. package/dist/_vendor/platform-web/react.d.ts.map +1 -1
  108. package/dist/_vendor/platform-web/react.js +2 -4
  109. package/dist/_vendor/platform-web/react.js.map +1 -1
  110. package/dist/_vendor/platform-web/sqljs.js +10 -1
  111. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  112. package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
  113. package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
  114. package/dist/_vendor/platform-web/worker.d.ts +60 -9
  115. package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
  116. package/dist/_vendor/platform-web/worker.js +37 -4
  117. package/dist/_vendor/platform-web/worker.js.map +1 -1
  118. package/dist/_vendor/react/index.d.ts +196 -13
  119. package/dist/_vendor/react/index.d.ts.map +1 -1
  120. package/dist/_vendor/react/index.js +208 -17
  121. package/dist/_vendor/react/index.js.map +1 -1
  122. package/dist/_vendor/schema/definition.d.ts +129 -0
  123. package/dist/_vendor/schema/definition.d.ts.map +1 -1
  124. package/dist/_vendor/schema/definition.js +99 -0
  125. package/dist/_vendor/schema/definition.js.map +1 -1
  126. package/dist/_vendor/schema/planner.d.ts.map +1 -1
  127. package/dist/_vendor/schema/planner.js.map +1 -1
  128. package/dist/_vendor/schema/validators.d.ts +180 -4
  129. package/dist/_vendor/schema/validators.d.ts.map +1 -1
  130. package/dist/_vendor/schema/validators.js +35 -1
  131. package/dist/_vendor/schema/validators.js.map +1 -1
  132. package/dist/_vendor/svelte/index.d.ts +205 -7
  133. package/dist/_vendor/svelte/index.d.ts.map +1 -1
  134. package/dist/_vendor/svelte/index.js +199 -6
  135. package/dist/_vendor/svelte/index.js.map +1 -1
  136. package/dist/browser.d.ts.map +1 -1
  137. package/dist/cli.js +3 -1
  138. package/dist/cli.js.map +1 -1
  139. package/dist/index.d.ts +1 -1
  140. package/package.json +24 -21
@@ -16,9 +16,10 @@ import WebSocket, { WebSocketServer } from "ws";
16
16
  import { SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION, SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION, SYNCORE_DEVTOOLS_PROTOCOL_VERSION, createPublicRuntimeId, createPublicTargetId } from "../devtools-protocol/index.js";
17
17
  //#region src/cli.ts
18
18
  function templateUsesConnectedClients(template) {
19
- return template === "react-web" || template === "expo" || template === "next";
19
+ return template === "react-web" || template === "svelte" || template === "expo" || template === "next";
20
20
  }
21
- const COMBINED_DEV_COMMAND = "concurrently --kill-others-on-fail --names syncore,app --prefix-colors yellow,cyan \"bun run syncorejs:dev\" \"bun run dev:app\"";
21
+ const loadedTypeScriptModules = /* @__PURE__ */ new Map();
22
+ const COMBINED_DEV_COMMAND = "concurrently --kill-others-on-fail --names syncore,app --prefix-colors yellow,cyan \"npm run syncorejs:dev\" \"npm run dev:app\"";
22
23
  const program = new Command();
23
24
  const CORE_PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
24
25
  const DEVTOOLS_SESSION_FILE = path.join(".syncore", "devtools-session.json");
@@ -27,6 +28,7 @@ const VALID_SYNCORE_TEMPLATES = [
27
28
  "minimal",
28
29
  "node",
29
30
  "react-web",
31
+ "svelte",
30
32
  "expo",
31
33
  "electron",
32
34
  "next"
@@ -131,7 +133,7 @@ async function runCodegen(cwd) {
131
133
  const componentsManifestPath = path.join(cwd, "syncore", "components.ts");
132
134
  await mkdir(generatedDir, { recursive: true });
133
135
  const functionImportExtension = await resolveFunctionImportExtension(cwd);
134
- const hasComponentsManifest = await fileExists(componentsManifestPath);
136
+ const hasComponentsManifest = await hasNonEmptyComponentsManifest(componentsManifestPath);
135
137
  const files = await listTypeScriptFiles(functionsDir);
136
138
  const functionEntries = [];
137
139
  for (const file of files) {
@@ -246,6 +248,24 @@ async function runCodegen(cwd) {
246
248
  `export default resolvedComponents;`,
247
249
  ``
248
250
  ].join("\n");
251
+ const runtimeSource = [
252
+ `/**`,
253
+ ` * Generated local runtime bundle for Syncore CLI and Node adapters.`,
254
+ ` *`,
255
+ ` * THIS CODE IS AUTOMATICALLY GENERATED.`,
256
+ ` *`,
257
+ ` * To regenerate, run \`npx syncorejs dev\` or \`npx syncorejs codegen\`.`,
258
+ ` * @module`,
259
+ ` */`,
260
+ ``,
261
+ `import schema from "./schema${functionImportExtension}";`,
262
+ `import { functions } from "./functions${functionImportExtension}";`,
263
+ ...hasComponentsManifest ? [`import { resolvedComponents } from "./components${functionImportExtension}";`] : [`const resolvedComponents = [] as const;`],
264
+ ``,
265
+ `export { functions, schema };`,
266
+ `export const components = resolvedComponents;`,
267
+ ``
268
+ ].join("\n");
249
269
  const serverSource = [
250
270
  `/**`,
251
271
  ` * Generated utilities for implementing Syncore query, mutation, and action functions.`,
@@ -341,11 +361,18 @@ async function runCodegen(cwd) {
341
361
  `};`,
342
362
  ``
343
363
  ].join("\n");
344
- await writeFile(path.join(generatedDir, "api.ts"), apiSource);
345
- await writeFile(path.join(generatedDir, "components.ts"), componentsSource);
346
- await writeFile(path.join(generatedDir, "functions.ts"), functionsSource);
347
- await writeFile(path.join(generatedDir, "schema.ts"), schemaSource);
348
- await writeFile(path.join(generatedDir, "server.ts"), serverSource);
364
+ await writeGeneratedFile(path.join(generatedDir, "api.ts"), apiSource);
365
+ await writeGeneratedFile(path.join(generatedDir, "components.ts"), componentsSource);
366
+ await writeGeneratedFile(path.join(generatedDir, "functions.ts"), functionsSource);
367
+ await writeGeneratedFile(path.join(generatedDir, "runtime.ts"), runtimeSource);
368
+ await writeGeneratedFile(path.join(generatedDir, "schema.ts"), schemaSource);
369
+ await writeGeneratedFile(path.join(generatedDir, "server.ts"), serverSource);
370
+ }
371
+ async function writeGeneratedFile(filePath, source) {
372
+ try {
373
+ if (await readFile(filePath, "utf8") === source) return;
374
+ } catch {}
375
+ await writeFile(filePath, source);
349
376
  }
350
377
  async function scaffoldProject(cwd, options) {
351
378
  const files = buildTemplateFiles(options.template);
@@ -423,16 +450,12 @@ export const create = mutation({
423
450
 
424
451
  import { createBrowserWorkerRuntime } from "syncorejs/browser";
425
452
  import schema from "../syncore/_generated/schema";
426
- import { resolvedComponents } from "../syncore/_generated/components";
427
453
  import { functions } from "../syncore/_generated/functions";
428
454
 
429
455
  void createBrowserWorkerRuntime({
430
456
  endpoint: self,
431
457
  schema,
432
- functions,
433
- components: resolvedComponents,
434
- databaseName: "syncore-app",
435
- persistenceMode: "opfs"
458
+ functions
436
459
  });
437
460
  `
438
461
  }, {
@@ -455,15 +478,11 @@ export function AppSyncoreProvider({ children }: { children: ReactNode }) {
455
478
  path: path.join("lib", "syncore.ts"),
456
479
  content: `import { createExpoSyncoreBootstrap } from "syncorejs/expo";
457
480
  import schema from "../syncore/_generated/schema";
458
- import { resolvedComponents } from "../syncore/_generated/components";
459
481
  import { functions } from "../syncore/_generated/functions";
460
482
 
461
483
  export const syncore = createExpoSyncoreBootstrap({
462
484
  schema,
463
- functions,
464
- components: resolvedComponents,
465
- databaseName: "syncore-app.db",
466
- storageDirectoryName: "syncore-app-storage"
485
+ functions
467
486
  });
468
487
  `
469
488
  });
@@ -475,18 +494,12 @@ export const syncore = createExpoSyncoreBootstrap({
475
494
 
476
495
  import { createBrowserWorkerRuntime } from "syncorejs/browser";
477
496
  import schema from "../syncore/_generated/schema";
478
- import { resolvedComponents } from "../syncore/_generated/components";
479
497
  import { functions } from "../syncore/_generated/functions";
480
498
 
481
499
  void createBrowserWorkerRuntime({
482
500
  endpoint: self,
483
501
  schema,
484
- functions,
485
- components: resolvedComponents,
486
- databaseName: "syncore-app",
487
- persistenceDatabaseName: "syncore-app",
488
- locateFile: () => "/sql-wasm.wasm",
489
- platform: "browser-worker"
502
+ functions
490
503
  });
491
504
  `
492
505
  }, {
@@ -518,7 +531,6 @@ export function AppSyncoreProvider({ children }: { children: ReactNode }) {
518
531
  import { withNodeSyncoreClient } from "syncorejs/node";
519
532
  import { api } from "./syncore/_generated/api.ts";
520
533
  import schema from "./syncore/_generated/schema.ts";
521
- import { resolvedComponents } from "./syncore/_generated/components.ts";
522
534
  import { functions } from "./syncore/_generated/functions.ts";
523
535
 
524
536
  await withNodeSyncoreClient(
@@ -526,8 +538,7 @@ await withNodeSyncoreClient(
526
538
  databasePath: path.join(process.cwd(), ".syncore", "syncore.db"),
527
539
  storageDirectory: path.join(process.cwd(), ".syncore", "storage"),
528
540
  schema,
529
- functions,
530
- components: resolvedComponents
541
+ functions
531
542
  },
532
543
  async (client) => {
533
544
  await client.mutation(api.tasks.create, { text: "Run locally" });
@@ -544,7 +555,6 @@ await withNodeSyncoreClient(
544
555
  import { app } from "electron";
545
556
  import { createNodeSyncoreRuntime } from "syncorejs/node";
546
557
  import schema from "../syncore/_generated/schema.js";
547
- import { resolvedComponents } from "../syncore/_generated/components.js";
548
558
  import { functions } from "../syncore/_generated/functions.js";
549
559
 
550
560
  export function createAppSyncoreRuntime() {
@@ -554,10 +564,53 @@ export function createAppSyncoreRuntime() {
554
564
  storageDirectory: path.join(userDataDirectory, "storage"),
555
565
  schema,
556
566
  functions,
557
- components: resolvedComponents,
558
567
  platform: "electron-main"
559
568
  });
560
569
  }
570
+ `
571
+ });
572
+ break;
573
+ case "svelte":
574
+ files.push({
575
+ path: path.join("src", "syncore.worker.ts"),
576
+ content: `/// <reference lib="webworker" />
577
+
578
+ import { createBrowserWorkerRuntime } from "syncorejs/browser";
579
+ import schema from "../syncore/_generated/schema";
580
+ import { functions } from "../syncore/_generated/functions";
581
+
582
+ void createBrowserWorkerRuntime({
583
+ endpoint: self,
584
+ schema,
585
+ functions
586
+ });
587
+ `
588
+ }, {
589
+ path: path.join("src", "SyncoreProvider.svelte"),
590
+ content: `<script lang="ts">
591
+ import { onDestroy } from "svelte";
592
+ import type { Snippet } from "svelte";
593
+ import { createBrowserWorkerClient } from "syncorejs/browser";
594
+ import { setSyncoreClient } from "syncorejs/svelte";
595
+
596
+ interface Props {
597
+ children?: Snippet;
598
+ }
599
+
600
+ const { children }: Props = $props();
601
+
602
+ const managed = createBrowserWorkerClient({
603
+ workerUrl: new URL("./syncore.worker.ts", import.meta.url)
604
+ });
605
+
606
+ setSyncoreClient(managed.client);
607
+
608
+ onDestroy(() => {
609
+ void managed.dispose();
610
+ });
611
+ <\/script>
612
+
613
+ {@render children?.()}
561
614
  `
562
615
  });
563
616
  break;
@@ -606,7 +659,8 @@ async function detectProjectTemplate(cwd) {
606
659
  if ("expo" in dependencies || "react-native" in dependencies) return "expo";
607
660
  if ("electron" in dependencies) return "electron";
608
661
  if ("next" in dependencies) return "next";
609
- if ("vite" in dependencies || "@vitejs/plugin-react" in dependencies || await fileExists(path.join(cwd, "src", "main.tsx")) && "react" in dependencies) return "react-web";
662
+ if ("svelte" in dependencies || "@sveltejs/vite-plugin-svelte" in dependencies || "@sveltejs/kit" in dependencies || await fileExists(path.join(cwd, "src", "SyncoreProvider.svelte"))) return "svelte";
663
+ if ("vite" in dependencies || "@vitejs/plugin-react" in dependencies || await fileExists(path.join(cwd, "src", "syncore.worker.ts")) || await fileExists(path.join(cwd, "src", "syncore-provider.tsx")) || await fileExists(path.join(cwd, "src", "main.tsx")) && "react" in dependencies) return "react-web";
610
664
  if (packageJson) return "node";
611
665
  return "minimal";
612
666
  }
@@ -621,7 +675,16 @@ async function readPackageJson(cwd) {
621
675
  }
622
676
  async function ensurePackageScripts(cwd, template) {
623
677
  const packageJsonPath = path.join(cwd, "package.json");
624
- if (!await fileExists(packageJsonPath)) return;
678
+ if (!await fileExists(packageJsonPath)) {
679
+ await writeFile(packageJsonPath, `${JSON.stringify({
680
+ type: "module",
681
+ scripts: {
682
+ "syncorejs:dev": "syncorejs dev",
683
+ "syncorejs:codegen": "syncorejs codegen"
684
+ }
685
+ }, null, 2)}\n`);
686
+ return;
687
+ }
625
688
  const packageJson = await readPackageJson(cwd);
626
689
  if (!packageJson) return;
627
690
  const nextPackageJson = {
@@ -654,7 +717,7 @@ function maybeAddManagedDevScripts(packageJson, template) {
654
717
  scripts.dev = combinedDevCommand();
655
718
  }
656
719
  function supportsManagedCombinedDev(template) {
657
- return template === "next" || template === "react-web" || template === "electron";
720
+ return template === "next" || template === "react-web" || template === "svelte" || template === "electron";
658
721
  }
659
722
  function combinedDevCommand() {
660
723
  return COMBINED_DEV_COMMAND;
@@ -703,7 +766,7 @@ async function importJsonlIntoProject(cwd, tableName, sourcePath) {
703
766
  try {
704
767
  parsed = JSON.parse(line);
705
768
  } catch (error) {
706
- throw new Error(`Invalid JSON on line ${lineNumber} of ${sourcePath}: ${formatError(error)}`);
769
+ throw new Error(`Invalid JSON on line ${lineNumber} of ${sourcePath}: ${formatError(error)}`, { cause: error });
707
770
  }
708
771
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`Line ${lineNumber} of ${sourcePath} must contain a JSON object.`);
709
772
  const payload = { ...parsed };
@@ -911,8 +974,7 @@ async function loadProjectSchema(cwd) {
911
974
  }
912
975
  async function loadDefaultExport(filePath) {
913
976
  if (!await fileExists(filePath)) throw new Error(`Missing file: ${path.relative(process.cwd(), filePath)}`);
914
- const moduleUrl = pathToFileURL(filePath).href;
915
- const loaded = await tsImport(moduleUrl, { parentURL: import.meta.url });
977
+ const loaded = await loadTypeScriptModule(filePath);
916
978
  if (!("default" in loaded)) throw new Error(`File ${path.relative(process.cwd(), filePath)} must have a default export.`);
917
979
  const resolvedDefault = unwrapDefaultExport(loaded.default);
918
980
  if (resolvedDefault === void 0) throw new Error(`File ${path.relative(process.cwd(), filePath)} exported undefined.`);
@@ -920,14 +982,30 @@ async function loadDefaultExport(filePath) {
920
982
  }
921
983
  async function loadNamedExport(filePath, exportName) {
922
984
  if (!await fileExists(filePath)) throw new Error(`Missing file: ${path.relative(process.cwd(), filePath)}`);
923
- const moduleUrl = pathToFileURL(filePath).href;
924
- const loaded = await tsImport(moduleUrl, { parentURL: import.meta.url });
985
+ const loaded = await loadTypeScriptModule(filePath);
925
986
  const defaultExport = loaded.default && typeof loaded.default === "object" && exportName in loaded.default ? loaded.default[exportName] : void 0;
926
987
  if (!(exportName in loaded) && defaultExport === void 0) throw new Error(`File ${path.relative(process.cwd(), filePath)} must export ${exportName}.`);
927
988
  const resolvedValue = unwrapDefaultExport(loaded[exportName] ?? defaultExport);
928
989
  if (resolvedValue === void 0) throw new Error(`File ${path.relative(process.cwd(), filePath)} exported undefined for ${exportName}.`);
929
990
  return resolvedValue;
930
991
  }
992
+ async function hasNonEmptyComponentsManifest(filePath) {
993
+ if (!await fileExists(filePath)) return false;
994
+ const source = await readFile(filePath, "utf8");
995
+ return !/defineComponents\s*\(\s*\{\s*\}\s*\)/.test(source);
996
+ }
997
+ async function loadTypeScriptModule(filePath) {
998
+ const fileStat = await stat(filePath);
999
+ const cached = loadedTypeScriptModules.get(filePath);
1000
+ if (cached && cached.mtimeMs === fileStat.mtimeMs) return await cached.loaded;
1001
+ const moduleUrl = pathToFileURL(filePath).href;
1002
+ const loaded = tsImport(moduleUrl, { parentURL: import.meta.url });
1003
+ loadedTypeScriptModules.set(filePath, {
1004
+ mtimeMs: fileStat.mtimeMs,
1005
+ loaded
1006
+ });
1007
+ return await loaded;
1008
+ }
931
1009
  async function loadProjectFunctions(cwd) {
932
1010
  const filePath = path.join(cwd, "syncore", "_generated", "functions.ts");
933
1011
  if (!await fileExists(filePath)) await runCodegen(cwd);
@@ -936,17 +1014,62 @@ async function loadProjectFunctions(cwd) {
936
1014
  return functions;
937
1015
  }
938
1016
  async function loadProjectResolvedComponents(cwd) {
1017
+ const componentsManifestPath = path.join(cwd, "syncore", "components.ts");
1018
+ if (await fileExists(componentsManifestPath)) {
1019
+ const source = await readFile(componentsManifestPath, "utf8");
1020
+ if (/defineComponents\s*\(\s*\{\s*\}\s*\)/.test(source)) return [];
1021
+ }
939
1022
  const filePath = path.join(cwd, "syncore", "_generated", "components.ts");
940
1023
  if (!await fileExists(filePath)) await runCodegen(cwd);
941
1024
  const components = await loadNamedExport(filePath, "resolvedComponents");
942
1025
  if (!Array.isArray(components)) throw new Error("syncore/_generated/components.ts must export resolvedComponents.");
943
1026
  return components;
944
1027
  }
1028
+ async function loadProjectRuntime(cwd) {
1029
+ const filePath = path.join(cwd, "syncore", "_generated", "runtime.ts");
1030
+ if (!await fileExists(filePath)) await runCodegen(cwd);
1031
+ const loaded = await loadTypeScriptModule(filePath);
1032
+ const schema = unwrapDefaultExport(loaded.schema);
1033
+ const functions = unwrapDefaultExport(loaded.functions);
1034
+ const components = unwrapDefaultExport(loaded.components);
1035
+ if (!schema || typeof schema !== "object" || typeof schema.tableNames !== "function") throw new Error("syncore/_generated/runtime.ts must export a composed Syncore schema.");
1036
+ if (!functions || typeof functions !== "object") throw new Error("syncore/_generated/runtime.ts must export a functions registry.");
1037
+ if (!Array.isArray(components)) throw new Error("syncore/_generated/runtime.ts must export resolved components.");
1038
+ return {
1039
+ schema,
1040
+ functions,
1041
+ components
1042
+ };
1043
+ }
1044
+ var HubExternalChangeSignal = class {
1045
+ publishToHub;
1046
+ listeners = /* @__PURE__ */ new Set();
1047
+ constructor(publishToHub) {
1048
+ this.publishToHub = publishToHub;
1049
+ }
1050
+ subscribe(listener) {
1051
+ this.listeners.add(listener);
1052
+ return () => {
1053
+ this.listeners.delete(listener);
1054
+ };
1055
+ }
1056
+ publish(event) {
1057
+ return this.publishToHub(event);
1058
+ }
1059
+ receive(event) {
1060
+ for (const listener of this.listeners) listener(event);
1061
+ }
1062
+ close() {
1063
+ this.listeners.clear();
1064
+ }
1065
+ };
945
1066
  var HubSqliteDriver = class {
1067
+ databasePath;
946
1068
  database;
947
1069
  transactionDepth = 0;
948
- constructor(filename) {
949
- this.database = new DatabaseSync(filename);
1070
+ constructor(databasePath) {
1071
+ this.databasePath = databasePath;
1072
+ this.database = new DatabaseSync(databasePath);
950
1073
  this.database.exec("PRAGMA foreign_keys = ON;");
951
1074
  this.database.exec("PRAGMA journal_mode = WAL;");
952
1075
  }
@@ -999,6 +1122,7 @@ var HubSqliteDriver = class {
999
1122
  }
1000
1123
  };
1001
1124
  var HubFileStorageAdapter = class {
1125
+ directory;
1002
1126
  constructor(directory) {
1003
1127
  this.directory = directory;
1004
1128
  }
@@ -1112,14 +1236,10 @@ const hubDevtoolsSqlSupport = {
1112
1236
  }
1113
1237
  }
1114
1238
  };
1115
- async function createProjectTargetBackend(cwd) {
1239
+ async function createProjectTargetBackend(cwd, externalChangeSignal) {
1116
1240
  const projectTarget = resolveProjectTargetConfig(await loadProjectConfig(cwd));
1117
1241
  if (!projectTarget) return null;
1118
- const [schema, functions, components] = await Promise.all([
1119
- loadProjectSchema(cwd),
1120
- loadProjectFunctions(cwd),
1121
- loadProjectResolvedComponents(cwd)
1122
- ]);
1242
+ const { schema, functions, components } = await loadProjectRuntime(cwd);
1123
1243
  const databasePath = path.resolve(cwd, projectTarget.databasePath);
1124
1244
  const storageDirectory = path.resolve(cwd, projectTarget.storageDirectory);
1125
1245
  await mkdir(path.dirname(databasePath), { recursive: true });
@@ -1131,9 +1251,10 @@ async function createProjectTargetBackend(cwd) {
1131
1251
  components,
1132
1252
  driver,
1133
1253
  storage: new HubFileStorageAdapter(storageDirectory),
1134
- platform: "project"
1254
+ platform: "project",
1255
+ ...externalChangeSignal ? { externalChangeSignal } : {}
1135
1256
  });
1136
- await runtime.prepareForDirectAccess();
1257
+ await runtime.start();
1137
1258
  const commandHandler = createDevtoolsCommandHandler({
1138
1259
  driver,
1139
1260
  schema,
@@ -1158,9 +1279,11 @@ async function createProjectTargetBackend(cwd) {
1158
1279
  platform: "project",
1159
1280
  sessionLabel: "Project Target",
1160
1281
  targetKind: "project",
1282
+ runtimeRole: "project-target",
1161
1283
  storageProtocol: "file",
1162
1284
  databaseLabel: path.basename(databasePath),
1163
- storageIdentity: `file::${databasePath}`
1285
+ storageIdentity: `file::${databasePath}`,
1286
+ capabilities: createProjectDevtoolsCapabilities()
1164
1287
  },
1165
1288
  handleCommand: commandHandler,
1166
1289
  subscribe(subscriptionId, payload, listener) {
@@ -1175,6 +1298,24 @@ async function createProjectTargetBackend(cwd) {
1175
1298
  }
1176
1299
  };
1177
1300
  }
1301
+ function createProjectDevtoolsCapabilities() {
1302
+ return {
1303
+ sql: {
1304
+ read: true,
1305
+ write: true,
1306
+ live: true
1307
+ },
1308
+ data: {
1309
+ browse: true,
1310
+ mutate: true,
1311
+ importExport: true
1312
+ },
1313
+ scheduler: {
1314
+ read: true,
1315
+ edit: true
1316
+ }
1317
+ };
1318
+ }
1178
1319
  function normalizeStorageInput(input) {
1179
1320
  if (typeof input === "string") return Buffer.from(input);
1180
1321
  if (input instanceof Uint8Array) return input;
@@ -1297,16 +1438,24 @@ function formatError(error) {
1297
1438
  }
1298
1439
  async function isLocalPortInUse(port) {
1299
1440
  return await new Promise((resolve) => {
1441
+ let settled = false;
1300
1442
  const socket = connect({
1301
1443
  host: "127.0.0.1",
1302
1444
  port
1303
1445
  });
1446
+ const finish = (inUse) => {
1447
+ if (settled) return;
1448
+ settled = true;
1449
+ clearTimeout(timeout);
1450
+ socket.destroy();
1451
+ resolve(inUse);
1452
+ };
1453
+ const timeout = setTimeout(() => finish(false), 100);
1304
1454
  socket.once("connect", () => {
1305
- socket.end();
1306
- resolve(true);
1455
+ finish(true);
1307
1456
  });
1308
1457
  socket.once("error", () => {
1309
- resolve(false);
1458
+ finish(false);
1310
1459
  });
1311
1460
  });
1312
1461
  }
@@ -1348,12 +1497,6 @@ async function startDevHub(options) {
1348
1497
  return await readDevtoolsSessionState(options.cwd) ?? sessionState;
1349
1498
  }
1350
1499
  await writeDevtoolsSessionState(options.cwd, sessionState);
1351
- let projectTargetBackend = null;
1352
- try {
1353
- projectTargetBackend = await createProjectTargetBackend(options.cwd);
1354
- } catch (error) {
1355
- console.warn(`Project target fallback unavailable: ${formatError(error)}`);
1356
- }
1357
1500
  const httpServer = createServer((_request, response) => {
1358
1501
  response.writeHead(200, { "content-type": "application/json" });
1359
1502
  response.end(JSON.stringify({
@@ -1368,6 +1511,14 @@ async function startDevHub(options) {
1368
1511
  const socketRuntimeIds = /* @__PURE__ */ new Map();
1369
1512
  const dashboardSockets = /* @__PURE__ */ new Set();
1370
1513
  const dashboardSubscriptions = /* @__PURE__ */ new Map();
1514
+ let relayExternalChange = () => {};
1515
+ const projectTargetExternalChangeSignal = new HubExternalChangeSignal((event) => relayExternalChange(PROJECT_TARGET_RUNTIME_ID, runtimeHellos.get(PROJECT_TARGET_RUNTIME_ID)?.storageIdentity ?? "", event));
1516
+ let projectTargetBackend = null;
1517
+ try {
1518
+ projectTargetBackend = await createProjectTargetBackend(options.cwd, projectTargetExternalChangeSignal);
1519
+ } catch (error) {
1520
+ console.warn(`Project target fallback unavailable: ${formatError(error)}`);
1521
+ }
1371
1522
  const hello = {
1372
1523
  type: "hello",
1373
1524
  protocolVersion: SYNCORE_DEVTOOLS_PROTOCOL_VERSION,
@@ -1380,12 +1531,30 @@ async function startDevHub(options) {
1380
1531
  runtimeHellos.set(PROJECT_TARGET_RUNTIME_ID, projectTargetBackend.hello);
1381
1532
  runtimeEvents.set(PROJECT_TARGET_RUNTIME_ID, []);
1382
1533
  }
1534
+ relayExternalChange = (sourceRuntimeId, storageIdentity, event) => {
1535
+ if (!storageIdentity) return;
1536
+ const message = {
1537
+ type: "external.change",
1538
+ runtimeId: sourceRuntimeId,
1539
+ storageIdentity,
1540
+ event
1541
+ };
1542
+ for (const [runtimeId, runtimeHello] of runtimeHellos) {
1543
+ if (runtimeId === sourceRuntimeId || runtimeHello.storageIdentity !== storageIdentity) continue;
1544
+ if (runtimeId === PROJECT_TARGET_RUNTIME_ID) {
1545
+ projectTargetExternalChangeSignal.receive(event);
1546
+ continue;
1547
+ }
1548
+ const targetSocket = runtimeSockets.get(runtimeId);
1549
+ if (targetSocket?.readyState === WebSocket.OPEN) targetSocket.send(JSON.stringify(message));
1550
+ }
1551
+ };
1383
1552
  const appendHubLog = async (event) => {
1384
1553
  const runtimeHello = runtimeHellos.get(event.runtimeId);
1385
- const clientRuntimeIds = [...runtimeHellos.values()].filter((hello) => hello.runtimeId !== "syncore-dev-hub" && hello.targetKind !== "project").map((hello) => hello.runtimeId).sort();
1386
- const clientTargetKeys = [...runtimeHellos.values()].filter((hello) => hello.runtimeId !== "syncore-dev-hub" && hello.targetKind !== "project").map((hello) => hello.storageIdentity ?? `runtime::${hello.runtimeId}`).sort();
1554
+ const clientRuntimeIds = [...runtimeHellos.values()].filter((hello) => hello.runtimeId !== "syncore-dev-hub").map((hello) => hello.runtimeId).sort();
1555
+ const clientTargetKeys = [...runtimeHellos.values()].filter((hello) => hello.runtimeId !== "syncore-dev-hub").map((hello) => hello.storageIdentity ?? `runtime::${hello.runtimeId}`).sort();
1387
1556
  const targetIdentity = runtimeHello?.storageIdentity ?? `runtime::${event.runtimeId}`;
1388
- const targetId = event.runtimeId === "syncore-dev-hub" ? "all" : runtimeHello?.targetKind === "project" ? "project" : createPublicTargetId(targetIdentity, clientTargetKeys);
1557
+ const targetId = event.runtimeId === "syncore-dev-hub" ? "all" : createPublicTargetId(targetIdentity, clientTargetKeys);
1389
1558
  const publicRuntimeId = event.runtimeId === "syncore-dev-hub" ? void 0 : createPublicRuntimeId(event.runtimeId, clientRuntimeIds);
1390
1559
  const category = event.type === "query.executed" ? "query" : event.type === "mutation.committed" ? "mutation" : event.type === "action.completed" ? "action" : "system";
1391
1560
  const message = event.type === "log" ? event.message : event.type === "query.executed" || event.type === "mutation.committed" || event.type === "action.completed" ? event.functionName : event.type;
@@ -1438,6 +1607,11 @@ async function startDevHub(options) {
1438
1607
  socket.send(JSON.stringify({ type: "pong" }));
1439
1608
  return;
1440
1609
  }
1610
+ if (message.type === "external.change") {
1611
+ const storageIdentity = runtimeHellos.get(message.runtimeId)?.storageIdentity ?? message.storageIdentity;
1612
+ if (storageIdentity && storageIdentity === message.storageIdentity) relayExternalChange(message.runtimeId, storageIdentity, message.event);
1613
+ return;
1614
+ }
1441
1615
  if (message.type === "command") {
1442
1616
  if (!isAuthorizedDashboardClient) return;
1443
1617
  const targetRuntimeId = message.targetRuntimeId;
@@ -1539,8 +1713,8 @@ async function startDevHub(options) {
1539
1713
  if (message.type === "event" && message.event.type === "runtime.disconnected") runtimeHellos.delete(message.event.runtimeId);
1540
1714
  if (message.type === "event" && message.event.runtimeId !== "syncore-dev-hub") {
1541
1715
  const history = runtimeEvents.get(message.event.runtimeId) ?? [];
1542
- history.unshift(message.event);
1543
- runtimeEvents.set(message.event.runtimeId, history.slice(0, 200));
1716
+ history.push(message.event);
1717
+ runtimeEvents.set(message.event.runtimeId, history.slice(-200));
1544
1718
  if (message.event.type === "runtime.disconnected") runtimeEvents.delete(message.event.runtimeId);
1545
1719
  appendHubLog(message.event);
1546
1720
  } else if (message.type === "event") appendHubLog(message.event);
@@ -1795,6 +1969,6 @@ function toSearchValue(value) {
1795
1969
  return stableStringify(value);
1796
1970
  }
1797
1971
  //#endregion
1798
- export { SYNCORE_MIGRATION_SNAPSHOT_FILE_NAME, VALID_SYNCORE_TEMPLATES, applyProjectMigrations, detectProjectTemplate, fileExists, formatError, getNextMigrationNumber, hasSyncoreProject, importJsonlIntoProject, isLocalPortInUse, loadProjectComponentsManifest, loadProjectConfig, loadProjectFunctions, loadProjectResolvedComponents, loadProjectRootSchema, loadProjectSchema, logScaffoldResult, readPackageJson, readStoredSnapshot, resolveDefaultSeedFile, resolvePortFromEnv, resolveProjectTargetConfig, resolveRequestedTemplate, runCodegen, runDevProjectBootstrap, runSyncoreCli, scaffoldProject, slugify, startDevHub, templateUsesConnectedClients, writeStoredSnapshot };
1972
+ export { SYNCORE_MIGRATION_SNAPSHOT_FILE_NAME, VALID_SYNCORE_TEMPLATES, applyProjectMigrations, detectProjectTemplate, fileExists, formatError, getNextMigrationNumber, hasSyncoreProject, importJsonlIntoProject, isLocalPortInUse, loadProjectComponentsManifest, loadProjectConfig, loadProjectFunctions, loadProjectResolvedComponents, loadProjectRootSchema, loadProjectRuntime, loadProjectSchema, logScaffoldResult, readPackageJson, readStoredSnapshot, resolveDefaultSeedFile, resolvePortFromEnv, resolveProjectTargetConfig, resolveRequestedTemplate, runCodegen, runDevProjectBootstrap, runSyncoreCli, scaffoldProject, slugify, startDevHub, templateUsesConnectedClients, writeStoredSnapshot };
1799
1973
 
1800
1974
  //# sourceMappingURL=cli.mjs.map