syncorejs 0.2.1 → 0.2.2

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 (135) 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 +323 -42
  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/doctor.mjs +513 -46
  8. package/dist/_vendor/cli/doctor.mjs.map +1 -1
  9. package/dist/_vendor/cli/messages.mjs +5 -4
  10. package/dist/_vendor/cli/messages.mjs.map +1 -1
  11. package/dist/_vendor/cli/project.mjs +110 -12
  12. package/dist/_vendor/cli/project.mjs.map +1 -1
  13. package/dist/_vendor/cli/render.mjs +57 -9
  14. package/dist/_vendor/cli/render.mjs.map +1 -1
  15. package/dist/_vendor/cli/targets.mjs +4 -3
  16. package/dist/_vendor/cli/targets.mjs.map +1 -1
  17. package/dist/_vendor/core/cli.d.mts +13 -3
  18. package/dist/_vendor/core/cli.d.mts.map +1 -1
  19. package/dist/_vendor/core/cli.mjs +242 -91
  20. package/dist/_vendor/core/cli.mjs.map +1 -1
  21. package/dist/_vendor/core/devtools-auth.mjs +60 -0
  22. package/dist/_vendor/core/devtools-auth.mjs.map +1 -0
  23. package/dist/_vendor/core/index.d.mts +5 -3
  24. package/dist/_vendor/core/index.mjs +22 -2
  25. package/dist/_vendor/core/index.mjs.map +1 -1
  26. package/dist/_vendor/core/runtime/components.d.mts +111 -0
  27. package/dist/_vendor/core/runtime/components.d.mts.map +1 -0
  28. package/dist/_vendor/core/runtime/components.mjs +186 -0
  29. package/dist/_vendor/core/runtime/components.mjs.map +1 -0
  30. package/dist/_vendor/core/runtime/devtools.d.mts +4 -4
  31. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  32. package/dist/_vendor/core/runtime/devtools.mjs +52 -41
  33. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  34. package/dist/_vendor/core/runtime/functions.d.mts +10 -10
  35. package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
  36. package/dist/_vendor/core/runtime/functions.mjs +2 -2
  37. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  38. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +77 -0
  39. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -0
  40. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +617 -0
  41. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -0
  42. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +186 -0
  43. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -0
  44. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +220 -0
  45. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -0
  46. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +203 -0
  47. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -0
  48. package/dist/_vendor/core/runtime/internal/engines/shared.mjs +177 -0
  49. package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -0
  50. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +144 -0
  51. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -0
  52. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +220 -0
  53. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -0
  54. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs +32 -0
  55. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -0
  56. package/dist/_vendor/core/runtime/internal/systemMeta.mjs +61 -0
  57. package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -0
  58. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +37 -0
  59. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -0
  60. package/dist/_vendor/core/runtime/runtime.d.mts +159 -205
  61. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  62. package/dist/_vendor/core/runtime/runtime.mjs +16 -1371
  63. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  64. package/dist/_vendor/core/transport.d.mts +111 -0
  65. package/dist/_vendor/core/transport.d.mts.map +1 -0
  66. package/dist/_vendor/core/transport.mjs +419 -0
  67. package/dist/_vendor/core/transport.mjs.map +1 -0
  68. package/dist/_vendor/devtools-protocol/index.d.ts +39 -1
  69. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  70. package/dist/_vendor/devtools-protocol/index.js +25 -9
  71. package/dist/_vendor/devtools-protocol/index.js.map +1 -1
  72. package/dist/_vendor/next/index.d.ts +1 -1
  73. package/dist/_vendor/next/index.d.ts.map +1 -1
  74. package/dist/_vendor/next/index.js +31 -13
  75. package/dist/_vendor/next/index.js.map +1 -1
  76. package/dist/_vendor/platform-expo/index.d.ts +12 -12
  77. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  78. package/dist/_vendor/platform-expo/index.js +4 -2
  79. package/dist/_vendor/platform-expo/index.js.map +1 -1
  80. package/dist/_vendor/platform-expo/react.d.ts.map +1 -1
  81. package/dist/_vendor/platform-expo/react.js +11 -10
  82. package/dist/_vendor/platform-expo/react.js.map +1 -1
  83. package/dist/_vendor/platform-node/index.d.mts +23 -19
  84. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  85. package/dist/_vendor/platform-node/index.mjs +13 -5
  86. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  87. package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -1
  88. package/dist/_vendor/platform-node/ipc-react.mjs +15 -2
  89. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  90. package/dist/_vendor/platform-node/ipc.d.mts +11 -35
  91. package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
  92. package/dist/_vendor/platform-node/ipc.mjs +3 -273
  93. package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
  94. package/dist/_vendor/platform-web/external-change.d.ts +2 -1
  95. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
  96. package/dist/_vendor/platform-web/external-change.js +2 -1
  97. package/dist/_vendor/platform-web/external-change.js.map +1 -1
  98. package/dist/_vendor/platform-web/index.d.ts +21 -21
  99. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  100. package/dist/_vendor/platform-web/index.js +44 -7
  101. package/dist/_vendor/platform-web/index.js.map +1 -1
  102. package/dist/_vendor/platform-web/react.d.ts.map +1 -1
  103. package/dist/_vendor/platform-web/react.js +29 -13
  104. package/dist/_vendor/platform-web/react.js.map +1 -1
  105. package/dist/_vendor/platform-web/worker.d.ts +11 -35
  106. package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
  107. package/dist/_vendor/platform-web/worker.js +3 -267
  108. package/dist/_vendor/platform-web/worker.js.map +1 -1
  109. package/dist/_vendor/react/index.d.ts +36 -20
  110. package/dist/_vendor/react/index.d.ts.map +1 -1
  111. package/dist/_vendor/react/index.js +279 -57
  112. package/dist/_vendor/react/index.js.map +1 -1
  113. package/dist/_vendor/schema/definition.d.ts +48 -63
  114. package/dist/_vendor/schema/definition.d.ts.map +1 -1
  115. package/dist/_vendor/schema/definition.js +22 -39
  116. package/dist/_vendor/schema/definition.js.map +1 -1
  117. package/dist/_vendor/schema/index.d.ts +4 -4
  118. package/dist/_vendor/schema/index.js +2 -2
  119. package/dist/_vendor/schema/planner.d.ts +19 -2
  120. package/dist/_vendor/schema/planner.d.ts.map +1 -1
  121. package/dist/_vendor/schema/planner.js +79 -3
  122. package/dist/_vendor/schema/planner.js.map +1 -1
  123. package/dist/_vendor/schema/validators.d.ts +141 -121
  124. package/dist/_vendor/schema/validators.d.ts.map +1 -1
  125. package/dist/_vendor/schema/validators.js +300 -42
  126. package/dist/_vendor/schema/validators.js.map +1 -1
  127. package/dist/_vendor/svelte/index.d.ts +47 -19
  128. package/dist/_vendor/svelte/index.d.ts.map +1 -1
  129. package/dist/_vendor/svelte/index.js +250 -20
  130. package/dist/_vendor/svelte/index.js.map +1 -1
  131. package/dist/components.d.ts +2 -0
  132. package/dist/components.js +2 -0
  133. package/dist/index.d.ts +3 -2
  134. package/dist/index.js +2 -1
  135. package/package.json +8 -3
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.mjs","names":[],"sources":["../src/doctor.ts"],"sourcesContent":["import path from \"node:path\";\nimport { detectProjectTemplate, fileExists, isLocalPortInUse } from \"@syncore/core/cli\";\nimport type { ClientTargetDescriptor, SyncoreTargetDescriptor, WorkspaceProjectMatch } from \"./project.js\";\nimport {\n findWorkspaceSyncoreProjects,\n listAvailableTargets,\n resolveDashboardUrl,\n resolveDevtoolsUrl,\n resolveProjectTargetDescriptor\n} from \"./project.js\";\nimport { templateUsesConnectedClients } from \"./messages.js\";\n\nexport type DoctorStatus =\n | \"ready\"\n | \"incomplete\"\n | \"workspace-root\"\n | \"missing\"\n | \"waiting-for-client\";\n\nexport type DoctorCheckCategory = \"project\" | \"generated\" | \"schema\";\n\nexport interface DoctorCheck {\n category: DoctorCheckCategory;\n path: string;\n ok: boolean;\n}\n\nexport interface DoctorReport {\n cwd: string;\n template: string;\n status: DoctorStatus;\n checks: DoctorCheck[];\n workspaceMatches: WorkspaceProjectMatch[];\n suggestions: string[];\n projectTarget: Awaited<ReturnType<typeof resolveProjectTargetDescriptor>>;\n targets: SyncoreTargetDescriptor[];\n hub: {\n url: string;\n dashboardUrl: string;\n running: boolean;\n dashboardRunning: boolean;\n ports: {\n devtools: number;\n dashboard: number;\n };\n };\n}\n\nexport async function buildDoctorReport(cwd: string): Promise<DoctorReport> {\n const template = await detectProjectTemplate(cwd);\n const checks = [\n { category: \"project\" as const, path: \"syncore.config.ts\" },\n { category: \"schema\" as const, path: path.join(\"syncore\", \"schema.ts\") },\n { category: \"project\" as const, path: path.join(\"syncore\", \"functions\") },\n {\n category: \"generated\" as const,\n path: path.join(\"syncore\", \"_generated\", \"functions.ts\")\n },\n { category: \"schema\" as const, path: path.join(\"syncore\", \"migrations\") }\n ];\n const checkResults = await Promise.all(\n checks.map(async (entry) => ({\n category: entry.category,\n path: entry.path.replaceAll(\"\\\\\", \"/\"),\n ok: await fileExists(path.join(cwd, entry.path))\n }))\n );\n const projectTarget = await resolveProjectTargetDescriptor(cwd);\n const targets = await listAvailableTargets(cwd);\n const devtoolsUrl = resolveDevtoolsUrl();\n const dashboardUrl = resolveDashboardUrl();\n const hubPort = Number.parseInt(new URL(devtoolsUrl).port, 10);\n const dashboardPort = Number.parseInt(new URL(dashboardUrl).port, 10);\n const hub = {\n url: devtoolsUrl,\n dashboardUrl,\n running:\n Number.isFinite(hubPort) && hubPort > 0\n ? await isLocalPortInUse(hubPort)\n : false,\n dashboardRunning:\n Number.isFinite(dashboardPort) && dashboardPort > 0\n ? await isLocalPortInUse(dashboardPort)\n : false,\n ports: {\n devtools: hubPort,\n dashboard: dashboardPort\n }\n };\n\n const ready = checkResults.every((entry) => entry.ok);\n const workspaceMatches = ready ? [] : await findWorkspaceSyncoreProjects(cwd);\n const clientTargets = targets.filter(\n (target): target is ClientTargetDescriptor => target.kind === \"client\"\n );\n const status =\n ready\n ? !projectTarget && clientTargets.length === 0\n ? \"waiting-for-client\"\n : \"ready\"\n : workspaceMatches.length > 0\n ? \"workspace-root\"\n : checkResults.some((entry) => entry.ok)\n ? \"incomplete\"\n : \"missing\";\n\n const suggestions: string[] = [];\n if (status === \"workspace-root\") {\n suggestions.push(\n `Run the command with --cwd ${workspaceMatches[0]!.relativePath} or change into a package directory.`\n );\n }\n if (status === \"missing\") {\n suggestions.push(\"Run `npx syncorejs init` to scaffold a new Syncore project.\");\n }\n if (status === \"incomplete\") {\n suggestions.push(\"Run `npx syncorejs codegen` after restoring missing files.\");\n suggestions.push(\"Run `npx syncorejs migrate status` to inspect schema state.\");\n }\n if (!projectTarget && templateUsesConnectedClients(template)) {\n suggestions.push(\n \"Use `npx syncorejs dev` and a connected client target for run/data/import/export in this template.\"\n );\n }\n if (status === \"waiting-for-client\") {\n suggestions.push(\"Start your app host, then run `npx syncorejs targets` to inspect connected client targets.\");\n }\n if (!hub.running) {\n suggestions.push(\"Run `npx syncorejs dev` to start the local devtools hub.\");\n }\n\n return {\n cwd,\n template,\n status,\n checks: checkResults,\n workspaceMatches,\n suggestions,\n projectTarget,\n targets,\n hub\n };\n}\n"],"mappings":";;;;;AAgDA,eAAsB,kBAAkB,KAAoC;CAC1E,MAAM,WAAW,MAAM,sBAAsB,IAAI;CACjD,MAAM,SAAS;EACb;GAAE,UAAU;GAAoB,MAAM;GAAqB;EAC3D;GAAE,UAAU;GAAmB,MAAM,KAAK,KAAK,WAAW,YAAY;GAAE;EACxE;GAAE,UAAU;GAAoB,MAAM,KAAK,KAAK,WAAW,YAAY;GAAE;EACzE;GACE,UAAU;GACV,MAAM,KAAK,KAAK,WAAW,cAAc,eAAe;GACzD;EACD;GAAE,UAAU;GAAmB,MAAM,KAAK,KAAK,WAAW,aAAa;GAAE;EAC1E;CACD,MAAM,eAAe,MAAM,QAAQ,IACjC,OAAO,IAAI,OAAO,WAAW;EAC3B,UAAU,MAAM;EAChB,MAAM,MAAM,KAAK,WAAW,MAAM,IAAI;EACtC,IAAI,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK,CAAC;EACjD,EAAE,CACJ;CACD,MAAM,gBAAgB,MAAM,+BAA+B,IAAI;CAC/D,MAAM,UAAU,MAAM,qBAAqB,IAAI;CAC/C,MAAM,cAAc,oBAAoB;CACxC,MAAM,eAAe,qBAAqB;CAC1C,MAAM,UAAU,OAAO,SAAS,IAAI,IAAI,YAAY,CAAC,MAAM,GAAG;CAC9D,MAAM,gBAAgB,OAAO,SAAS,IAAI,IAAI,aAAa,CAAC,MAAM,GAAG;CACrE,MAAM,MAAM;EACV,KAAK;EACL;EACA,SACE,OAAO,SAAS,QAAQ,IAAI,UAAU,IAClC,MAAM,iBAAiB,QAAQ,GAC/B;EACN,kBACE,OAAO,SAAS,cAAc,IAAI,gBAAgB,IAC9C,MAAM,iBAAiB,cAAc,GACrC;EACN,OAAO;GACL,UAAU;GACV,WAAW;GACZ;EACF;CAED,MAAM,QAAQ,aAAa,OAAO,UAAU,MAAM,GAAG;CACrD,MAAM,mBAAmB,QAAQ,EAAE,GAAG,MAAM,6BAA6B,IAAI;CAC7E,MAAM,gBAAgB,QAAQ,QAC3B,WAA6C,OAAO,SAAS,SAC/D;CACD,MAAM,SACJ,QACI,CAAC,iBAAiB,cAAc,WAAW,IACzC,uBACA,UACF,iBAAiB,SAAS,IACxB,mBACA,aAAa,MAAM,UAAU,MAAM,GAAG,GACpC,eACA;CAEV,MAAM,cAAwB,EAAE;AAChC,KAAI,WAAW,iBACb,aAAY,KACV,8BAA8B,iBAAiB,GAAI,aAAa,sCACjE;AAEH,KAAI,WAAW,UACb,aAAY,KAAK,8DAA8D;AAEjF,KAAI,WAAW,cAAc;AAC3B,cAAY,KAAK,6DAA6D;AAC9E,cAAY,KAAK,8DAA8D;;AAEjF,KAAI,CAAC,iBAAiB,6BAA6B,SAAS,CAC1D,aAAY,KACV,qGACD;AAEH,KAAI,WAAW,qBACb,aAAY,KAAK,6FAA6F;AAEhH,KAAI,CAAC,IAAI,QACP,aAAY,KAAK,2DAA2D;AAG9E,QAAO;EACL;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;EACD"}
1
+ {"version":3,"file":"doctor.mjs","names":["templateUsesConnectedClients"],"sources":["../src/doctor.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n createSchemaSnapshot,\n diffSchemaSnapshots,\n type SchemaSnapshot\n} from \"@syncore/core\";\nimport {\n detectProjectTemplate,\n fileExists,\n formatError,\n hasSyncoreProject,\n isLocalPortInUse,\n loadProjectSchema,\n readStoredSnapshot,\n runCodegen,\n writeStoredSnapshot\n} from \"@syncore/core/cli\";\nimport type {\n ClientTargetDescriptor,\n SyncoreTargetDescriptor,\n WorkspaceProjectMatch\n} from \"./project.js\";\nimport {\n findWorkspaceSyncoreProjects,\n listConnectedClientTargets,\n resolveDashboardUrl,\n resolveDevtoolsUrl,\n resolveProjectTargetDescriptor\n} from \"./project.js\";\nimport { templateUsesConnectedClients } from \"./messages.js\";\n\nexport type DoctorStatus =\n | \"ready\"\n | \"workspace-root\"\n | \"missing-project\"\n | \"missing-generated\"\n | \"schema-drift\"\n | \"schema-destructive-drift\"\n | \"hub-down\"\n | \"waiting-for-client\";\n\nexport type DoctorCheckCategory = \"project\" | \"generated\" | \"schema\";\nexport type DiagnosticCategory =\n | \"project\"\n | \"generated\"\n | \"schema\"\n | \"hub\"\n | \"runtime\"\n | \"persistence\"\n | \"client\";\nexport type DiagnosticSeverity = \"info\" | \"warning\" | \"error\";\nexport type DiagnosticStatus = \"pass\" | \"warn\" | \"fail\";\n\nexport interface DoctorCheck {\n category: DoctorCheckCategory;\n path: string;\n ok: boolean;\n}\n\nexport interface JourneyDiagnostic {\n id: string;\n category: DiagnosticCategory;\n severity: DiagnosticSeverity;\n status: DiagnosticStatus;\n summary: string;\n details?: string;\n suggestedAction?: string;\n canAutoFix: boolean;\n fixCommand?: string;\n}\n\nexport interface DoctorPrimaryIssue {\n code: DoctorStatus;\n summary: string;\n details: string;\n impact: string;\n suggestedAction?: string;\n}\n\nexport interface RuntimeSignalEntry {\n timestamp: number;\n category: \"query\" | \"mutation\" | \"action\" | \"system\";\n message: string;\n targetId: string;\n runtimeLabel?: string;\n}\n\nexport interface RuntimeSignals {\n logFilePath: string;\n logFilePresent: boolean;\n logEntryCount: number;\n recent: RuntimeSignalEntry[];\n sessionState: \"present\" | \"missing\" | \"invalid\";\n sessionPath: string;\n}\n\nexport interface DriftState {\n state:\n | \"clean\"\n | \"missing-snapshot\"\n | \"snapshot-outdated\"\n | \"migration-pending\"\n | \"destructive\"\n | \"unavailable\";\n currentSchemaHash: string | null;\n storedSchemaHash: string | null;\n statements: string[];\n warnings: string[];\n destructiveChanges: string[];\n details?: string;\n}\n\nexport interface DoctorReport {\n cwd: string;\n template: string;\n status: DoctorStatus;\n primaryIssue: DoctorPrimaryIssue;\n diagnostics: JourneyDiagnostic[];\n autoFixesAvailable: boolean;\n drift: DriftState;\n runtimeSignals: RuntimeSignals;\n checks: DoctorCheck[];\n workspaceMatches: WorkspaceProjectMatch[];\n suggestions: string[];\n projectTarget: Awaited<ReturnType<typeof resolveProjectTargetDescriptor>>;\n targets: SyncoreTargetDescriptor[];\n hub: {\n url: string;\n dashboardUrl: string;\n running: boolean;\n dashboardRunning: boolean;\n ports: {\n devtools: number;\n dashboard: number;\n };\n };\n}\n\ninterface SessionInspection {\n state: RuntimeSignals[\"sessionState\"];\n path: string;\n}\n\ninterface LoadedSchemaDrift {\n currentSnapshot: SchemaSnapshot | null;\n storedSnapshot: SchemaSnapshot | null;\n drift: DriftState;\n}\n\ninterface PersistedLogEntryLike {\n version?: number;\n timestamp: number;\n category: \"query\" | \"mutation\" | \"action\" | \"system\";\n message: string;\n targetId?: string;\n runtimeLabel?: string;\n}\n\nconst STRUCTURE_CHECKS = [\n { category: \"project\" as const, path: \"syncore.config.ts\" },\n { category: \"schema\" as const, path: path.join(\"syncore\", \"schema.ts\") },\n {\n category: \"project\" as const,\n path: path.join(\"syncore\", \"components.ts\"),\n optional: true\n },\n { category: \"project\" as const, path: path.join(\"syncore\", \"functions\") },\n {\n category: \"generated\" as const,\n path: path.join(\"syncore\", \"_generated\", \"api.ts\")\n },\n {\n category: \"generated\" as const,\n path: path.join(\"syncore\", \"_generated\", \"components.ts\")\n },\n {\n category: \"generated\" as const,\n path: path.join(\"syncore\", \"_generated\", \"schema.ts\")\n },\n {\n category: \"generated\" as const,\n path: path.join(\"syncore\", \"_generated\", \"functions.ts\")\n },\n {\n category: \"generated\" as const,\n path: path.join(\"syncore\", \"_generated\", \"server.ts\")\n },\n { category: \"schema\" as const, path: path.join(\"syncore\", \"migrations\") }\n] as const;\n\nexport async function buildDoctorReport(cwd: string): Promise<DoctorReport> {\n const template = await detectProjectTemplate(cwd);\n const checks = await Promise.all(\n STRUCTURE_CHECKS.map(async (entry) => ({\n category: entry.category,\n path: entry.path.replaceAll(\"\\\\\", \"/\"),\n ok:\n (await fileExists(path.join(cwd, entry.path))) ||\n (\"optional\" in entry && entry.optional === true)\n }))\n );\n const hasProject = await hasSyncoreProject(cwd);\n\n let projectTarget: Awaited<ReturnType<typeof resolveProjectTargetDescriptor>> = null;\n let persistenceDetails: string | undefined;\n try {\n projectTarget = await resolveProjectTargetDescriptor(cwd);\n if (projectTarget) {\n persistenceDetails = `Database path: ${projectTarget.databasePath}. Storage directory: ${projectTarget.storageDirectory}.`;\n }\n } catch (error) {\n persistenceDetails = formatError(error);\n }\n const usesConnectedClients =\n templateUsesConnectedClients(template) ||\n (!projectTarget && template !== \"node\");\n\n const clientTargets = await listConnectedClientTargets();\n const targets: SyncoreTargetDescriptor[] = [\n ...(projectTarget ? [projectTarget] : []),\n ...clientTargets\n ];\n\n const devtoolsUrl = resolveDevtoolsUrl();\n const dashboardUrl = resolveDashboardUrl();\n const hubPort = Number.parseInt(new URL(devtoolsUrl).port, 10);\n const dashboardPort = Number.parseInt(new URL(dashboardUrl).port, 10);\n const hub = {\n url: devtoolsUrl,\n dashboardUrl,\n running:\n Number.isFinite(hubPort) && hubPort > 0\n ? await isLocalPortInUse(hubPort)\n : false,\n dashboardRunning:\n Number.isFinite(dashboardPort) && dashboardPort > 0\n ? await isLocalPortInUse(dashboardPort)\n : false,\n ports: {\n devtools: hubPort,\n dashboard: dashboardPort\n }\n };\n\n const workspaceMatches = hasProject ? [] : await findWorkspaceSyncoreProjects(cwd);\n const runtimeSignals = await inspectRuntimeSignals(cwd);\n const loadedDrift = await loadSchemaDrift(cwd, checks);\n const drift = loadedDrift?.drift ?? {\n state: \"unavailable\",\n currentSchemaHash: null,\n storedSchemaHash: null,\n statements: [],\n warnings: [],\n destructiveChanges: [],\n details: \"Syncore could not inspect schema drift yet.\"\n };\n\n const diagnostics = buildDiagnostics({\n checks,\n drift,\n hasProject,\n hub,\n projectTarget,\n runtimeSignals,\n template,\n usesConnectedClients,\n clientTargets,\n ...(persistenceDetails ? { persistenceDetails } : {})\n });\n\n const primaryIssue = resolvePrimaryIssue({\n checks,\n diagnostics,\n drift,\n hasProject,\n hubRunning: hub.running,\n usesConnectedClients,\n clientTargets,\n workspaceMatches\n });\n\n const suggestions = collectSuggestions(primaryIssue, diagnostics, workspaceMatches);\n\n return {\n cwd,\n template,\n status: primaryIssue.code,\n primaryIssue,\n diagnostics,\n autoFixesAvailable: diagnostics.some(\n (diagnostic) => diagnostic.canAutoFix && diagnostic.status !== \"pass\"\n ),\n drift,\n runtimeSignals,\n checks,\n workspaceMatches,\n suggestions,\n projectTarget,\n targets,\n hub\n };\n}\n\nexport async function applyDoctorFixes(\n cwd: string,\n report?: DoctorReport\n): Promise<string[]> {\n const appliedFixes: string[] = [];\n const currentReport = report ?? (await buildDoctorReport(cwd));\n const missingGenerated = currentReport.checks.some(\n (check) => check.category === \"generated\" && !check.ok\n );\n\n if (missingGenerated) {\n await runCodegen(cwd);\n appliedFixes.push(\"Regenerated syncore/_generated/*.\");\n }\n\n const refreshedReport =\n missingGenerated || !report ? await buildDoctorReport(cwd) : currentReport;\n if (\n refreshedReport.drift.state === \"missing-snapshot\" ||\n refreshedReport.drift.state === \"snapshot-outdated\" ||\n refreshedReport.drift.state === \"migration-pending\"\n ) {\n const generatedSchemaPath = path.join(cwd, \"syncore\", \"_generated\", \"schema.ts\");\n if (await fileExists(generatedSchemaPath)) {\n const schema = await loadProjectSchema(cwd);\n const snapshot = createSchemaSnapshot(schema);\n await writeStoredSnapshot(cwd, snapshot);\n appliedFixes.push(\"Refreshed the stored schema snapshot.\");\n }\n }\n\n return appliedFixes;\n}\n\nasync function inspectRuntimeSignals(cwd: string): Promise<RuntimeSignals> {\n const session = await inspectDevtoolsSession(cwd);\n const logFilePath = path.join(cwd, \".syncore\", \"logs\", \"runtime.jsonl\");\n if (!(await fileExists(logFilePath))) {\n return {\n logFilePath,\n logFilePresent: false,\n logEntryCount: 0,\n recent: [],\n sessionState: session.state,\n sessionPath: session.path\n };\n }\n\n try {\n const source = await readFile(logFilePath, \"utf8\");\n const entries = source\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => JSON.parse(line) as PersistedLogEntryLike)\n .filter((entry) => entry.version === 2);\n\n return {\n logFilePath,\n logFilePresent: true,\n logEntryCount: entries.length,\n recent: entries.slice(-5).map((entry) => ({\n timestamp: entry.timestamp,\n category: entry.category,\n message: entry.message,\n targetId: entry.targetId ?? \"unknown\",\n ...(entry.runtimeLabel ? { runtimeLabel: entry.runtimeLabel } : {})\n })),\n sessionState: session.state,\n sessionPath: session.path\n };\n } catch (error) {\n return {\n logFilePath,\n logFilePresent: true,\n logEntryCount: 0,\n recent: [\n {\n timestamp: Date.now(),\n category: \"system\",\n message: `Unable to read runtime log history: ${formatError(error)}`,\n targetId: \"system\"\n }\n ],\n sessionState: session.state,\n sessionPath: session.path\n };\n }\n}\n\nasync function inspectDevtoolsSession(cwd: string): Promise<SessionInspection> {\n const sessionPath = path.join(cwd, \".syncore\", \"devtools-session.json\");\n if (!(await fileExists(sessionPath))) {\n return { state: \"missing\", path: sessionPath };\n }\n\n try {\n const source = await readFile(sessionPath, \"utf8\");\n const parsed = JSON.parse(source) as Partial<{\n dashboardUrl: string;\n authenticatedDashboardUrl: string;\n devtoolsUrl: string;\n token: string;\n }>;\n const valid =\n typeof parsed.dashboardUrl === \"string\" &&\n typeof parsed.authenticatedDashboardUrl === \"string\" &&\n typeof parsed.devtoolsUrl === \"string\" &&\n typeof parsed.token === \"string\";\n return {\n state: valid ? \"present\" : \"invalid\",\n path: sessionPath\n };\n } catch {\n return { state: \"invalid\", path: sessionPath };\n }\n}\n\nasync function loadSchemaDrift(\n cwd: string,\n checks: DoctorCheck[]\n): Promise<LoadedSchemaDrift | null> {\n const generatedSchemaPresent = checks.some(\n (check) => check.path === \"syncore/_generated/schema.ts\" && check.ok\n );\n if (!generatedSchemaPresent) {\n return null;\n }\n\n try {\n const schema = await loadProjectSchema(cwd);\n const currentSnapshot = createSchemaSnapshot(schema);\n const storedSnapshot = await readStoredSnapshot(cwd);\n const plan = diffSchemaSnapshots(storedSnapshot, currentSnapshot);\n const state =\n plan.destructiveChanges.length > 0\n ? \"destructive\"\n : !storedSnapshot\n ? \"missing-snapshot\"\n : storedSnapshot.hash !== currentSnapshot.hash && plan.statements.length > 0\n ? \"migration-pending\"\n : storedSnapshot.hash !== currentSnapshot.hash\n ? \"snapshot-outdated\"\n : \"clean\";\n return {\n currentSnapshot,\n storedSnapshot,\n drift: {\n state,\n currentSchemaHash: currentSnapshot.hash,\n storedSchemaHash: storedSnapshot?.hash ?? null,\n statements: plan.statements,\n warnings: plan.warnings,\n destructiveChanges: plan.destructiveChanges,\n details:\n state === \"clean\"\n ? \"Local schema snapshot matches the generated Syncore schema.\"\n : describeDriftState(state, plan.statements.length, plan.warnings.length)\n }\n };\n } catch (error) {\n return {\n currentSnapshot: null,\n storedSnapshot: null,\n drift: {\n state: \"unavailable\",\n currentSchemaHash: null,\n storedSchemaHash: null,\n statements: [],\n warnings: [],\n destructiveChanges: [],\n details: `Syncore could not load the generated schema: ${formatError(error)}`\n }\n };\n }\n}\n\nfunction describeDriftState(\n state: DriftState[\"state\"],\n statementCount: number,\n warningCount: number\n): string {\n if (state === \"missing-snapshot\") {\n return \"No stored schema snapshot was found yet.\";\n }\n if (state === \"migration-pending\") {\n return `Schema drift detected with ${statementCount} SQL statement(s) pending and ${warningCount} warning(s).`;\n }\n if (state === \"snapshot-outdated\") {\n return \"The stored schema snapshot differs from the generated schema, but no SQL statements are pending.\";\n }\n if (state === \"destructive\") {\n return \"The current schema diff includes destructive changes that require manual review.\";\n }\n return \"Syncore could not inspect schema drift.\";\n}\n\nfunction buildDiagnostics(input: {\n checks: DoctorCheck[];\n drift: DriftState;\n hasProject: boolean;\n hub: DoctorReport[\"hub\"];\n persistenceDetails?: string;\n projectTarget: DoctorReport[\"projectTarget\"];\n runtimeSignals: RuntimeSignals;\n template: string;\n usesConnectedClients: boolean;\n clientTargets: ClientTargetDescriptor[];\n}): JourneyDiagnostic[] {\n const diagnostics: JourneyDiagnostic[] = [];\n const missingProjectPaths = input.checks.filter(\n (check) => (check.category === \"project\" || check.category === \"schema\") && !check.ok\n );\n diagnostics.push(\n missingProjectPaths.length === 0 && input.hasProject\n ? {\n id: \"project.structure\",\n category: \"project\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Syncore project structure is present.\",\n details: \"Core project files are available in this directory.\",\n canAutoFix: false\n }\n : {\n id: \"project.structure\",\n category: \"project\",\n severity: \"error\",\n status: \"fail\",\n summary: \"Syncore project structure is incomplete or missing.\",\n details:\n missingProjectPaths.length > 0\n ? `Missing: ${missingProjectPaths.map((check) => check.path).join(\", \")}.`\n : \"This directory does not contain a full Syncore project yet.\",\n suggestedAction: \"Run `npx syncorejs init` or restore the missing project files.\",\n canAutoFix: false\n }\n );\n\n const missingGenerated = input.checks.filter(\n (check) => check.category === \"generated\" && !check.ok\n );\n diagnostics.push(\n missingGenerated.length === 0\n ? {\n id: \"generated.files\",\n category: \"generated\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Generated Syncore files are present.\",\n details: \"syncore/_generated looks available for runtime and type-driven tooling.\",\n canAutoFix: false\n }\n : {\n id: \"generated.files\",\n category: \"generated\",\n severity: \"error\",\n status: \"fail\",\n summary: \"Generated Syncore files are missing.\",\n details: `Missing: ${missingGenerated.map((check) => check.path).join(\", \")}.`,\n suggestedAction: \"Run `npx syncorejs codegen` or `npx syncorejs doctor --fix`.\",\n canAutoFix: true,\n fixCommand: \"npx syncorejs doctor --fix\"\n }\n );\n\n diagnostics.push(buildSchemaDiagnostic(input.drift));\n\n diagnostics.push(\n input.projectTarget\n ? {\n id: \"persistence.project-target\",\n category: \"persistence\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Project target persistence is configured.\",\n ...(input.persistenceDetails ? { details: input.persistenceDetails } : {}),\n canAutoFix: false\n }\n : input.usesConnectedClients\n ? {\n id: \"persistence.project-target\",\n category: \"persistence\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Persistence is client-managed for this template.\",\n details:\n \"This app template expects a connected client runtime to provide local storage and runtime state.\",\n canAutoFix: false\n }\n : {\n id: \"persistence.project-target\",\n category: \"persistence\",\n severity: \"error\",\n status: \"fail\",\n summary: \"No local project target is configured.\",\n details:\n input.persistenceDetails ??\n \"Syncore could not resolve a project target database and storage directory.\",\n suggestedAction:\n \"Check syncore.config.ts and make sure projectTarget.databasePath and projectTarget.storageDirectory are valid.\",\n canAutoFix: false\n }\n );\n\n diagnostics.push(\n input.hub.running\n ? {\n id: \"hub.devtools\",\n category: \"hub\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Local devtools hub is running.\",\n details: `Devtools: ${input.hub.url}. Dashboard: ${input.hub.dashboardUrl}.`,\n canAutoFix: false\n }\n : {\n id: \"hub.devtools\",\n category: \"hub\",\n severity: \"warning\",\n status: \"warn\",\n summary: \"Local devtools hub is not running.\",\n details: `Expected devtools endpoint: ${input.hub.url}.`,\n suggestedAction: \"Run `npx syncorejs dev` to start the local hub and dashboard.\",\n canAutoFix: false\n }\n );\n\n diagnostics.push(\n input.hub.dashboardRunning\n ? {\n id: \"hub.dashboard\",\n category: \"hub\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Dashboard shell is responding.\",\n details: input.hub.dashboardUrl,\n canAutoFix: false\n }\n : {\n id: \"hub.dashboard\",\n category: \"hub\",\n severity: \"warning\",\n status: \"warn\",\n summary: \"Dashboard shell is not responding yet.\",\n details: `Expected dashboard URL: ${input.hub.dashboardUrl}.`,\n suggestedAction: \"Run `npx syncorejs dev` or inspect whether the dashboard port is already taken.\",\n canAutoFix: false\n }\n );\n\n diagnostics.push(\n input.usesConnectedClients\n ? input.clientTargets.length > 0\n ? {\n id: \"client.runtime\",\n category: \"client\",\n severity: \"info\",\n status: \"pass\",\n summary: \"At least one client runtime is connected.\",\n details: `Connected targets: ${input.clientTargets.map((target) => target.id).join(\", \")}.`,\n canAutoFix: false\n }\n : {\n id: \"client.runtime\",\n category: \"client\",\n severity: \"warning\",\n status: \"warn\",\n summary: \"This template is waiting for a connected client runtime.\",\n details:\n \"Syncore is ready to inspect or operate on your app once a browser tab, worker, Electron shell, or Expo runtime connects.\",\n suggestedAction:\n \"Start your app host, then run `npx syncorejs targets` to inspect connected client targets.\",\n canAutoFix: false\n }\n : {\n id: \"client.runtime\",\n category: \"client\",\n severity: \"info\",\n status: \"pass\",\n summary: \"This template does not require a connected client runtime.\",\n canAutoFix: false\n }\n );\n\n diagnostics.push(buildRuntimeDiagnostic(input.runtimeSignals));\n\n return diagnostics;\n}\n\nfunction buildSchemaDiagnostic(drift: DriftState): JourneyDiagnostic {\n if (drift.state === \"clean\") {\n return {\n id: \"schema.drift\",\n category: \"schema\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Schema snapshot is in sync.\",\n ...(drift.details ? { details: drift.details } : {}),\n canAutoFix: false\n };\n }\n if (drift.state === \"destructive\") {\n return {\n id: \"schema.drift\",\n category: \"schema\",\n severity: \"error\",\n status: \"fail\",\n summary: \"Schema drift includes destructive changes.\",\n details: drift.destructiveChanges.join(\"; \"),\n suggestedAction:\n \"Review the schema change manually and create or edit a migration before continuing.\",\n canAutoFix: false\n };\n }\n if (drift.state === \"missing-snapshot\") {\n return {\n id: \"schema.drift\",\n category: \"schema\",\n severity: \"warning\",\n status: \"warn\",\n summary: \"No stored schema snapshot was found.\",\n ...(drift.details ? { details: drift.details } : {}),\n suggestedAction:\n \"Run `npx syncorejs doctor --fix` to refresh the snapshot, or generate a migration if you intend to persist the change.\",\n canAutoFix: true,\n fixCommand: \"npx syncorejs doctor --fix\"\n };\n }\n if (drift.state === \"snapshot-outdated\" || drift.state === \"migration-pending\") {\n return {\n id: \"schema.drift\",\n category: \"schema\",\n severity: \"warning\",\n status: \"warn\",\n summary:\n drift.state === \"migration-pending\"\n ? \"Schema drift has pending migration statements.\"\n : \"Stored schema snapshot differs from the generated schema.\",\n ...(drift.details ? { details: drift.details } : {}),\n suggestedAction:\n drift.state === \"migration-pending\"\n ? \"Run `npx syncorejs migrate status` to inspect the diff, then `npx syncorejs doctor --fix` only if you just want to refresh the stored snapshot.\"\n : \"Run `npx syncorejs doctor --fix` to refresh the stored snapshot safely.\",\n canAutoFix: true,\n fixCommand: \"npx syncorejs doctor --fix\"\n };\n }\n return {\n id: \"schema.drift\",\n category: \"schema\",\n severity: \"warning\",\n status: \"warn\",\n summary: \"Schema drift could not be inspected yet.\",\n ...(drift.details ? { details: drift.details } : {}),\n suggestedAction:\n \"Restore generated files or rerun `npx syncorejs codegen`, then run `npx syncorejs doctor` again.\",\n canAutoFix: false\n };\n}\n\nfunction buildRuntimeDiagnostic(runtimeSignals: RuntimeSignals): JourneyDiagnostic {\n if (runtimeSignals.sessionState === \"invalid\") {\n return {\n id: \"runtime.session\",\n category: \"runtime\",\n severity: \"warning\",\n status: \"warn\",\n summary: \"The saved devtools session file is invalid.\",\n details: runtimeSignals.sessionPath,\n suggestedAction:\n \"Restart `npx syncorejs dev` to regenerate the session state for the local hub.\",\n canAutoFix: false\n };\n }\n if (runtimeSignals.logEntryCount === 0) {\n return {\n id: \"runtime.signals\",\n category: \"runtime\",\n severity: \"info\",\n status: \"pass\",\n summary: \"No recent runtime signals were recorded yet.\",\n details: runtimeSignals.logFilePresent\n ? \"The runtime log file exists but has no recorded entries yet.\"\n : \"No runtime log file has been created yet.\",\n canAutoFix: false\n };\n }\n const latest = runtimeSignals.recent[runtimeSignals.recent.length - 1];\n return {\n id: \"runtime.signals\",\n category: \"runtime\",\n severity: \"info\",\n status: \"pass\",\n summary: \"Recent runtime signals are available.\",\n ...(latest\n ? {\n details: `Latest: ${latest.category} on ${latest.targetId} at ${new Date(latest.timestamp).toISOString()}: ${latest.message}`\n }\n : {}),\n canAutoFix: false\n };\n}\n\nfunction resolvePrimaryIssue(input: {\n checks: DoctorCheck[];\n diagnostics: JourneyDiagnostic[];\n drift: DriftState;\n hasProject: boolean;\n hubRunning: boolean;\n usesConnectedClients: boolean;\n clientTargets: ClientTargetDescriptor[];\n workspaceMatches: WorkspaceProjectMatch[];\n}): DoctorPrimaryIssue {\n if (!input.hasProject && input.workspaceMatches.length > 0) {\n return {\n code: \"workspace-root\",\n summary: \"You are at a workspace root, not inside a Syncore app package.\",\n details: `Found ${input.workspaceMatches.length} Syncore package(s) under this workspace.`,\n impact: \"Project-specific diagnostics and runtime operations are ambiguous from the workspace root.\",\n suggestedAction: `Run the command with --cwd ${input.workspaceMatches[0]!.relativePath} or change into that package directory.`\n };\n }\n\n const missingProjectPaths = input.checks.filter(\n (check) => (check.category === \"project\" || check.category === \"schema\") && !check.ok\n );\n if (!input.hasProject || missingProjectPaths.length > 0) {\n return {\n code: \"missing-project\",\n summary: \"Syncore project files are missing or incomplete.\",\n details:\n missingProjectPaths.length > 0\n ? `Missing: ${missingProjectPaths.map((check) => check.path).join(\", \")}.`\n : \"This directory does not contain a complete Syncore project yet.\",\n impact: \"The CLI cannot bootstrap the local runtime or inspect schema and persistence reliably.\",\n suggestedAction: \"Run `npx syncorejs init` or restore the missing project files.\"\n };\n }\n\n const missingGenerated = input.checks.filter(\n (check) => check.category === \"generated\" && !check.ok\n );\n if (missingGenerated.length > 0) {\n return {\n code: \"missing-generated\",\n summary: \"Generated Syncore files are missing.\",\n details: `Missing: ${missingGenerated.map((check) => check.path).join(\", \")}.`,\n impact: \"Type-driven runtime loading and schema inspection may be stale or unavailable.\",\n suggestedAction: \"Run `npx syncorejs doctor --fix` or `npx syncorejs codegen`.\"\n };\n }\n\n if (input.drift.state === \"destructive\") {\n return {\n code: \"schema-destructive-drift\",\n summary: \"Schema drift is blocked by destructive changes.\",\n details: input.drift.destructiveChanges.join(\"; \"),\n impact: \"Syncore cannot safely advance the local schema automatically.\",\n suggestedAction: \"Review the schema change manually and generate a migration before continuing.\"\n };\n }\n\n if (input.usesConnectedClients && input.clientTargets.length === 0) {\n return {\n code: \"waiting-for-client\",\n summary: \"This app is waiting for a connected local runtime.\",\n details:\n input.hubRunning\n ? \"Client-managed templates only become fully operational after the app host connects to the local Syncore hub.\"\n : \"This template depends on a client-managed runtime, and no app runtime is connected yet.\",\n impact: \"Worker, bridge IPC, storage, and client-side data inspection stay unavailable until a runtime connects.\",\n suggestedAction:\n input.hubRunning\n ? \"Start your app host, then run `npx syncorejs targets` to inspect connected runtimes.\"\n : \"Run `npx syncorejs dev`, start your app host, then run `npx syncorejs targets` to inspect connected runtimes.\"\n };\n }\n\n if (\n input.drift.state === \"missing-snapshot\" ||\n input.drift.state === \"snapshot-outdated\" ||\n input.drift.state === \"migration-pending\"\n ) {\n return {\n code: \"schema-drift\",\n summary: \"The local schema snapshot is out of sync.\",\n details: input.drift.details ?? \"Schema drift was detected.\",\n impact: \"The local dev loop can become confusing because the stored snapshot no longer matches the generated schema.\",\n suggestedAction:\n input.drift.state === \"migration-pending\"\n ? \"Run `npx syncorejs migrate status` to inspect the diff, then use `npx syncorejs doctor --fix` if you only need to refresh the stored snapshot.\"\n : \"Run `npx syncorejs doctor --fix` to refresh the stored snapshot safely.\"\n };\n }\n\n if (!input.hubRunning) {\n return {\n code: \"hub-down\",\n summary: \"The local devtools hub is not running.\",\n details: \"Syncore can inspect project state, but runtime and client diagnostics are limited until the hub starts.\",\n impact: \"Commands that depend on live targets, logs, or IPC visibility will have reduced signal.\",\n suggestedAction: \"Run `npx syncorejs dev` to start the local hub.\"\n };\n }\n\n return {\n code: \"ready\",\n summary: \"Syncore is ready for the local development loop.\",\n details: \"Project structure, generated files, schema state, and runtime prerequisites look healthy.\",\n impact: \"You can use `syncorejs dev`, inspect targets, and operate on the local runtime.\",\n suggestedAction: \"Run `npx syncorejs dev` to keep codegen, schema, and the local hub in sync.\"\n };\n}\n\nfunction collectSuggestions(\n primaryIssue: DoctorPrimaryIssue,\n diagnostics: JourneyDiagnostic[],\n workspaceMatches: WorkspaceProjectMatch[]\n): string[] {\n const suggestions = new Set<string>();\n if (primaryIssue.suggestedAction) {\n suggestions.add(primaryIssue.suggestedAction);\n }\n if (primaryIssue.code === \"workspace-root\" && workspaceMatches.length > 0) {\n suggestions.add(\n `Run the command with --cwd ${workspaceMatches[0]!.relativePath} or change into a package directory.`\n );\n }\n for (const diagnostic of diagnostics) {\n if (diagnostic.status === \"pass\") {\n continue;\n }\n if (diagnostic.suggestedAction) {\n suggestions.add(diagnostic.suggestedAction);\n }\n }\n return [...suggestions];\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
+ import { templateUsesConnectedClients } from "../core/cli.mjs";
1
2
  //#region src/messages.ts
2
3
  function buildInitNextSteps(template) {
3
- if (templateUsesConnectedClients(template)) return ["Run `npx syncorejs dev` to start the hub and keep generated code in sync.", "After your app connects, run `npx syncorejs targets` to inspect connected client targets."];
4
+ if (templateUsesConnectedClients$1(template)) return ["Run `npx syncorejs dev` to start the hub and keep generated code in sync.", "After your app connects, run `npx syncorejs targets` to inspect connected client targets."];
4
5
  return ["Run `npx syncorejs dev` to start the local loop.", "Operational commands default to `project` when it is the only target."];
5
6
  }
6
7
  function buildDevBootstrapNextSteps() {
@@ -23,10 +24,10 @@ function buildHubUnavailableNextSteps() {
23
24
  function buildNoTargetsNextSteps() {
24
25
  return ["Run `npx syncorejs dev` to start the local hub.", "Then run `npx syncorejs targets` to inspect the available targets."];
25
26
  }
26
- function templateUsesConnectedClients(template) {
27
- return template === "react-web" || template === "expo" || template === "next";
27
+ function templateUsesConnectedClients$1(template) {
28
+ return templateUsesConnectedClients(template);
28
29
  }
29
30
  //#endregion
30
- export { buildDevBootstrapNextSteps, buildHubUnavailableNextSteps, buildInitNextSteps, buildNoTargetsNextSteps, buildSelectTargetNextSteps, buildTargetCommandNextSteps, templateUsesConnectedClients };
31
+ export { buildDevBootstrapNextSteps, buildHubUnavailableNextSteps, buildInitNextSteps, buildNoTargetsNextSteps, buildSelectTargetNextSteps, buildTargetCommandNextSteps, templateUsesConnectedClients$1 as templateUsesConnectedClients };
31
32
 
32
33
  //# sourceMappingURL=messages.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.mjs","names":[],"sources":["../src/messages.ts"],"sourcesContent":["import type { SyncoreTemplateName } from \"@syncore/core/cli\";\n\nexport function buildInitNextSteps(template: SyncoreTemplateName): string[] {\n if (templateUsesConnectedClients(template)) {\n return [\n \"Run `npx syncorejs dev` to start the hub and keep generated code in sync.\",\n \"After your app connects, run `npx syncorejs targets` to inspect connected client targets.\"\n ];\n }\n\n return [\n \"Run `npx syncorejs dev` to start the local loop.\",\n \"Operational commands default to `project` when it is the only target.\"\n ];\n}\n\nexport function buildDevBootstrapNextSteps(): string[] {\n return [\n \"Run `npx syncorejs dashboard --open` to inspect the dashboard.\",\n \"Run `npx syncorejs targets` to inspect available targets.\",\n \"Run `npx syncorejs doctor` to inspect project health.\"\n ];\n}\n\nexport function buildTargetCommandNextSteps(targetId?: string): string[] {\n if (targetId) {\n return [`Use \\`npx syncorejs run --target ${targetId} <function>\\` to operate on a specific target.`];\n }\n return [\n \"Run `npx syncorejs dev` and connect an app runtime, or define a projectTarget for Node/Electron projects.\"\n ];\n}\n\nexport function buildSelectTargetNextSteps(): string[] {\n return [\n \"Run `npx syncorejs targets` to inspect the available targets.\",\n \"Rerun the command with `--target <id>` to choose one explicitly.\"\n ];\n}\n\nexport function buildHubUnavailableNextSteps(): string[] {\n return [\n \"Run `npx syncorejs dev` to start the local devtools hub.\",\n \"Then rerun `npx syncorejs targets` to confirm the available targets.\"\n ];\n}\n\nexport function buildNoTargetsNextSteps(): string[] {\n return [\n \"Run `npx syncorejs dev` to start the local hub.\",\n \"Then run `npx syncorejs targets` to inspect the available targets.\"\n ];\n}\n\nexport function templateUsesConnectedClients(template: string): boolean {\n return template === \"react-web\" || template === \"expo\" || template === \"next\";\n}\n"],"mappings":";AAEA,SAAgB,mBAAmB,UAAyC;AAC1E,KAAI,6BAA6B,SAAS,CACxC,QAAO,CACL,6EACA,4FACD;AAGH,QAAO,CACL,oDACA,wEACD;;AAGH,SAAgB,6BAAuC;AACrD,QAAO;EACL;EACA;EACA;EACD;;AAGH,SAAgB,4BAA4B,UAA6B;AACvE,KAAI,SACF,QAAO,CAAC,oCAAoC,SAAS,gDAAgD;AAEvG,QAAO,CACL,4GACD;;AAGH,SAAgB,6BAAuC;AACrD,QAAO,CACL,iEACA,mEACD;;AAGH,SAAgB,+BAAyC;AACvD,QAAO,CACL,4DACA,uEACD;;AAGH,SAAgB,0BAAoC;AAClD,QAAO,CACL,mDACA,qEACD;;AAGH,SAAgB,6BAA6B,UAA2B;AACtE,QAAO,aAAa,eAAe,aAAa,UAAU,aAAa"}
1
+ {"version":3,"file":"messages.mjs","names":["templateUsesConnectedClients","coreTemplateUsesConnectedClients"],"sources":["../src/messages.ts"],"sourcesContent":["import {\n type SyncoreTemplateName,\n templateUsesConnectedClients as coreTemplateUsesConnectedClients\n} from \"@syncore/core/cli\";\n\nexport function buildInitNextSteps(template: SyncoreTemplateName): string[] {\n if (templateUsesConnectedClients(template)) {\n return [\n \"Run `npx syncorejs dev` to start the hub and keep generated code in sync.\",\n \"After your app connects, run `npx syncorejs targets` to inspect connected client targets.\"\n ];\n }\n\n return [\n \"Run `npx syncorejs dev` to start the local loop.\",\n \"Operational commands default to `project` when it is the only target.\"\n ];\n}\n\nexport function buildDevBootstrapNextSteps(): string[] {\n return [\n \"Run `npx syncorejs dashboard --open` to inspect the dashboard.\",\n \"Run `npx syncorejs targets` to inspect available targets.\",\n \"Run `npx syncorejs doctor` to inspect project health.\"\n ];\n}\n\nexport function buildTargetCommandNextSteps(targetId?: string): string[] {\n if (targetId) {\n return [`Use \\`npx syncorejs run --target ${targetId} <function>\\` to operate on a specific target.`];\n }\n return [\n \"Run `npx syncorejs dev` and connect an app runtime, or define a projectTarget for Node/Electron projects.\"\n ];\n}\n\nexport function buildSelectTargetNextSteps(): string[] {\n return [\n \"Run `npx syncorejs targets` to inspect the available targets.\",\n \"Rerun the command with `--target <id>` to choose one explicitly.\"\n ];\n}\n\nexport function buildHubUnavailableNextSteps(): string[] {\n return [\n \"Run `npx syncorejs dev` to start the local devtools hub.\",\n \"Then rerun `npx syncorejs targets` to confirm the available targets.\"\n ];\n}\n\nexport function buildNoTargetsNextSteps(): string[] {\n return [\n \"Run `npx syncorejs dev` to start the local hub.\",\n \"Then run `npx syncorejs targets` to inspect the available targets.\"\n ];\n}\n\nexport function templateUsesConnectedClients(template: string): boolean {\n return coreTemplateUsesConnectedClients(template as SyncoreTemplateName);\n}\n"],"mappings":";;AAKA,SAAgB,mBAAmB,UAAyC;AAC1E,KAAIA,+BAA6B,SAAS,CACxC,QAAO,CACL,6EACA,4FACD;AAGH,QAAO,CACL,oDACA,wEACD;;AAGH,SAAgB,6BAAuC;AACrD,QAAO;EACL;EACA;EACA;EACD;;AAGH,SAAgB,4BAA4B,UAA6B;AACvE,KAAI,SACF,QAAO,CAAC,oCAAoC,SAAS,gDAAgD;AAEvG,QAAO,CACL,4GACD;;AAGH,SAAgB,6BAAuC;AACrD,QAAO,CACL,iEACA,mEACD;;AAGH,SAAgB,+BAAyC;AACvD,QAAO,CACL,4DACA,uEACD;;AAGH,SAAgB,0BAAoC;AAClD,QAAO,CACL,mDACA,qEACD;;AAGH,SAAgBA,+BAA6B,UAA2B;AACtE,QAAOC,6BAAiC,SAAgC"}
@@ -1,6 +1,6 @@
1
1
  import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { VALID_SYNCORE_TEMPLATES, detectProjectTemplate, fileExists, importJsonlIntoProject, isLocalPortInUse, loadProjectConfig, loadProjectFunctions, loadProjectSchema, resolvePortFromEnv, resolveProjectTargetConfig, runCodegen } from "../core/cli.mjs";
3
+ import { VALID_SYNCORE_TEMPLATES, detectProjectTemplate, fileExists, importJsonlIntoProject, isLocalPortInUse, loadProjectConfig, loadProjectFunctions, loadProjectResolvedComponents, loadProjectSchema, resolvePortFromEnv, resolveProjectTargetConfig, runCodegen } from "../core/cli.mjs";
4
4
  import os from "node:os";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import AdmZip from "adm-zip";
@@ -67,16 +67,18 @@ async function resolveProjectTargetDescriptor(cwd) {
67
67
  };
68
68
  }
69
69
  async function createManagedProjectClient(cwd) {
70
- const [paths, schema, functions] = await Promise.all([
70
+ const [paths, schema, functions, components] = await Promise.all([
71
71
  requireProjectPaths(cwd),
72
72
  loadProjectSchema(cwd),
73
- loadRuntimeProjectFunctions(cwd)
73
+ loadRuntimeProjectFunctions(cwd),
74
+ loadProjectResolvedComponents(cwd)
74
75
  ]);
75
76
  return await createManagedNodeSyncoreClient({
76
77
  databasePath: paths.databasePath,
77
78
  storageDirectory: paths.storageDirectory,
78
79
  schema,
79
80
  functions,
81
+ components,
80
82
  devtools: false,
81
83
  platform: "cli"
82
84
  });
@@ -123,7 +125,10 @@ function normalizeFunctionName(requestedName, functions) {
123
125
  trimmed.replaceAll(".", "/")
124
126
  ];
125
127
  for (const candidate of candidates) if (functions[candidate]) return candidate;
126
- return trimmed.replace(/^api\./, "").replaceAll(".", "/").replaceAll(":", "/");
128
+ const normalized = trimmed.replace(/^api\./, "").replaceAll(".", "/").replaceAll(":", "/");
129
+ const componentMatch = [...Object.keys(functions)].filter((name) => isComponentPublicFunctionMatch(name, normalized)).sort((left, right) => left.localeCompare(right));
130
+ if (componentMatch.length === 1) return componentMatch[0];
131
+ return normalized;
127
132
  }
128
133
  async function listProjectTables(cwd) {
129
134
  const [paths, schema] = await Promise.all([requireProjectPaths(cwd), loadProjectSchema(cwd)]);
@@ -132,9 +137,14 @@ async function listProjectTables(cwd) {
132
137
  try {
133
138
  const results = [];
134
139
  for (const tableName of schema.tableNames()) {
140
+ const table = schema.getTable(tableName);
135
141
  const row = await driver.get(`SELECT COUNT(*) AS count FROM ${quoteIdentifier(tableName)}`);
136
142
  results.push({
137
143
  name: tableName,
144
+ ...table.options.tableName ? { displayName: table.options.tableName } : {},
145
+ owner: table.options.componentPath ? "component" : "root",
146
+ ...table.options.componentPath ? { componentPath: table.options.componentPath } : {},
147
+ ...table.options.componentName ? { componentName: table.options.componentName } : {},
138
148
  documentCount: Number(row?.count ?? 0)
139
149
  });
140
150
  }
@@ -279,9 +289,29 @@ async function resolveDocsTarget(cwd) {
279
289
  function resolveDashboardUrl() {
280
290
  return `http://localhost:${resolvePortFromEnv("SYNCORE_DASHBOARD_PORT", 4310)}`;
281
291
  }
292
+ async function resolveActiveDashboardUrl(cwd) {
293
+ return (await readDevtoolsSessionState(cwd))?.authenticatedDashboardUrl ?? resolveDashboardUrl();
294
+ }
282
295
  function resolveDevtoolsUrl() {
283
296
  return `ws://127.0.0.1:${resolvePortFromEnv("SYNCORE_DEVTOOLS_PORT", 4311)}`;
284
297
  }
298
+ async function readDevtoolsSessionState(cwd) {
299
+ const sessionPath = path.join(cwd, ".syncore", "devtools-session.json");
300
+ if (!await fileExists(sessionPath)) return null;
301
+ try {
302
+ const source = await readFile(sessionPath, "utf8");
303
+ const parsed = JSON.parse(source);
304
+ if (typeof parsed.dashboardUrl !== "string" || typeof parsed.authenticatedDashboardUrl !== "string" || typeof parsed.devtoolsUrl !== "string" || typeof parsed.token !== "string") return null;
305
+ return {
306
+ dashboardUrl: parsed.dashboardUrl,
307
+ authenticatedDashboardUrl: parsed.authenticatedDashboardUrl,
308
+ devtoolsUrl: parsed.devtoolsUrl,
309
+ token: parsed.token
310
+ };
311
+ } catch {
312
+ return null;
313
+ }
314
+ }
285
315
  async function listConnectedClientTargets(devtoolsUrl = resolveDevtoolsUrl()) {
286
316
  const port = Number.parseInt(new URL(devtoolsUrl).port, 10);
287
317
  if (!Number.isFinite(port) || !await isLocalPortInUse(port)) return [];
@@ -322,6 +352,13 @@ async function loadRuntimeProjectFunctions(cwd) {
322
352
  return await loadProjectFunctions(cwd);
323
353
  }
324
354
  }
355
+ function isComponentPublicFunctionMatch(functionName, requestedName) {
356
+ const match = /^components\/(.+)\/public\/(.+)$/.exec(functionName);
357
+ if (!match) return false;
358
+ const componentPath = match[1] ?? "";
359
+ const localName = match[2] ?? "";
360
+ return requestedName === `components/${componentPath}/${localName}` || requestedName === `${componentPath}/${localName}`;
361
+ }
325
362
  function quoteIdentifier(value) {
326
363
  return `"${value.replaceAll("\"", "\"\"")}"`;
327
364
  }
@@ -370,9 +407,58 @@ async function resolveImportSources(sourcePath, explicitTable, cleanupDirectorie
370
407
  async function extractImportSourcesFromZip(sourcePath, cleanupDirectories) {
371
408
  const tempDirectory = await mkdtemp(path.join(os.tmpdir(), "syncore-cli-import-"));
372
409
  cleanupDirectories.push(tempDirectory);
373
- new AdmZip(sourcePath).extractAllTo(tempDirectory, true);
410
+ const zip = new AdmZip(sourcePath);
411
+ await assertSafeZipExtractionPaths(sourcePath, zip, tempDirectory);
412
+ zip.extractAllTo(tempDirectory, true);
374
413
  return await resolveImportSources(tempDirectory, void 0, cleanupDirectories);
375
414
  }
415
+ async function assertSafeZipExtractionPaths(sourcePath, zip, extractionDirectory) {
416
+ const resolvedExtractionDirectory = path.resolve(extractionDirectory);
417
+ const extractionRoot = `${resolvedExtractionDirectory}${path.sep}`;
418
+ for (const entryPath of await readRawZipEntryPaths(sourcePath)) assertSafeZipEntryPath(entryPath, resolvedExtractionDirectory, extractionRoot);
419
+ for (const entry of zip.getEntries()) assertSafeZipEntryPath(entry.entryName, resolvedExtractionDirectory, extractionRoot);
420
+ }
421
+ function assertSafeZipEntryPath(entryName, resolvedExtractionDirectory, extractionRoot) {
422
+ const entryPath = entryName.replaceAll("\\", "/");
423
+ if (path.posix.isAbsolute(entryPath) || /^[A-Za-z]:/.test(entryPath)) throw new Error(`Invalid ZIP entry path: ${entryName}`);
424
+ const extractionTarget = path.resolve(resolvedExtractionDirectory, entryPath);
425
+ if (extractionTarget !== resolvedExtractionDirectory && !extractionTarget.startsWith(extractionRoot)) throw new Error(`Invalid ZIP entry path: ${entryName}`);
426
+ }
427
+ async function readRawZipEntryPaths(sourcePath) {
428
+ const archive = await readFile(sourcePath);
429
+ const endOfCentralDirectoryOffset = findEndOfCentralDirectoryOffset(archive);
430
+ if (endOfCentralDirectoryOffset < 0) throw new Error(`Invalid ZIP archive: ${sourcePath}`);
431
+ const entryCount = archive.readUInt16LE(endOfCentralDirectoryOffset + 10);
432
+ const centralDirectorySize = archive.readUInt32LE(endOfCentralDirectoryOffset + 12);
433
+ const centralDirectoryOffset = archive.readUInt32LE(endOfCentralDirectoryOffset + 16);
434
+ const centralDirectoryEnd = centralDirectoryOffset + centralDirectorySize;
435
+ if (centralDirectoryEnd > archive.length) throw new Error(`Invalid ZIP archive: ${sourcePath}`);
436
+ const entryPaths = [];
437
+ let cursor = centralDirectoryOffset;
438
+ for (let index = 0; index < entryCount; index += 1) {
439
+ if (cursor + 46 > centralDirectoryEnd) throw new Error(`Invalid ZIP archive: ${sourcePath}`);
440
+ if (archive.readUInt32LE(cursor) !== 33639248) throw new Error(`Invalid ZIP archive: ${sourcePath}`);
441
+ const flags = archive.readUInt16LE(cursor + 8);
442
+ const fileNameLength = archive.readUInt16LE(cursor + 28);
443
+ const extraFieldLength = archive.readUInt16LE(cursor + 30);
444
+ const commentLength = archive.readUInt16LE(cursor + 32);
445
+ const fileNameStart = cursor + 46;
446
+ const fileNameEnd = fileNameStart + fileNameLength;
447
+ const nextEntryOffset = fileNameEnd + extraFieldLength + commentLength;
448
+ if (nextEntryOffset > centralDirectoryEnd) throw new Error(`Invalid ZIP archive: ${sourcePath}`);
449
+ entryPaths.push(decodeZipEntryPath(archive.subarray(fileNameStart, fileNameEnd), flags));
450
+ cursor = nextEntryOffset;
451
+ }
452
+ return entryPaths;
453
+ }
454
+ function findEndOfCentralDirectoryOffset(archive) {
455
+ const minOffset = Math.max(0, archive.length - 65535 - 22);
456
+ for (let offset = archive.length - 22; offset >= minOffset; offset -= 1) if (archive.readUInt32LE(offset) === 101010256) return offset;
457
+ return -1;
458
+ }
459
+ function decodeZipEntryPath(entryPath, flags) {
460
+ return entryPath.toString((flags & 2048) === 0 ? "latin1" : "utf8");
461
+ }
376
462
  async function writeRowsToTempJsonl(rows) {
377
463
  const tempDirectory = await mkdtemp(path.join(os.tmpdir(), "syncore-cli-json-"));
378
464
  const tempFile = path.join(tempDirectory, "rows.jsonl");
@@ -410,16 +496,14 @@ async function connectToDevtoolsHub(url) {
410
496
  const hellos = /* @__PURE__ */ new Map();
411
497
  const events = [];
412
498
  const eventListeners = /* @__PURE__ */ new Set();
499
+ let lastSnapshotMessageAt = 0;
413
500
  const commandResolvers = /* @__PURE__ */ new Map();
414
501
  const subscriptionHandlers = /* @__PURE__ */ new Map();
415
- await new Promise((resolve, reject) => {
416
- socket.once("open", () => resolve());
417
- socket.once("error", (error) => reject(error));
418
- });
419
502
  socket.on("message", (rawPayload) => {
420
503
  const payload = typeof rawPayload === "string" ? rawPayload : rawPayload instanceof Buffer ? rawPayload.toString("utf8") : Array.isArray(rawPayload) ? Buffer.concat(rawPayload).toString("utf8") : rawPayload instanceof ArrayBuffer ? Buffer.from(rawPayload).toString("utf8") : Buffer.from(rawPayload.buffer, rawPayload.byteOffset, rawPayload.byteLength).toString("utf8");
421
504
  if (payload.length === 0) return;
422
505
  const message = JSON.parse(payload);
506
+ lastSnapshotMessageAt = Date.now();
423
507
  if (message.type === "hello") {
424
508
  hellos.set(message.runtimeId, message);
425
509
  return;
@@ -444,6 +528,10 @@ async function connectToDevtoolsHub(url) {
444
528
  }
445
529
  if (message.type === "subscription.error") subscriptionHandlers.get(message.subscriptionId)?.onError?.(message.error);
446
530
  });
531
+ await new Promise((resolve, reject) => {
532
+ socket.once("open", () => resolve());
533
+ socket.once("error", (error) => reject(error));
534
+ });
447
535
  const dispose = async () => {
448
536
  for (const [commandId, resolver] of commandResolvers) {
449
537
  commandResolvers.delete(commandId);
@@ -457,8 +545,18 @@ async function connectToDevtoolsHub(url) {
457
545
  });
458
546
  };
459
547
  return {
460
- async collectSnapshot(timeoutMs = 120) {
461
- await new Promise((resolve) => setTimeout(resolve, timeoutMs));
548
+ async collectSnapshot(timeoutMs = 500) {
549
+ const deadline = Date.now() + timeoutMs;
550
+ let lastObservedMessageAt = lastSnapshotMessageAt;
551
+ while (Date.now() < deadline) {
552
+ await new Promise((resolve) => setTimeout(resolve, 40));
553
+ if (![...hellos.keys()].some((runtimeId) => runtimeId !== "syncore-dev-hub")) {
554
+ lastObservedMessageAt = lastSnapshotMessageAt;
555
+ continue;
556
+ }
557
+ if (lastSnapshotMessageAt === lastObservedMessageAt) break;
558
+ lastObservedMessageAt = lastSnapshotMessageAt;
559
+ }
462
560
  return {
463
561
  hellos: [...hellos.values()],
464
562
  events: [...events]
@@ -578,6 +676,6 @@ function createHubRequestId(prefix) {
578
676
  return `syncore-cli-${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
579
677
  }
580
678
  //#endregion
581
- export { buildRuntimeLookup, connectToProjectHub, createManagedProjectClient, createPublicRuntimeId$1 as createPublicRuntimeId, exportProjectData, findWorkspaceSyncoreProjects, importProjectData, isKnownTemplate, listAvailableTargets, listConnectedClientTargets, listProjectTables, loadImportDocumentBatches, readProjectTable, resolveDashboardUrl, resolveDevtoolsUrl, resolveDocsTarget, resolveProjectFunction, resolveProjectTargetDescriptor, targetSupportsCapability, writeExportData };
679
+ export { buildRuntimeLookup, connectToProjectHub, createManagedProjectClient, createPublicRuntimeId$1 as createPublicRuntimeId, exportProjectData, findWorkspaceSyncoreProjects, importProjectData, isKnownTemplate, listAvailableTargets, listConnectedClientTargets, listProjectTables, loadImportDocumentBatches, readProjectTable, resolveActiveDashboardUrl, resolveDashboardUrl, resolveDevtoolsUrl, resolveDocsTarget, resolveProjectFunction, resolveProjectTargetDescriptor, targetSupportsCapability, writeExportData };
582
680
 
583
681
  //# sourceMappingURL=project.mjs.map