syncorejs 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +2 -1
  2. package/dist/_vendor/cli/app.d.mts.map +1 -1
  3. package/dist/_vendor/cli/app.mjs +330 -46
  4. package/dist/_vendor/cli/app.mjs.map +1 -1
  5. package/dist/_vendor/cli/context.mjs +27 -9
  6. package/dist/_vendor/cli/context.mjs.map +1 -1
  7. package/dist/_vendor/cli/dev-session.mjs.map +1 -1
  8. package/dist/_vendor/cli/doctor.mjs +513 -46
  9. package/dist/_vendor/cli/doctor.mjs.map +1 -1
  10. package/dist/_vendor/cli/errors.mjs.map +1 -1
  11. package/dist/_vendor/cli/help.mjs.map +1 -1
  12. package/dist/_vendor/cli/index.mjs +9 -2
  13. package/dist/_vendor/cli/index.mjs.map +1 -1
  14. package/dist/_vendor/cli/messages.mjs +5 -4
  15. package/dist/_vendor/cli/messages.mjs.map +1 -1
  16. package/dist/_vendor/cli/preflight.mjs.map +1 -1
  17. package/dist/_vendor/cli/project.mjs +125 -27
  18. package/dist/_vendor/cli/project.mjs.map +1 -1
  19. package/dist/_vendor/cli/render.mjs +57 -9
  20. package/dist/_vendor/cli/render.mjs.map +1 -1
  21. package/dist/_vendor/cli/targets.mjs +4 -3
  22. package/dist/_vendor/cli/targets.mjs.map +1 -1
  23. package/dist/_vendor/core/cli.d.mts +20 -4
  24. package/dist/_vendor/core/cli.d.mts.map +1 -1
  25. package/dist/_vendor/core/cli.mjs +458 -133
  26. package/dist/_vendor/core/cli.mjs.map +1 -1
  27. package/dist/_vendor/core/devtools-auth.mjs +60 -0
  28. package/dist/_vendor/core/devtools-auth.mjs.map +1 -0
  29. package/dist/_vendor/core/index.d.mts +5 -3
  30. package/dist/_vendor/core/index.mjs +22 -2
  31. package/dist/_vendor/core/index.mjs.map +1 -1
  32. package/dist/_vendor/core/runtime/components.d.mts +111 -0
  33. package/dist/_vendor/core/runtime/components.d.mts.map +1 -0
  34. package/dist/_vendor/core/runtime/components.mjs +186 -0
  35. package/dist/_vendor/core/runtime/components.mjs.map +1 -0
  36. package/dist/_vendor/core/runtime/devtools.d.mts +4 -4
  37. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  38. package/dist/_vendor/core/runtime/devtools.mjs +178 -60
  39. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  40. package/dist/_vendor/core/runtime/functions.d.mts +398 -16
  41. package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
  42. package/dist/_vendor/core/runtime/functions.mjs +74 -3
  43. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  44. package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
  45. package/dist/_vendor/core/runtime/id.mjs.map +1 -1
  46. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +83 -0
  47. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -0
  48. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +720 -0
  49. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -0
  50. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +234 -0
  51. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -0
  52. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +255 -0
  53. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -0
  54. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +200 -0
  55. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -0
  56. package/dist/_vendor/core/runtime/internal/engines/shared.mjs +252 -0
  57. package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -0
  58. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +145 -0
  59. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -0
  60. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +221 -0
  61. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -0
  62. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs +32 -0
  63. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -0
  64. package/dist/_vendor/core/runtime/internal/systemMeta.mjs +61 -0
  65. package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -0
  66. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +41 -0
  67. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -0
  68. package/dist/_vendor/core/runtime/runtime.d.mts +1187 -202
  69. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  70. package/dist/_vendor/core/runtime/runtime.mjs +73 -1365
  71. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  72. package/dist/_vendor/core/transport.d.mts +113 -0
  73. package/dist/_vendor/core/transport.d.mts.map +1 -0
  74. package/dist/_vendor/core/transport.mjs +428 -0
  75. package/dist/_vendor/core/transport.mjs.map +1 -0
  76. package/dist/_vendor/devtools-protocol/index.d.ts +187 -4
  77. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  78. package/dist/_vendor/devtools-protocol/index.js +25 -9
  79. package/dist/_vendor/devtools-protocol/index.js.map +1 -1
  80. package/dist/_vendor/next/config.d.ts +3 -4
  81. package/dist/_vendor/next/config.d.ts.map +1 -1
  82. package/dist/_vendor/next/config.js +37 -19
  83. package/dist/_vendor/next/config.js.map +1 -1
  84. package/dist/_vendor/next/index.d.ts +109 -29
  85. package/dist/_vendor/next/index.d.ts.map +1 -1
  86. package/dist/_vendor/next/index.js +104 -26
  87. package/dist/_vendor/next/index.js.map +1 -1
  88. package/dist/_vendor/platform-expo/index.d.ts +156 -37
  89. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  90. package/dist/_vendor/platform-expo/index.js +80 -12
  91. package/dist/_vendor/platform-expo/index.js.map +1 -1
  92. package/dist/_vendor/platform-expo/react.d.ts.map +1 -1
  93. package/dist/_vendor/platform-expo/react.js +11 -10
  94. package/dist/_vendor/platform-expo/react.js.map +1 -1
  95. package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
  96. package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
  97. package/dist/_vendor/platform-node/index.d.mts +192 -24
  98. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  99. package/dist/_vendor/platform-node/index.mjs +236 -97
  100. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  101. package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -1
  102. package/dist/_vendor/platform-node/ipc-react.mjs +15 -2
  103. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  104. package/dist/_vendor/platform-node/ipc.d.mts +11 -35
  105. package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
  106. package/dist/_vendor/platform-node/ipc.mjs +3 -273
  107. package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
  108. package/dist/_vendor/platform-web/external-change.d.ts +43 -1
  109. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
  110. package/dist/_vendor/platform-web/external-change.js +32 -1
  111. package/dist/_vendor/platform-web/external-change.js.map +1 -1
  112. package/dist/_vendor/platform-web/index.d.ts +323 -51
  113. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  114. package/dist/_vendor/platform-web/index.js +233 -30
  115. package/dist/_vendor/platform-web/index.js.map +1 -1
  116. package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
  117. package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
  118. package/dist/_vendor/platform-web/indexeddb.js +10 -0
  119. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  120. package/dist/_vendor/platform-web/opfs.d.ts +13 -0
  121. package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
  122. package/dist/_vendor/platform-web/opfs.js +12 -0
  123. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  124. package/dist/_vendor/platform-web/persistence.d.ts +54 -0
  125. package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
  126. package/dist/_vendor/platform-web/persistence.js +15 -0
  127. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  128. package/dist/_vendor/platform-web/react.d.ts +1 -2
  129. package/dist/_vendor/platform-web/react.d.ts.map +1 -1
  130. package/dist/_vendor/platform-web/react.js +27 -13
  131. package/dist/_vendor/platform-web/react.js.map +1 -1
  132. package/dist/_vendor/platform-web/sqljs.js +10 -1
  133. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  134. package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
  135. package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
  136. package/dist/_vendor/platform-web/worker.d.ts +71 -44
  137. package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
  138. package/dist/_vendor/platform-web/worker.js +40 -271
  139. package/dist/_vendor/platform-web/worker.js.map +1 -1
  140. package/dist/_vendor/react/index.d.ts +222 -23
  141. package/dist/_vendor/react/index.d.ts.map +1 -1
  142. package/dist/_vendor/react/index.js +476 -63
  143. package/dist/_vendor/react/index.js.map +1 -1
  144. package/dist/_vendor/schema/definition.d.ts +151 -37
  145. package/dist/_vendor/schema/definition.d.ts.map +1 -1
  146. package/dist/_vendor/schema/definition.js +102 -20
  147. package/dist/_vendor/schema/definition.js.map +1 -1
  148. package/dist/_vendor/schema/index.d.ts +4 -4
  149. package/dist/_vendor/schema/index.js +2 -2
  150. package/dist/_vendor/schema/planner.d.ts +19 -2
  151. package/dist/_vendor/schema/planner.d.ts.map +1 -1
  152. package/dist/_vendor/schema/planner.js +79 -3
  153. package/dist/_vendor/schema/planner.js.map +1 -1
  154. package/dist/_vendor/schema/validators.d.ts +279 -83
  155. package/dist/_vendor/schema/validators.d.ts.map +1 -1
  156. package/dist/_vendor/schema/validators.js +330 -38
  157. package/dist/_vendor/schema/validators.js.map +1 -1
  158. package/dist/_vendor/svelte/index.d.ts +245 -19
  159. package/dist/_vendor/svelte/index.d.ts.map +1 -1
  160. package/dist/_vendor/svelte/index.js +443 -20
  161. package/dist/_vendor/svelte/index.js.map +1 -1
  162. package/dist/browser.d.ts.map +1 -1
  163. package/dist/cli.js +3 -1
  164. package/dist/cli.js.map +1 -1
  165. package/dist/components.d.ts +2 -0
  166. package/dist/components.js +2 -0
  167. package/dist/index.d.ts +3 -2
  168. package/dist/index.js +2 -1
  169. package/package.json +29 -21
package/README.md CHANGED
@@ -18,7 +18,7 @@ npx syncorejs dev
18
18
  ## Imports
19
19
 
20
20
  ```ts
21
- import { defineSchema, defineTable, query, mutation, v } from "syncorejs";
21
+ import { defineSchema, defineTable, query, mutation, s } from "syncorejs";
22
22
  import { useQuery, useMutation } from "syncorejs/react";
23
23
  import { createBrowserWorkerClient } from "syncorejs/browser";
24
24
  import { SyncoreNextProvider } from "syncorejs/next";
@@ -28,3 +28,4 @@ import { SyncoreNextProvider } from "syncorejs/next";
28
28
 
29
29
  - Repository: https://github.com/JPSAUD501/Syncore
30
30
  - Quickstarts: https://github.com/JPSAUD501/Syncore/tree/main/docs/quickstarts
31
+
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.mts","names":[],"sources":["../src/app.ts"],"mappings":";;;iBAqIsB,aAAA,CAAc,IAAA,cAAsB,OAAA"}
1
+ {"version":3,"file":"app.d.mts","names":[],"sources":["../src/app.ts"],"mappings":";;;iBAgJsB,aAAA,CAAc,IAAA,cAAsB,OAAO"}
@@ -1,16 +1,17 @@
1
1
  import { CliContext, openTarget } from "./context.mjs";
2
2
  import { printCompactDevPhase, printDevSessionIntro, runShellCommand, withConsoleCapture } from "./dev-session.mjs";
3
- import { buildRuntimeLookup, connectToProjectHub, createManagedProjectClient, createPublicRuntimeId, exportProjectData, importProjectData, isKnownTemplate, listAvailableTargets, listConnectedClientTargets, listProjectTables, loadImportDocumentBatches, readProjectTable, resolveDashboardUrl, resolveDevtoolsUrl, resolveDocsTarget, resolveProjectFunction, targetSupportsCapability, writeExportData } from "./project.mjs";
4
- import { buildDevBootstrapNextSteps, buildHubUnavailableNextSteps, buildInitNextSteps, buildTargetCommandNextSteps, templateUsesConnectedClients } from "./messages.mjs";
5
- import { buildDoctorReport } from "./doctor.mjs";
3
+ import { buildRuntimeLookup, connectToProjectHub, createManagedProjectClient, createPublicRuntimeId, exportProjectData, importProjectData, isKnownTemplate, listAvailableTargets, listConnectedClientTargets, listProjectTables, loadImportDocumentBatches, readProjectTable, resolveActiveDashboardUrl, resolveDashboardUrl, resolveDevtoolsUrl, resolveDocsTarget, resolveProjectFunction, targetSupportsCapability, writeExportData } from "./project.mjs";
4
+ import { buildDevBootstrapNextSteps, buildHubUnavailableNextSteps, buildInitNextSteps, buildTargetCommandNextSteps, templateUsesConnectedClients as templateUsesConnectedClients$1 } from "./messages.mjs";
5
+ import { applyDoctorFixes, buildDoctorReport } from "./doctor.mjs";
6
6
  import { applyRootHelp } from "./help.mjs";
7
- import { printDevReadySummary, printDoctorReport, printTargetsTable, renderOutput } from "./render.mjs";
7
+ import { formatPersistedLogEntry, printDevReadySummary, printDoctorReport, printTargetsTable, renderOutput } from "./render.mjs";
8
8
  import { resolveClientRuntime, resolveOperationalTarget } from "./targets.mjs";
9
9
  import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
10
10
  import path from "node:path";
11
+ import { spawn } from "node:child_process";
11
12
  import { Command } from "commander";
12
13
  import { createSchemaSnapshot, diffSchemaSnapshots, renderMigrationSql } from "../core/index.mjs";
13
- import { VALID_SYNCORE_TEMPLATES, applyProjectMigrations, detectProjectTemplate, formatError, getNextMigrationNumber, hasSyncoreProject, isLocalPortInUse, loadProjectSchema, readStoredSnapshot, resolveRequestedTemplate, runCodegen, runDevProjectBootstrap, scaffoldProject, slugify, startDevHub, writeStoredSnapshot } from "../core/cli.mjs";
14
+ import { VALID_SYNCORE_TEMPLATES, applyProjectMigrations, detectProjectTemplate, fileExists, formatError, getNextMigrationNumber, hasSyncoreProject, isLocalPortInUse, loadProjectSchema, readStoredSnapshot, resolveRequestedTemplate, runCodegen, runDevProjectBootstrap, scaffoldProject, slugify, startDevHub, writeStoredSnapshot } from "../core/cli.mjs";
14
15
  //#region src/app.ts
15
16
  async function runSyncoreCli(argv = process.argv) {
16
17
  const program = buildProgram();
@@ -91,26 +92,37 @@ function addCodegenCommand(program) {
91
92
  });
92
93
  }
93
94
  function addDoctorCommand(program) {
94
- program.command("doctor").summary("Inspect the current Syncore project state").description("Check project structure, template capabilities, hub state, and available targets.").addHelpText("after", [
95
+ program.command("doctor").summary("Inspect the current Syncore project state").description("Check project structure, template capabilities, hub state, and available targets.").option("--fix", "Apply safe low-risk fixes like codegen and snapshot refresh").addHelpText("after", [
95
96
  "",
96
97
  "Examples:",
97
98
  " npx syncorejs doctor",
98
- " npx syncorejs doctor --json"
99
- ].join("\n")).action(async (_options, command) => {
99
+ " npx syncorejs doctor --json",
100
+ " npx syncorejs doctor --fix"
101
+ ].join("\n")).action(async (options, command) => {
100
102
  const ctx = createContext(command);
101
103
  await executeCommand(ctx, async () => {
102
- const report = await buildDoctorReport(ctx.cwd);
104
+ let report = await buildDoctorReport(ctx.cwd);
105
+ let appliedFixes = [];
106
+ if (options.fix) {
107
+ appliedFixes = await applyDoctorFixes(ctx.cwd, report);
108
+ report = await buildDoctorReport(ctx.cwd);
109
+ }
103
110
  if (ctx.json) {
104
111
  ctx.printResult({
105
112
  command: "doctor",
106
- data: report
113
+ ...options.fix && appliedFixes.length > 0 ? { summary: `Applied ${appliedFixes.length} safe fix(es).` } : {},
114
+ data: {
115
+ ...report,
116
+ ...options.fix ? { appliedFixes } : {}
117
+ }
107
118
  });
108
119
  return;
109
120
  }
110
- ctx.info(`Detected template: ${report.template}`);
111
- ctx.info(`Project status: ${report.status}`);
112
- ctx.info(`Project target: ${report.projectTarget ? report.projectTarget.databasePath : "not configured"}`);
113
- ctx.info(`Devtools hub: ${report.hub.running ? report.hub.url : "not running"}`);
121
+ ctx.info(report.primaryIssue.summary);
122
+ if (options.fix) if (appliedFixes.length > 0) {
123
+ ctx.success(`Applied ${appliedFixes.length} safe fix(es).`);
124
+ for (const fix of appliedFixes) ctx.info(fix);
125
+ } else ctx.info("No safe fixes were applied.");
114
126
  printDoctorReport(report, { verbose: ctx.verbose });
115
127
  if (report.workspaceMatches.length > 0) {
116
128
  ctx.warn("You appear to be at a workspace root instead of inside an app package.");
@@ -147,26 +159,31 @@ function addTargetsCommand(program) {
147
159
  });
148
160
  }
149
161
  function addDevCommand(program) {
150
- program.command("dev").summary("Run the Syncore development loop").description("Bootstrap the local Syncore project, start the hub, discover targets, and keep the local workflow in sync.").option("--template <template>", `Template to scaffold when Syncore is missing (${VALID_SYNCORE_TEMPLATES.join(", ")}, or auto)`, "auto").option("--once", "Run bootstrap once and exit").option("--until-success", "Retry bootstrap until it succeeds").option("--run <function>", "Run a Syncore function after bootstrap succeeds").option("--run-sh <command>", "Run a shell command after bootstrap succeeds").option("--open-dashboard", "Open the dashboard URL even in non-interactive mode").addHelpText("after", [
162
+ program.command("dev").summary("Run the Syncore development loop").description("Bootstrap the local Syncore project, start the hub, discover targets, and keep the local workflow in sync.").option("--template <template>", `Template to scaffold when Syncore is missing (${VALID_SYNCORE_TEMPLATES.join(", ")}, or auto)`, "auto").option("--once", "Run bootstrap once and exit").option("--until-success", "Retry bootstrap until it succeeds").option("--run <function>", "Run a Syncore function after bootstrap succeeds").option("--run-sh <command>", "Run a shell command after bootstrap succeeds").option("--typecheck <mode>", "Run TypeScript typecheck before entering the local dev loop: enable, try, or disable", "try").option("--tail-logs <mode>", "Control whether runtime logs appear in this terminal: always, errors, or disable", "errors").option("--no-open-dashboard", "Do not open the dashboard automatically after the hub is ready").addHelpText("after", [
151
163
  "",
152
164
  "Examples:",
153
165
  " npx syncorejs dev",
154
166
  " npx syncorejs dev --once",
155
167
  " npx syncorejs dev --until-success",
156
168
  " npx syncorejs dev --run tasks/list",
157
- " npx syncorejs dev --open-dashboard",
158
- " npx syncorejs dev --run-sh \"npm run dev\""
169
+ " npx syncorejs dev --no-open-dashboard",
170
+ " npx syncorejs dev --run-sh \"npm run dev\"",
171
+ " npx syncorejs dev --typecheck enable",
172
+ " npx syncorejs dev --tail-logs always"
159
173
  ].join("\n")).action(async (options, command) => {
160
174
  const ctx = createContext(command);
161
175
  await executeCommand(ctx, async () => {
162
176
  if (options.run && options.runSh) ctx.fail("`syncorejs dev` accepts either --run or --run-sh, not both.");
163
- const shouldOpenDashboard = Boolean(options.openDashboard) || isRealInteractiveTerminal(ctx);
177
+ const shouldOpenDashboard = options.openDashboard ?? true;
164
178
  await ensureLocalPortConfiguration(ctx);
165
179
  const template = await resolveRequestedTemplate(ctx.cwd, options.template);
180
+ validateDevModes(ctx, options);
166
181
  printDevSessionIntro(ctx);
167
182
  await ensureDevProjectExists(ctx, template);
183
+ printDevPreflight(ctx, await buildDoctorReport(ctx.cwd));
184
+ const typecheckResult = await runDevTypecheck(ctx, options.typecheck);
168
185
  if (options.once) {
169
- await runDevBootstrapLoop(ctx, template, options.untilSuccess ?? false);
186
+ const bootstrapReport = await runDevBootstrapLoop(ctx, template, options.untilSuccess ?? false, options.tailLogs);
170
187
  await runDevFollowup(ctx, options);
171
188
  const targets = await listAvailableTargets(ctx.cwd);
172
189
  ctx.printResult({
@@ -179,32 +196,39 @@ function addDevCommand(program) {
179
196
  projectTargetConfigured: targets.some((target) => target.kind === "project"),
180
197
  dashboardUrl: resolveDashboardUrl(),
181
198
  devtoolsUrl: resolveDevtoolsUrl(),
182
- targets
199
+ targets,
200
+ codegenStatus: "refreshed",
201
+ driftStatus: describeDevDriftStatus(bootstrapReport),
202
+ typecheckStatus: describeTypecheckStatus(typecheckResult)
183
203
  });
184
204
  return;
185
205
  }
186
- await runDevBootstrapLoop(ctx, template, options.untilSuccess ?? false);
206
+ const bootstrapReport = await runDevBootstrapLoop(ctx, template, options.untilSuccess ?? false, options.tailLogs);
187
207
  const targets = await listAvailableTargets(ctx.cwd);
188
208
  printDevReadySummary(ctx, {
189
209
  template,
190
210
  projectTargetConfigured: targets.some((target) => target.kind === "project"),
191
211
  dashboardUrl: resolveDashboardUrl(),
192
212
  devtoolsUrl: resolveDevtoolsUrl(),
193
- targets
213
+ targets,
214
+ codegenStatus: "refreshed",
215
+ driftStatus: describeDevDriftStatus(bootstrapReport),
216
+ typecheckStatus: describeTypecheckStatus(typecheckResult)
194
217
  });
195
- await startManagedDevHub(ctx, template);
196
- await maybeOpenDashboard(ctx, shouldOpenDashboard);
197
- await monitorLiveDevSession(ctx, template);
218
+ await maybeOpenDashboard(ctx, shouldOpenDashboard, await startManagedDevHub(ctx, template));
219
+ await monitorLiveDevSession(ctx, template, options.tailLogs);
198
220
  });
199
221
  });
200
222
  }
201
- function isRealInteractiveTerminal(context) {
202
- return context.interactive && Boolean(process.stdin.isTTY && process.stdout.isTTY);
203
- }
204
- async function maybeOpenDashboard(context, shouldOpenDashboard) {
223
+ async function maybeOpenDashboard(context, shouldOpenDashboard, hubSession) {
205
224
  if (!shouldOpenDashboard) return;
206
- if (await openTarget(resolveDashboardUrl())) {
207
- context.info(`Opened dashboard at ${resolveDashboardUrl()}.`);
225
+ const targetUrl = hubSession?.authenticatedDashboardUrl ?? await resolveActiveDashboardUrl(context.cwd);
226
+ if (!await waitForDashboardReady(targetUrl)) {
227
+ context.warn("Dashboard did not become ready in time, so it was not opened.");
228
+ return;
229
+ }
230
+ if (await openTarget(targetUrl)) {
231
+ context.info(`Opened dashboard at ${targetUrl}`);
208
232
  return;
209
233
  }
210
234
  context.warn("Unable to open the dashboard automatically.");
@@ -291,18 +315,18 @@ function addRunCommand(program) {
291
315
  const ctx = createContext(command);
292
316
  await executeCommand(ctx, async () => {
293
317
  if (options.runtime && !options.target) ctx.fail("`syncorejs run --runtime` requires --target.");
294
- const resolved = await resolveProjectFunction(ctx.cwd, functionName);
295
318
  const args = parseJsonObject(argsText, "Function arguments");
296
- if (options.watch && resolved.definition.kind !== "query") ctx.fail("`syncorejs run --watch` only supports query functions.");
297
319
  const target = await resolveOperationalTarget(ctx, options.target, {
298
320
  command: "run",
299
321
  capability: "run"
300
322
  });
301
323
  const runtime = resolveClientRuntime(target, options.runtime, { command: "run" });
302
- ctx.info(options.watch ? `Watching ${resolved.name} on ${target.id}${runtime ? ` (${runtime.id} ${runtime.label})` : ""}.` : `Running ${resolved.name} on ${target.id}${runtime ? ` (${runtime.id} ${runtime.label})` : ""}.`);
303
324
  if (target.kind === "project") {
304
325
  const managed = await createManagedProjectClient(ctx.cwd);
305
326
  try {
327
+ const resolved = await resolveProjectFunction(ctx.cwd, functionName, managed.functions);
328
+ if (options.watch && resolved.definition.kind !== "query") ctx.fail("`syncorejs run --watch` only supports query functions.");
329
+ ctx.info(options.watch ? `Watching ${resolved.name} on ${target.id}.` : `Running ${resolved.name} on ${target.id}.`);
306
330
  if (options.watch) {
307
331
  const watch = managed.client.watchQuery(resolved.reference, args);
308
332
  const render = () => {
@@ -326,6 +350,9 @@ function addRunCommand(program) {
326
350
  await managed.dispose();
327
351
  }
328
352
  }
353
+ const resolved = await resolveProjectFunction(ctx.cwd, functionName);
354
+ if (options.watch && resolved.definition.kind !== "query") ctx.fail("`syncorejs run --watch` only supports query functions.");
355
+ ctx.info(options.watch ? `Watching ${resolved.name} on ${target.id}${runtime ? ` (${runtime.id} ${runtime.label})` : ""}.` : `Running ${resolved.name} on ${target.id}${runtime ? ` (${runtime.id} ${runtime.label})` : ""}.`);
329
356
  const hub = await requireHubConnection(ctx);
330
357
  try {
331
358
  if (options.watch) {
@@ -395,7 +422,12 @@ function addDataCommand(program) {
395
422
  data: tables,
396
423
  target: target.id
397
424
  });
398
- if (!ctx.json) for (const entry of tables) process.stdout.write(` ${entry.name} (${entry.documentCount} document(s))\n`);
425
+ if (!ctx.json) for (const entry of tables) {
426
+ const tableEntry = entry;
427
+ const label = typeof tableEntry.displayName === "string" && tableEntry.displayName.length > 0 && tableEntry.displayName !== tableEntry.name ? `${tableEntry.displayName} -> ${tableEntry.name}` : tableEntry.name;
428
+ const owner = tableEntry.owner === "component" ? ` component:${String(tableEntry.componentPath ?? "unknown")}` : "";
429
+ process.stdout.write(` ${label} (${tableEntry.documentCount} document(s))${owner}\n`);
430
+ }
399
431
  return;
400
432
  }
401
433
  if (target.kind === "project") {
@@ -506,14 +538,18 @@ function addDashboardCommand(program) {
506
538
  const ctx = createContext(command);
507
539
  await executeCommand(ctx, async () => {
508
540
  const url = resolveDashboardUrl();
541
+ const activeUrl = await resolveActiveDashboardUrl(ctx.cwd);
509
542
  if (options.open) {
510
- if (!await openTarget(url)) ctx.warn("Unable to open the dashboard automatically.");
543
+ if (!(await waitForDashboardReady(activeUrl) ? await openTarget(activeUrl) : false)) ctx.warn("Unable to open the dashboard automatically.");
511
544
  }
512
545
  ctx.printResult({
513
546
  summary: "Dashboard URL resolved.",
514
547
  command: "dashboard",
515
- data: { url },
516
- nextSteps: [`Open ${url}`]
548
+ data: {
549
+ url: activeUrl,
550
+ baseUrl: url
551
+ },
552
+ nextSteps: [`Open ${activeUrl}`]
517
553
  });
518
554
  });
519
555
  });
@@ -559,13 +595,15 @@ async function ensureLocalPortConfiguration(context) {
559
595
  if (Number.isFinite(dashboardPort) && Number.isFinite(devtoolsPort) && dashboardPort === devtoolsPort) context.fail([`Dashboard and devtools cannot share the same port (${dashboardPort}).`, "Set different values for SYNCORE_DASHBOARD_PORT and SYNCORE_DEVTOOLS_PORT, then rerun `npx syncorejs dev`."].join(" "));
560
596
  if (Number.isFinite(dashboardPort) && dashboardPort > 0 && Number.isFinite(devtoolsPort) && devtoolsPort > 0 && await isLocalPortInUse(dashboardPort) && !await isLocalPortInUse(devtoolsPort)) context.warn(`Dashboard port ${dashboardPort} is already in use. If Syncore does not start cleanly, set SYNCORE_DASHBOARD_PORT to a different value.`);
561
597
  }
562
- async function runDevBootstrapLoop(context, template, untilSuccess) {
598
+ async function runDevBootstrapLoop(context, template, untilSuccess, tailLogs) {
563
599
  while (true) try {
600
+ let sawBootstrapFailure = false;
564
601
  printCompactDevPhase(context, "Project");
565
602
  printCompactDevPhase(context, "Codegen");
566
603
  printCompactDevPhase(context, "Schema");
567
604
  await withConsoleCapture((method, message) => {
568
605
  if (/destructive schema changes/i.test(message)) {
606
+ sawBootstrapFailure = true;
569
607
  context.error("Syncore dev blocked by destructive schema changes.");
570
608
  return;
571
609
  }
@@ -573,9 +611,20 @@ async function runDevBootstrapLoop(context, template, untilSuccess) {
573
611
  context.warn(message.replace(/^Syncore dev warning:\s*/i, ""));
574
612
  return;
575
613
  }
576
- if (/bootstrap failed/i.test(message) || method === "error") context.error(message);
614
+ if (/bootstrap failed/i.test(message) || method === "error") {
615
+ sawBootstrapFailure = true;
616
+ context.error(message);
617
+ }
577
618
  }, async () => runDevProjectBootstrap(context.cwd, template));
578
- return;
619
+ const report = await buildDoctorReport(context.cwd);
620
+ if (sawBootstrapFailure || report.status === "schema-destructive-drift") {
621
+ if (tailLogs === "errors") await printRecentRuntimeSignals(context, context.cwd);
622
+ context.fail(report.primaryIssue.summary, 1, report, {
623
+ category: "runtime",
624
+ nextSteps: report.suggestions
625
+ });
626
+ }
627
+ return report;
579
628
  } catch (error) {
580
629
  if (!untilSuccess) throw error;
581
630
  context.warn(`Syncore dev bootstrap failed, retrying: ${formatError(error)}`);
@@ -585,7 +634,7 @@ async function runDevBootstrapLoop(context, template, untilSuccess) {
585
634
  async function startManagedDevHub(context, template) {
586
635
  printCompactDevPhase(context, "Hub");
587
636
  printCompactDevPhase(context, "Targets");
588
- await withConsoleCapture((method, message) => {
637
+ return await withConsoleCapture((method, message) => {
589
638
  if (/already running/i.test(message)) {
590
639
  context.info(message.replaceAll("127.0.0.1", "localhost"));
591
640
  return;
@@ -609,6 +658,28 @@ async function startManagedDevHub(context, template) {
609
658
  template
610
659
  }));
611
660
  }
661
+ async function waitForDashboardReady(url, options = {}) {
662
+ const timeoutMs = options.timeoutMs ?? 15e3;
663
+ const intervalMs = options.intervalMs ?? 250;
664
+ const deadline = Date.now() + timeoutMs;
665
+ while (Date.now() < deadline) {
666
+ try {
667
+ const controller = new AbortController();
668
+ const timeout = setTimeout(() => controller.abort(), intervalMs);
669
+ try {
670
+ const response = await fetch(url, {
671
+ signal: controller.signal,
672
+ redirect: "manual"
673
+ });
674
+ if (response.ok || response.status === 304) return true;
675
+ } finally {
676
+ clearTimeout(timeout);
677
+ }
678
+ } catch {}
679
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
680
+ }
681
+ return false;
682
+ }
612
683
  async function runDevFollowup(context, options) {
613
684
  if (options.run) {
614
685
  const target = await resolveOperationalTarget(context, void 0, {
@@ -642,10 +713,13 @@ async function runDevFollowup(context, options) {
642
713
  }
643
714
  if (options.runSh) await runShellCommand(context, options.runSh);
644
715
  }
645
- async function monitorLiveDevSession(context, template) {
646
- if (!templateUsesConnectedClients(template)) {
716
+ async function monitorLiveDevSession(context, template, tailLogs) {
717
+ const stopTailing = tailLogs === "always" ? startRuntimeLogTail(context, context.cwd) : void 0;
718
+ if (!templateUsesConnectedClients$1(template)) try {
647
719
  await waitForSignal();
648
720
  return;
721
+ } finally {
722
+ stopTailing?.();
649
723
  }
650
724
  let knownTargets = /* @__PURE__ */ new Set();
651
725
  let waitingNoticeVisible = false;
@@ -653,7 +727,10 @@ async function monitorLiveDevSession(context, template) {
653
727
  const nextTargets = await listConnectedClientTargets();
654
728
  const nextIds = new Set(nextTargets.map((target) => target.id));
655
729
  for (const target of nextTargets) if (!knownTargets.has(target.id)) context.info(`Client target connected: ${target.id}`);
656
- for (const targetId of knownTargets) if (!nextIds.has(targetId)) context.warn(`Client target disconnected: ${targetId}`);
730
+ for (const targetId of knownTargets) if (!nextIds.has(targetId)) {
731
+ context.warn(`Client target disconnected: ${targetId}`);
732
+ if (tailLogs === "errors") await printRecentRuntimeSignals(context, context.cwd);
733
+ }
657
734
  if (nextTargets.length === 0 && !waitingNoticeVisible) {
658
735
  context.info("Hub ready. Start your app to connect a client target.");
659
736
  waitingNoticeVisible = true;
@@ -668,6 +745,157 @@ async function monitorLiveDevSession(context, template) {
668
745
  await waitForSignal();
669
746
  } finally {
670
747
  clearInterval(interval);
748
+ stopTailing?.();
749
+ }
750
+ }
751
+ function validateDevModes(context, options) {
752
+ if (![
753
+ "enable",
754
+ "try",
755
+ "disable"
756
+ ].includes(options.typecheck)) context.fail(`Unknown typecheck mode ${JSON.stringify(options.typecheck)}. Expected enable, try, or disable.`);
757
+ if (![
758
+ "always",
759
+ "errors",
760
+ "disable"
761
+ ].includes(options.tailLogs)) context.fail(`Unknown tail log mode ${JSON.stringify(options.tailLogs)}. Expected always, errors, or disable.`);
762
+ }
763
+ function printDevPreflight(context, report) {
764
+ if (report.status === "missing-generated") {
765
+ context.info("Preflight: generated Syncore files are missing; dev will refresh them.");
766
+ return;
767
+ }
768
+ if (report.status === "schema-drift") {
769
+ context.info("Preflight: schema drift detected; dev will refresh local Syncore state where safe.");
770
+ return;
771
+ }
772
+ if (report.status === "waiting-for-client") {
773
+ context.info("Preflight: this template uses client-managed runtimes; connect the app to unlock live targets.");
774
+ return;
775
+ }
776
+ context.info("Preflight: Syncore project structure and local runtime prerequisites were inspected.");
777
+ }
778
+ async function runDevTypecheck(context, mode) {
779
+ if (mode === "disable") return {
780
+ mode,
781
+ attempted: false,
782
+ ok: true,
783
+ summary: "disabled"
784
+ };
785
+ const tsconfigPath = await findTypecheckConfig(context.cwd);
786
+ if (!tsconfigPath) {
787
+ if (mode === "enable") context.fail("Typecheck was enabled but no tsconfig.json was found in this project.");
788
+ context.warn("Typecheck skipped because no tsconfig.json was found.");
789
+ return {
790
+ mode,
791
+ attempted: false,
792
+ ok: true,
793
+ summary: "skipped (no tsconfig)"
794
+ };
795
+ }
796
+ const tscPath = await findTypeScriptCompiler(context.cwd);
797
+ if (!tscPath) {
798
+ if (mode === "enable") context.fail("Typecheck was enabled but no local TypeScript compiler was found.");
799
+ context.warn("Typecheck skipped because TypeScript is not available in this workspace.");
800
+ return {
801
+ mode,
802
+ attempted: false,
803
+ ok: true,
804
+ summary: "skipped (tsc unavailable)"
805
+ };
806
+ }
807
+ context.info(`Typecheck: running tsc --noEmit -p ${path.basename(tsconfigPath)}.`);
808
+ const result = await runTypeScriptCompiler(context.cwd, tscPath, tsconfigPath);
809
+ if (result.ok) {
810
+ context.success("Typecheck passed.");
811
+ return {
812
+ mode,
813
+ attempted: true,
814
+ ok: true,
815
+ summary: "passed"
816
+ };
817
+ }
818
+ const detail = summarizeCompilerOutput(result.output);
819
+ if (mode === "enable") context.fail(`Typecheck failed.${detail ? ` ${detail}` : ""}`, 1, result.output, { category: "validation" });
820
+ context.warn(`Typecheck reported issues but dev will continue.${detail ? ` ${detail}` : ""}`);
821
+ return {
822
+ mode,
823
+ attempted: true,
824
+ ok: false,
825
+ summary: "warning",
826
+ ...detail ? { details: detail } : {}
827
+ };
828
+ }
829
+ async function findTypecheckConfig(cwd) {
830
+ for (const candidate of [
831
+ "tsconfig.json",
832
+ "tsconfig.app.json",
833
+ "tsconfig.main.json",
834
+ "tsconfig.build.json"
835
+ ]) {
836
+ const resolved = path.join(cwd, candidate);
837
+ if (await fileExists(resolved)) return resolved;
838
+ }
839
+ return null;
840
+ }
841
+ async function findTypeScriptCompiler(cwd) {
842
+ const executableName = process.platform === "win32" ? "tsc.cmd" : "tsc";
843
+ let current = cwd;
844
+ while (true) {
845
+ const candidate = path.join(current, "node_modules", ".bin", executableName);
846
+ if (await fileExists(candidate)) return candidate;
847
+ const parent = path.dirname(current);
848
+ if (parent === current) break;
849
+ current = parent;
850
+ }
851
+ return null;
852
+ }
853
+ async function runTypeScriptCompiler(cwd, compilerPath, tsconfigPath) {
854
+ return await new Promise((resolve, reject) => {
855
+ const isWindowsCmd = process.platform === "win32" && /\.(cmd|bat)$/i.test(compilerPath);
856
+ const child = spawn(compilerPath, [
857
+ "--noEmit",
858
+ "-p",
859
+ tsconfigPath
860
+ ], {
861
+ cwd,
862
+ stdio: [
863
+ "ignore",
864
+ "pipe",
865
+ "pipe"
866
+ ],
867
+ ...isWindowsCmd ? { shell: true } : {}
868
+ });
869
+ let output = "";
870
+ child.stdout.on("data", (chunk) => {
871
+ output += chunk.toString();
872
+ });
873
+ child.stderr.on("data", (chunk) => {
874
+ output += chunk.toString();
875
+ });
876
+ child.once("error", reject);
877
+ child.once("exit", (code) => {
878
+ resolve({
879
+ ok: (code ?? 1) === 0,
880
+ output: output.trim()
881
+ });
882
+ });
883
+ });
884
+ }
885
+ function summarizeCompilerOutput(output) {
886
+ return output.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
887
+ }
888
+ function describeTypecheckStatus(result) {
889
+ return result.details ? `${result.summary} (${result.details})` : result.summary;
890
+ }
891
+ function describeDevDriftStatus(report) {
892
+ switch (report.drift.state) {
893
+ case "clean": return "clean";
894
+ case "missing-snapshot": return "snapshot refreshed";
895
+ case "snapshot-outdated": return "snapshot refreshed";
896
+ case "migration-pending": return "migration review pending";
897
+ case "destructive": return "blocked";
898
+ default: return "unavailable";
671
899
  }
672
900
  }
673
901
  async function requireHubConnection(context) {
@@ -777,8 +1005,41 @@ async function readPersistedLogs(cwd) {
777
1005
  }
778
1006
  return (await readFile(logPath, "utf8")).split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line)).filter((entry) => entry.version === 2).filter((entry) => !shouldSuppressLogEntry(entry));
779
1007
  }
1008
+ async function printRecentRuntimeSignals(context, cwd, limit = 5) {
1009
+ const recent = (await readPersistedLogs(cwd)).slice(-limit);
1010
+ if (recent.length === 0) return;
1011
+ context.info("Recent runtime signals:");
1012
+ for (const entry of recent) process.stdout.write(` ${formatPersistedLogEntry(entry)}\n`);
1013
+ }
1014
+ function startRuntimeLogTail(context, cwd) {
1015
+ let seenCount = 0;
1016
+ let disposed = false;
1017
+ const poll = async () => {
1018
+ if (disposed) return;
1019
+ const entries = await readPersistedLogs(cwd);
1020
+ const next = entries.slice(seenCount);
1021
+ for (const entry of next) process.stdout.write(`${formatPersistedLogEntry(entry)}\n`);
1022
+ seenCount = entries.length;
1023
+ };
1024
+ const interval = setInterval(() => {
1025
+ poll();
1026
+ }, 1200);
1027
+ poll();
1028
+ return () => {
1029
+ disposed = true;
1030
+ clearInterval(interval);
1031
+ };
1032
+ }
780
1033
  function normalizeRuntimeEvent(event, runtimeEntry) {
781
1034
  const functionName = typeof event.functionName === "string" ? event.functionName : "unknown";
1035
+ const functionComponent = resolveComponentInfoFromFunctionName(functionName);
1036
+ const queryComponent = typeof event.queryId === "string" ? resolveComponentInfoFromFunctionName(formatInvalidatedQueryId(event.queryId)) : void 0;
1037
+ const storageComponent = typeof event.storageId === "string" ? resolveComponentInfoFromScopedValue(event.storageId) : void 0;
1038
+ const componentInfo = typeof event.componentPath === "string" ? {
1039
+ owner: "component",
1040
+ componentPath: event.componentPath,
1041
+ ...typeof event.componentName === "string" ? { componentName: event.componentName } : {}
1042
+ } : functionComponent ?? queryComponent ?? storageComponent;
782
1043
  const logMessage = typeof event.message === "string" ? event.message : "Syncore log";
783
1044
  const resolvedTargetId = event.runtimeId === "syncore-dev-hub" ? "all" : runtimeEntry?.targetId ?? event.runtimeId;
784
1045
  const runtimeLabel = event.runtimeId === "syncore-dev-hub" ? "dashboard" : runtimeEntry?.label ?? "runtime";
@@ -798,6 +1059,7 @@ function normalizeRuntimeEvent(event, runtimeEntry) {
798
1059
  ...entryBase,
799
1060
  eventType: event.type,
800
1061
  category: "system",
1062
+ ...componentInfo ?? {},
801
1063
  message: logMessage,
802
1064
  event
803
1065
  })) return null;
@@ -806,6 +1068,7 @@ function normalizeRuntimeEvent(event, runtimeEntry) {
806
1068
  ...entryBase,
807
1069
  eventType: event.type,
808
1070
  category: "query",
1071
+ ...componentInfo ?? {},
809
1072
  message: `${functionName} executed`,
810
1073
  event
811
1074
  };
@@ -813,6 +1076,7 @@ function normalizeRuntimeEvent(event, runtimeEntry) {
813
1076
  ...entryBase,
814
1077
  eventType: event.type,
815
1078
  category: "system",
1079
+ ...componentInfo ?? {},
816
1080
  message: `${formatInvalidatedQueryId(event.queryId)} invalidated${typeof event.reason === "string" ? ` (${event.reason})` : ""}`,
817
1081
  event
818
1082
  };
@@ -820,6 +1084,7 @@ function normalizeRuntimeEvent(event, runtimeEntry) {
820
1084
  ...entryBase,
821
1085
  eventType: event.type,
822
1086
  category: "mutation",
1087
+ ...componentInfo ?? {},
823
1088
  message: Array.isArray(event.changedTables) && event.changedTables.length > 0 ? `${functionName} committed (${event.changedTables.join(", ")})` : `${functionName} committed`,
824
1089
  event
825
1090
  };
@@ -827,6 +1092,7 @@ function normalizeRuntimeEvent(event, runtimeEntry) {
827
1092
  ...entryBase,
828
1093
  eventType: event.type,
829
1094
  category: "action",
1095
+ ...componentInfo ?? {},
830
1096
  message: typeof event.error === "string" && event.error.length > 0 ? `${functionName} failed: ${event.error}` : `${functionName} completed`,
831
1097
  event
832
1098
  };
@@ -848,6 +1114,7 @@ function normalizeRuntimeEvent(event, runtimeEntry) {
848
1114
  ...entryBase,
849
1115
  eventType: event.type,
850
1116
  category: "system",
1117
+ ...componentInfo ?? {},
851
1118
  message: `${typeof event.operation === "string" ? event.operation : "update"} ${typeof event.storageId === "string" ? event.storageId : "storage"}`,
852
1119
  event
853
1120
  };
@@ -855,6 +1122,7 @@ function normalizeRuntimeEvent(event, runtimeEntry) {
855
1122
  ...entryBase,
856
1123
  eventType: event.type,
857
1124
  category: "system",
1125
+ ...componentInfo ?? {},
858
1126
  message: event.type === "log" ? logMessage : humanizeRuntimeEvent(event),
859
1127
  event
860
1128
  };
@@ -880,6 +1148,22 @@ function formatInvalidatedQueryId(queryId) {
880
1148
  if (separatorIndex === -1) return queryId;
881
1149
  return queryId.slice(0, separatorIndex);
882
1150
  }
1151
+ function resolveComponentInfoFromFunctionName(functionName) {
1152
+ const match = /^components\/(.+)\/(public|internal)\/(.+)$/.exec(functionName);
1153
+ if (!match) return;
1154
+ return {
1155
+ owner: "component",
1156
+ componentPath: match[1] ?? ""
1157
+ };
1158
+ }
1159
+ function resolveComponentInfoFromScopedValue(value) {
1160
+ const match = /^component:([^:]+):(.+)$/.exec(value);
1161
+ if (!match) return;
1162
+ return {
1163
+ owner: "component",
1164
+ componentPath: match[1] ?? ""
1165
+ };
1166
+ }
883
1167
  function humanizeRuntimeEvent(event) {
884
1168
  if (event.type === "scheduler.tick" && Array.isArray(event.executedJobIds)) return `scheduler tick (${event.executedJobIds.length} job(s))`;
885
1169
  return event.type.replaceAll(".", " ");
@@ -949,7 +1233,7 @@ function parseJsonObject(input, label) {
949
1233
  try {
950
1234
  parsed = JSON.parse(input);
951
1235
  } catch (error) {
952
- throw new Error(`${label} must be valid JSON: ${formatError(error)}`);
1236
+ throw new Error(`${label} must be valid JSON: ${formatError(error)}`, { cause: error });
953
1237
  }
954
1238
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${label} must be a JSON object.`);
955
1239
  return parsed;