syncorejs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/_vendor/core/_virtual/_rolldown/runtime.mjs +27 -0
- package/dist/_vendor/core/cli.d.mts +5 -0
- package/dist/_vendor/core/cli.d.mts.map +1 -0
- package/dist/_vendor/core/cli.mjs +1196 -0
- package/dist/_vendor/core/cli.mjs.map +1 -0
- package/dist/_vendor/core/index.d.mts +7 -0
- package/dist/_vendor/core/index.mjs +25 -0
- package/dist/_vendor/core/index.mjs.map +1 -0
- package/dist/_vendor/core/runtime/devtools.d.mts +15 -0
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/devtools.mjs +300 -0
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -0
- package/dist/_vendor/core/runtime/functions.d.mts +123 -0
- package/dist/_vendor/core/runtime/functions.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/functions.mjs +71 -0
- package/dist/_vendor/core/runtime/functions.mjs.map +1 -0
- package/dist/_vendor/core/runtime/id.d.mts +13 -0
- package/dist/_vendor/core/runtime/id.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/id.mjs +28 -0
- package/dist/_vendor/core/runtime/id.mjs.map +1 -0
- package/dist/_vendor/core/runtime/runtime.d.mts +370 -0
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/runtime.mjs +1143 -0
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -0
- package/dist/_vendor/devtools-protocol/index.d.ts +230 -0
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -0
- package/dist/_vendor/devtools-protocol/index.js +0 -0
- package/dist/_vendor/next/config.d.ts +17 -0
- package/dist/_vendor/next/config.d.ts.map +1 -0
- package/dist/_vendor/next/config.js +73 -0
- package/dist/_vendor/next/config.js.map +1 -0
- package/dist/_vendor/next/index.d.ts +80 -0
- package/dist/_vendor/next/index.d.ts.map +1 -0
- package/dist/_vendor/next/index.js +81 -0
- package/dist/_vendor/next/index.js.map +1 -0
- package/dist/_vendor/platform-expo/index.d.ts +97 -0
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -0
- package/dist/_vendor/platform-expo/index.js +197 -0
- package/dist/_vendor/platform-expo/index.js.map +1 -0
- package/dist/_vendor/platform-expo/react.d.ts +26 -0
- package/dist/_vendor/platform-expo/react.d.ts.map +1 -0
- package/dist/_vendor/platform-expo/react.js +30 -0
- package/dist/_vendor/platform-expo/react.js.map +1 -0
- package/dist/_vendor/platform-node/index.d.mts +145 -0
- package/dist/_vendor/platform-node/index.d.mts.map +1 -0
- package/dist/_vendor/platform-node/index.mjs +405 -0
- package/dist/_vendor/platform-node/index.mjs.map +1 -0
- package/dist/_vendor/platform-node/ipc-react.d.mts +25 -0
- package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -0
- package/dist/_vendor/platform-node/ipc-react.mjs +21 -0
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -0
- package/dist/_vendor/platform-node/ipc.d.mts +75 -0
- package/dist/_vendor/platform-node/ipc.d.mts.map +1 -0
- package/dist/_vendor/platform-node/ipc.mjs +343 -0
- package/dist/_vendor/platform-node/ipc.mjs.map +1 -0
- package/dist/_vendor/platform-web/index.d.ts +123 -0
- package/dist/_vendor/platform-web/index.d.ts.map +1 -0
- package/dist/_vendor/platform-web/index.js +309 -0
- package/dist/_vendor/platform-web/index.js.map +1 -0
- package/dist/_vendor/platform-web/indexeddb.d.ts +25 -0
- package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -0
- package/dist/_vendor/platform-web/indexeddb.js +125 -0
- package/dist/_vendor/platform-web/indexeddb.js.map +1 -0
- package/dist/_vendor/platform-web/opfs.d.ts +27 -0
- package/dist/_vendor/platform-web/opfs.d.ts.map +1 -0
- package/dist/_vendor/platform-web/opfs.js +146 -0
- package/dist/_vendor/platform-web/opfs.js.map +1 -0
- package/dist/_vendor/platform-web/persistence.d.ts +27 -0
- package/dist/_vendor/platform-web/persistence.d.ts.map +1 -0
- package/dist/_vendor/platform-web/persistence.js +23 -0
- package/dist/_vendor/platform-web/persistence.js.map +1 -0
- package/dist/_vendor/platform-web/react.d.ts +35 -0
- package/dist/_vendor/platform-web/react.d.ts.map +1 -0
- package/dist/_vendor/platform-web/react.js +42 -0
- package/dist/_vendor/platform-web/react.js.map +1 -0
- package/dist/_vendor/platform-web/sqljs.js +133 -0
- package/dist/_vendor/platform-web/sqljs.js.map +1 -0
- package/dist/_vendor/platform-web/worker.d.ts +78 -0
- package/dist/_vendor/platform-web/worker.d.ts.map +1 -0
- package/dist/_vendor/platform-web/worker.js +307 -0
- package/dist/_vendor/platform-web/worker.js.map +1 -0
- package/dist/_vendor/react/index.d.ts +58 -0
- package/dist/_vendor/react/index.d.ts.map +1 -0
- package/dist/_vendor/react/index.js +151 -0
- package/dist/_vendor/react/index.js.map +1 -0
- package/dist/_vendor/schema/definition.d.ts +98 -0
- package/dist/_vendor/schema/definition.d.ts.map +1 -0
- package/dist/_vendor/schema/definition.js +84 -0
- package/dist/_vendor/schema/definition.js.map +1 -0
- package/dist/_vendor/schema/index.d.ts +4 -0
- package/dist/_vendor/schema/index.js +4 -0
- package/dist/_vendor/schema/planner.d.ts +42 -0
- package/dist/_vendor/schema/planner.d.ts.map +1 -0
- package/dist/_vendor/schema/planner.js +131 -0
- package/dist/_vendor/schema/planner.js.map +1 -0
- package/dist/_vendor/schema/validators.d.ts +194 -0
- package/dist/_vendor/schema/validators.d.ts.map +1 -0
- package/dist/_vendor/schema/validators.js +158 -0
- package/dist/_vendor/schema/validators.js.map +1 -0
- package/dist/_vendor/svelte/index.d.ts +43 -0
- package/dist/_vendor/svelte/index.d.ts.map +1 -0
- package/dist/_vendor/svelte/index.js +75 -0
- package/dist/_vendor/svelte/index.js.map +1 -0
- package/dist/browser-react.d.ts +2 -0
- package/dist/browser-react.js +2 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +10 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/src/cli.d.ts +5 -0
- package/dist/core/src/cli.d.ts.map +1 -0
- package/dist/core/src/cli.js +1196 -0
- package/dist/core/src/cli.js.map +1 -0
- package/dist/core/src/index.js +7 -0
- package/dist/core/src/runtime/devtools.d.ts +7 -0
- package/dist/core/src/runtime/devtools.d.ts.map +1 -0
- package/dist/core/src/runtime/devtools.js +300 -0
- package/dist/core/src/runtime/devtools.js.map +1 -0
- package/dist/core/src/runtime/functions.d.ts +123 -0
- package/dist/core/src/runtime/functions.d.ts.map +1 -0
- package/dist/core/src/runtime/functions.js +71 -0
- package/dist/core/src/runtime/functions.js.map +1 -0
- package/dist/core/src/runtime/id.d.ts +13 -0
- package/dist/core/src/runtime/id.d.ts.map +1 -0
- package/dist/core/src/runtime/id.js +28 -0
- package/dist/core/src/runtime/id.js.map +1 -0
- package/dist/core/src/runtime/runtime.d.ts +371 -0
- package/dist/core/src/runtime/runtime.d.ts.map +1 -0
- package/dist/core/src/runtime/runtime.js +1143 -0
- package/dist/core/src/runtime/runtime.js.map +1 -0
- package/dist/devtools-protocol/src/index.d.ts +201 -0
- package/dist/devtools-protocol/src/index.d.ts.map +1 -0
- package/dist/expo-react.d.ts +2 -0
- package/dist/expo-react.js +2 -0
- package/dist/expo.d.ts +2 -0
- package/dist/expo.js +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/next/src/config.d.ts +17 -0
- package/dist/next/src/config.d.ts.map +1 -0
- package/dist/next/src/config.js +73 -0
- package/dist/next/src/config.js.map +1 -0
- package/dist/next/src/index.d.ts +80 -0
- package/dist/next/src/index.d.ts.map +1 -0
- package/dist/next/src/index.js +82 -0
- package/dist/next/src/index.js.map +1 -0
- package/dist/next-config.d.ts +2 -0
- package/dist/next-config.js +2 -0
- package/dist/next.d.ts +3 -0
- package/dist/next.js +3 -0
- package/dist/node-ipc-react.d.ts +2 -0
- package/dist/node-ipc-react.js +2 -0
- package/dist/node-ipc.d.ts +2 -0
- package/dist/node-ipc.js +2 -0
- package/dist/node.d.ts +4 -0
- package/dist/node.js +3 -0
- package/dist/platform-expo/src/index.d.ts +96 -0
- package/dist/platform-expo/src/index.d.ts.map +1 -0
- package/dist/platform-expo/src/index.js +198 -0
- package/dist/platform-expo/src/index.js.map +1 -0
- package/dist/platform-expo/src/react.d.ts +26 -0
- package/dist/platform-expo/src/react.d.ts.map +1 -0
- package/dist/platform-expo/src/react.js +30 -0
- package/dist/platform-expo/src/react.js.map +1 -0
- package/dist/platform-node/src/index.d.ts +145 -0
- package/dist/platform-node/src/index.d.ts.map +1 -0
- package/dist/platform-node/src/index.js +407 -0
- package/dist/platform-node/src/index.js.map +1 -0
- package/dist/platform-node/src/ipc-react.d.ts +25 -0
- package/dist/platform-node/src/ipc-react.d.ts.map +1 -0
- package/dist/platform-node/src/ipc-react.js +21 -0
- package/dist/platform-node/src/ipc-react.js.map +1 -0
- package/dist/platform-node/src/ipc.d.ts +76 -0
- package/dist/platform-node/src/ipc.d.ts.map +1 -0
- package/dist/platform-node/src/ipc.js +344 -0
- package/dist/platform-node/src/ipc.js.map +1 -0
- package/dist/platform-web/src/index.d.ts +106 -0
- package/dist/platform-web/src/index.d.ts.map +1 -0
- package/dist/platform-web/src/index.js +311 -0
- package/dist/platform-web/src/index.js.map +1 -0
- package/dist/platform-web/src/indexeddb.js +125 -0
- package/dist/platform-web/src/indexeddb.js.map +1 -0
- package/dist/platform-web/src/opfs.js +146 -0
- package/dist/platform-web/src/opfs.js.map +1 -0
- package/dist/platform-web/src/persistence.d.ts +20 -0
- package/dist/platform-web/src/persistence.d.ts.map +1 -0
- package/dist/platform-web/src/persistence.js +23 -0
- package/dist/platform-web/src/persistence.js.map +1 -0
- package/dist/platform-web/src/react.d.ts +35 -0
- package/dist/platform-web/src/react.d.ts.map +1 -0
- package/dist/platform-web/src/react.js +42 -0
- package/dist/platform-web/src/react.js.map +1 -0
- package/dist/platform-web/src/sqljs.js +133 -0
- package/dist/platform-web/src/sqljs.js.map +1 -0
- package/dist/platform-web/src/worker.d.ts +79 -0
- package/dist/platform-web/src/worker.d.ts.map +1 -0
- package/dist/platform-web/src/worker.js +308 -0
- package/dist/platform-web/src/worker.js.map +1 -0
- package/dist/react/src/index.d.ts +59 -0
- package/dist/react/src/index.d.ts.map +1 -0
- package/dist/react/src/index.js +151 -0
- package/dist/react/src/index.js.map +1 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +2 -0
- package/dist/schema/src/definition.d.ts +98 -0
- package/dist/schema/src/definition.d.ts.map +1 -0
- package/dist/schema/src/definition.js +84 -0
- package/dist/schema/src/definition.js.map +1 -0
- package/dist/schema/src/planner.d.ts +42 -0
- package/dist/schema/src/planner.d.ts.map +1 -0
- package/dist/schema/src/planner.js +131 -0
- package/dist/schema/src/planner.js.map +1 -0
- package/dist/schema/src/validators.d.ts +194 -0
- package/dist/schema/src/validators.d.ts.map +1 -0
- package/dist/schema/src/validators.js +158 -0
- package/dist/schema/src/validators.js.map +1 -0
- package/dist/svelte/src/index.d.ts +44 -0
- package/dist/svelte/src/index.d.ts.map +1 -0
- package/dist/svelte/src/index.js +75 -0
- package/dist/svelte/src/index.js.map +1 -0
- package/dist/svelte.d.ts +2 -0
- package/dist/svelte.js +2 -0
- package/package.json +152 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":["connectToNet"],"sources":["../../../../core/src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readdir, mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { createServer } from \"node:http\";\nimport { connect as connectToNet } from \"node:net\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { Command } from \"commander\";\nimport { tsImport } from \"tsx/esm/api\";\nimport WebSocket, { WebSocketServer } from \"ws\";\nimport type {\n SyncoreDevtoolsMessage,\n SyncoreDevtoolsRequest\n} from \"@syncore/devtools-protocol\";\nimport {\n generateId,\n type AnyTableDefinition,\n createSchemaSnapshot,\n diffSchemaSnapshots,\n parseSchemaSnapshot,\n renderCreateIndexStatement,\n renderCreateSearchIndexStatement,\n renderCreateTableStatement,\n renderMigrationSql,\n searchIndexTableName,\n type SchemaSnapshot,\n type SyncoreSchema,\n type TableDefinition,\n type Validator\n} from \"./index.js\";\n\ninterface SyncoreConfig {\n databasePath: string;\n storageDirectory: string;\n}\n\ntype SyncoreTemplateName =\n | \"minimal\"\n | \"node\"\n | \"react-web\"\n | \"expo\"\n | \"electron\"\n | \"next\";\n\ninterface SyncoreTemplateFile {\n path: string;\n content: string;\n}\n\ninterface ScaffoldProjectOptions {\n template: SyncoreTemplateName;\n force?: boolean;\n}\n\ninterface ScaffoldProjectResult {\n template: SyncoreTemplateName;\n created: string[];\n updated: string[];\n skipped: string[];\n}\n\ninterface PackageJsonShape {\n name?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nconst COMBINED_DEV_COMMAND =\n 'concurrently --kill-others-on-fail --names syncore,app --prefix-colors yellow,cyan \"bun run syncorejs:dev\" \"bun run dev:app\"';\n\nconst program = new Command();\nconst CORE_PACKAGE_ROOT = path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n \"..\"\n);\nconst migrationSnapshotFileName = \"_schema_snapshot.json\";\nconst validTemplates: SyncoreTemplateName[] = [\n \"minimal\",\n \"node\",\n \"react-web\",\n \"expo\",\n \"electron\",\n \"next\"\n];\nlet pendingDevBootstrap: ReturnType<typeof setTimeout> | undefined;\nlet devBootstrapInFlight = false;\n\nprogram\n .name(\"syncorejs\")\n .description(\"Syncore local-first toolkit CLI\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"init\")\n .description(\"Scaffold Syncore in the current directory\")\n .option(\n \"--template <template>\",\n `Template to scaffold (${validTemplates.join(\", \")}, or auto)`,\n \"auto\"\n )\n .option(\"--force\", \"Overwrite Syncore-managed files when they already exist\")\n .action(async (options: { template: string; force?: boolean }) => {\n const cwd = process.cwd();\n const template = await resolveRequestedTemplate(cwd, options.template);\n const result = await scaffoldProject(cwd, {\n template,\n ...(options.force ? { force: true } : {})\n });\n await runCodegen(cwd);\n logScaffoldResult(result, \"Syncore project scaffolded.\");\n console.log(\n \"Next: run `npx syncorejs dev` to keep codegen and local migrations in sync.\"\n );\n });\n\nprogram\n .command(\"codegen\")\n .description(\"Generate typed Syncore references from syncore/functions\")\n .action(async () => {\n await runCodegen(process.cwd());\n console.log(\"Generated syncore/_generated files.\");\n });\n\nprogram\n .command(\"doctor\")\n .description(\"Check Syncore project structure and inferred template\")\n .action(async () => {\n const cwd = process.cwd();\n const checks = [\n \"syncore.config.ts\",\n path.join(\"syncore\", \"schema.ts\"),\n path.join(\"syncore\", \"functions\"),\n path.join(\"syncore\", \"migrations\")\n ];\n console.log(`Detected template: ${await detectProjectTemplate(cwd)}`);\n for (const check of checks) {\n const exists = await fileExists(path.join(cwd, check));\n console.log(`${exists ? \"OK\" : \"MISSING\"} ${check}`);\n }\n });\n\nprogram\n .command(\"import\")\n .description(\"Import JSONL sample data into a local Syncore table\")\n .requiredOption(\"--table <table>\", \"Table name to import into\")\n .argument(\"<file>\", \"Path to a JSONL file\")\n .action(async (filePath: string, options: { table: string }) => {\n const importedCount = await importJsonlIntoProject(\n process.cwd(),\n options.table,\n filePath\n );\n console.log(\n `Imported ${importedCount} row(s) into ${JSON.stringify(options.table)}.`\n );\n });\n\nprogram\n .command(\"seed\")\n .description(\n \"Import seed data from syncore/seed.jsonl or syncore/seed/<table>.jsonl\"\n )\n .requiredOption(\"--table <table>\", \"Table name to seed\")\n .option(\"--file <file>\", \"Explicit JSONL file path\")\n .action(async (options: { table: string; file?: string }) => {\n const cwd = process.cwd();\n const seedFile =\n options.file ??\n (await resolveDefaultSeedFile(cwd, options.table)) ??\n path.join(\"syncore\", \"seed\", `${options.table}.jsonl`);\n const importedCount = await importJsonlIntoProject(\n cwd,\n options.table,\n seedFile\n );\n console.log(\n `Seeded ${importedCount} row(s) into ${JSON.stringify(options.table)} from ${seedFile}.`\n );\n });\n\nprogram\n .command(\"migrate:status\")\n .description(\n \"Compare the current schema against the last saved migration snapshot\"\n )\n .action(async () => {\n const cwd = process.cwd();\n const schema = await loadProjectSchema(cwd);\n const currentSnapshot = createSchemaSnapshot(schema);\n const storedSnapshot = await readStoredSnapshot(cwd);\n const plan = diffSchemaSnapshots(storedSnapshot, currentSnapshot);\n\n console.log(`Current schema hash: ${currentSnapshot.hash}`);\n console.log(`Stored snapshot: ${storedSnapshot?.hash ?? \"none\"}`);\n console.log(`Statements to generate: ${plan.statements.length}`);\n console.log(`Warnings: ${plan.warnings.length}`);\n console.log(`Destructive changes: ${plan.destructiveChanges.length}`);\n\n for (const warning of plan.warnings) {\n console.log(`WARN ${warning}`);\n }\n for (const destructiveChange of plan.destructiveChanges) {\n console.log(`BLOCK ${destructiveChange}`);\n }\n });\n\nprogram\n .command(\"migrate:generate\")\n .argument(\"[name]\", \"Optional migration name\", \"auto\")\n .description(\"Generate a SQL migration file from the current schema diff\")\n .action(async (name: string) => {\n const cwd = process.cwd();\n const schema = await loadProjectSchema(cwd);\n const currentSnapshot = createSchemaSnapshot(schema);\n const storedSnapshot = await readStoredSnapshot(cwd);\n const plan = diffSchemaSnapshots(storedSnapshot, currentSnapshot);\n\n if (plan.destructiveChanges.length > 0) {\n console.error(\"Destructive schema changes require a manual migration:\");\n for (const destructiveChange of plan.destructiveChanges) {\n console.error(`- ${destructiveChange}`);\n }\n process.exitCode = 1;\n return;\n }\n\n if (plan.statements.length === 0 && plan.warnings.length === 0) {\n console.log(\"No schema changes detected.\");\n return;\n }\n\n const migrationsDirectory = path.join(cwd, \"syncore\", \"migrations\");\n await mkdir(migrationsDirectory, { recursive: true });\n const migrationNumber = await getNextMigrationNumber(migrationsDirectory);\n const slug = slugify(name);\n const migrationFileName = `${String(migrationNumber).padStart(4, \"0\")}_${slug}.sql`;\n const migrationSql = renderMigrationSql(plan, {\n title: `Syncore migration ${migrationFileName}`\n });\n await writeFile(\n path.join(migrationsDirectory, migrationFileName),\n migrationSql\n );\n await writeStoredSnapshot(cwd, currentSnapshot);\n console.log(\n `Generated ${path.join(\"syncore\", \"migrations\", migrationFileName)}`\n );\n });\n\nprogram\n .command(\"migrate:apply\")\n .description(\n \"Apply SQL migrations from syncore/migrations to the configured database\"\n )\n .action(async () => {\n const appliedCount = await applyProjectMigrations(process.cwd());\n console.log(`Applied ${appliedCount} migration(s).`);\n });\n\nprogram\n .command(\"dev\")\n .description(\"Start the Syncore dev loop and devtools hub\")\n .option(\n \"--template <template>\",\n `Template to scaffold when Syncore is missing (${validTemplates.join(\", \")}, or auto)`,\n \"auto\"\n )\n .action(async (options: { template: string }) => {\n const cwd = process.cwd();\n const template = await resolveRequestedTemplate(cwd, options.template);\n await startDevHub({ cwd, template });\n });\n\nexport async function runSyncoreCli(argv = process.argv): Promise<void> {\n await program.parseAsync(argv);\n}\n\nif (isCliEntryPoint()) {\n await runSyncoreCli();\n}\n\nasync function runCodegen(cwd: string): Promise<void> {\n const functionsDir = path.join(cwd, \"syncore\", \"functions\");\n const generatedDir = path.join(cwd, \"syncore\", \"_generated\");\n await mkdir(generatedDir, { recursive: true });\n const functionImportExtension = await resolveFunctionImportExtension(cwd);\n\n const files = await listTypeScriptFiles(functionsDir);\n const functionEntries: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }> = [];\n\n for (const file of files) {\n const content = await readFile(file, \"utf8\");\n const relative = path\n .relative(functionsDir, file)\n .replaceAll(\"\\\\\", \"/\")\n .replace(/\\.tsx?$/, \"\");\n const pathParts = relative.split(\"/\");\n const regex = /export const (\\w+)\\s*=\\s*(query|mutation|action)\\(/g;\n for (const match of content.matchAll(regex)) {\n functionEntries.push({\n pathParts,\n exportName: match[1]!,\n kind: match[2] as \"query\" | \"mutation\" | \"action\"\n });\n }\n }\n\n const apiSource = [\n `/**`,\n ` * Generated \\`api\\` utility for referencing Syncore functions.`,\n ` *`,\n ` * THIS CODE IS AUTOMATICALLY GENERATED.`,\n ` *`,\n ` * To regenerate, run \\`npx syncorejs dev\\` or \\`npx syncorejs codegen\\`.`,\n ` * @module`,\n ` */`,\n ``,\n `import { createFunctionReferenceFor } from \"syncorejs\";`,\n `import type { FunctionReferenceFor } from \"syncorejs\";`,\n ...renderFunctionTypeImports(functionEntries, functionImportExtension),\n ``,\n ...renderGeneratedApiInterfaces(functionEntries),\n ``,\n `/**`,\n ` * A utility for referencing Syncore functions in your app's public API.`,\n ` *`,\n ` * Usage:`,\n ` * \\`\\`\\`ts`,\n ` * const listTasks = api.tasks.list;`,\n ` * \\`\\`\\``,\n ` */`,\n `export const api: SyncoreApi = ${renderApiObject(functionEntries)} as const;`,\n ``\n ].join(\"\\n\");\n\n const functionsSource = [\n `/**`,\n ` * Generated Syncore function registry.`,\n ` *`,\n ` * THIS CODE IS AUTOMATICALLY GENERATED.`,\n ` *`,\n ` * To regenerate, run \\`npx syncorejs dev\\` or \\`npx syncorejs codegen\\`.`,\n ` * @module`,\n ` */`,\n ``,\n `import type { SyncoreFunctionRegistry } from \"syncorejs\";`,\n ``,\n ...renderFunctionImports(functionEntries, functionImportExtension),\n ``,\n ...renderGeneratedFunctionsInterface(functionEntries),\n ``,\n `/**`,\n ` * The runtime registry for every function exported from \\`syncore/functions\\`.`,\n ` *`,\n ` * Most application code should import from \\`./api\\` instead of using this map directly.`,\n ` */`,\n `export const functions: SyncoreFunctionsRegistry = {`,\n ...functionEntries.map(\n (entry) =>\n ` ${JSON.stringify(`${entry.pathParts.join(\"/\")}/${entry.exportName}`)}: ${renderFunctionImportName(entry)},`\n ),\n `} as const;`,\n ``\n ].join(\"\\n\");\n\n const serverSource = [\n `/**`,\n ` * Generated utilities for implementing Syncore query, mutation, and action functions.`,\n ` *`,\n ` * THIS CODE IS AUTOMATICALLY GENERATED.`,\n ` *`,\n ` * To regenerate, run \\`npx syncorejs dev\\` or \\`npx syncorejs codegen\\`.`,\n ` * @module`,\n ` */`,\n ``,\n `import type schema from \"../schema${functionImportExtension}\";`,\n `import { action as baseAction, mutation as baseMutation, query as baseQuery } from \"syncorejs\";`,\n `import type {`,\n ` ActionCtx as BaseActionCtx,`,\n ` FunctionConfig,`,\n ` Infer,`,\n ` InferArgs,`,\n ` MutationCtx as BaseMutationCtx,`,\n ` QueryCtx as BaseQueryCtx,`,\n ` SyncoreFunctionDefinition,`,\n ` Validator,`,\n ` ValidatorMap`,\n `} from \"syncorejs\";`,\n ``,\n `export { createFunctionReference, createFunctionReferenceFor, v } from \"syncorejs\";`,\n ``,\n `/**`,\n ` * The context object available inside Syncore query handlers in this app.`,\n ` */`,\n `export type QueryCtx = BaseQueryCtx<typeof schema>;`,\n ``,\n `/**`,\n ` * The context object available inside Syncore mutation handlers in this app.`,\n ` */`,\n `export type MutationCtx = BaseMutationCtx<typeof schema>;`,\n ``,\n `/**`,\n ` * The context object available inside Syncore action handlers in this app.`,\n ` */`,\n `export type ActionCtx = BaseActionCtx<typeof schema>;`,\n ``,\n `export type { FunctionReference } from \"syncorejs\";`,\n ``,\n `/**`,\n ` * Define a query in this Syncore app's public API.`,\n ` *`,\n ` * Queries can read from your local Syncore database and can be called from clients.`,\n ` *`,\n ` * @param config - The query definition, including args and a handler.`,\n ` * @returns The wrapped query. Export it from \\`syncore/functions\\` to add it to the generated API.`,\n ` */`,\n `export function query<TValidator extends Validator<unknown>, TResult>(`,\n ` config: FunctionConfig<QueryCtx, Infer<TValidator>, TResult> & { args: TValidator }`,\n `): SyncoreFunctionDefinition<\"query\", QueryCtx, Infer<TValidator>, TResult>;`,\n `export function query<TArgsShape extends ValidatorMap, TResult>(`,\n ` config: FunctionConfig<QueryCtx, InferArgs<TArgsShape>, TResult> & { args: TArgsShape }`,\n `): SyncoreFunctionDefinition<\"query\", QueryCtx, InferArgs<TArgsShape>, TResult>;`,\n `export function query<TArgsShape extends Validator<unknown> | ValidatorMap, TResult>(`,\n ` config: FunctionConfig<QueryCtx, InferArgs<TArgsShape>, TResult> & { args: TArgsShape }`,\n `) {`,\n ` return baseQuery(config as never) as SyncoreFunctionDefinition<`,\n ` \"query\",`,\n ` QueryCtx,`,\n ` InferArgs<TArgsShape>,`,\n ` TResult`,\n ` >;`,\n `}`,\n ``,\n `/**`,\n ` * Define a mutation in this Syncore app's public API.`,\n ` *`,\n ` * Mutations can write to your local Syncore database and can be called from clients.`,\n ` *`,\n ` * @param config - The mutation definition, including args and a handler.`,\n ` * @returns The wrapped mutation. Export it from \\`syncore/functions\\` to add it to the generated API.`,\n ` */`,\n `export function mutation<TValidator extends Validator<unknown>, TResult>(`,\n ` config: FunctionConfig<MutationCtx, Infer<TValidator>, TResult> & { args: TValidator }`,\n `): SyncoreFunctionDefinition<\"mutation\", MutationCtx, Infer<TValidator>, TResult>;`,\n `export function mutation<TArgsShape extends ValidatorMap, TResult>(`,\n ` config: FunctionConfig<MutationCtx, InferArgs<TArgsShape>, TResult> & { args: TArgsShape }`,\n `): SyncoreFunctionDefinition<\"mutation\", MutationCtx, InferArgs<TArgsShape>, TResult>;`,\n `export function mutation<TArgsShape extends Validator<unknown> | ValidatorMap, TResult>(`,\n ` config: FunctionConfig<MutationCtx, InferArgs<TArgsShape>, TResult> & { args: TArgsShape }`,\n `) {`,\n ` return baseMutation(config as never) as SyncoreFunctionDefinition<`,\n ` \"mutation\",`,\n ` MutationCtx,`,\n ` InferArgs<TArgsShape>,`,\n ` TResult`,\n ` >;`,\n `}`,\n ``,\n `/**`,\n ` * Define an action in this Syncore app's public API.`,\n ` *`,\n ` * Actions can run arbitrary JavaScript and may call queries or mutations.`,\n ` *`,\n ` * @param config - The action definition, including args and a handler.`,\n ` * @returns The wrapped action. Export it from \\`syncore/functions\\` to add it to the generated API.`,\n ` */`,\n `export function action<TValidator extends Validator<unknown>, TResult>(`,\n ` config: FunctionConfig<ActionCtx, Infer<TValidator>, TResult> & { args: TValidator }`,\n `): SyncoreFunctionDefinition<\"action\", ActionCtx, Infer<TValidator>, TResult>;`,\n `export function action<TArgsShape extends ValidatorMap, TResult>(`,\n ` config: FunctionConfig<ActionCtx, InferArgs<TArgsShape>, TResult> & { args: TArgsShape }`,\n `): SyncoreFunctionDefinition<\"action\", ActionCtx, InferArgs<TArgsShape>, TResult>;`,\n `export function action<TArgsShape extends Validator<unknown> | ValidatorMap, TResult>(`,\n ` config: FunctionConfig<ActionCtx, InferArgs<TArgsShape>, TResult> & { args: TArgsShape }`,\n `) {`,\n ` return baseAction(config as never) as SyncoreFunctionDefinition<`,\n ` \"action\",`,\n ` ActionCtx,`,\n ` InferArgs<TArgsShape>,`,\n ` TResult`,\n ` >;`,\n `}`,\n ``\n ].join(\"\\n\");\n\n await writeFile(path.join(generatedDir, \"api.ts\"), apiSource);\n await writeFile(path.join(generatedDir, \"functions.ts\"), functionsSource);\n await writeFile(path.join(generatedDir, \"server.ts\"), serverSource);\n}\n\nasync function scaffoldProject(\n cwd: string,\n options: ScaffoldProjectOptions\n): Promise<ScaffoldProjectResult> {\n const files = buildTemplateFiles(options.template);\n const created: string[] = [];\n const updated: string[] = [];\n const skipped: string[] = [];\n\n await mkdir(path.join(cwd, \"syncore\", \"functions\"), { recursive: true });\n await mkdir(path.join(cwd, \"syncore\", \"_generated\"), { recursive: true });\n await mkdir(path.join(cwd, \"syncore\", \"migrations\"), { recursive: true });\n\n for (const file of files) {\n const targetPath = path.join(cwd, file.path);\n const result = await writeManagedFile(\n targetPath,\n file.content,\n options.force\n );\n const relative = path.relative(cwd, targetPath).replaceAll(\"\\\\\", \"/\");\n if (result === \"created\") {\n created.push(relative);\n } else if (result === \"updated\") {\n updated.push(relative);\n } else {\n skipped.push(relative);\n }\n }\n\n await ensurePackageScripts(cwd, options.template);\n await ensureGitignoreEntries(cwd, [\".syncore/\"]);\n\n return {\n template: options.template,\n created,\n updated,\n skipped\n };\n}\n\nfunction buildTemplateFiles(\n template: SyncoreTemplateName\n): SyncoreTemplateFile[] {\n const files: SyncoreTemplateFile[] = [\n {\n path: \"syncore.config.ts\",\n content: `export default {\n databasePath: \".syncore/syncore.db\",\n storageDirectory: \".syncore/storage\"\n};\n`\n },\n {\n path: path.join(\"syncore\", \"schema.ts\"),\n content: `import { defineSchema, defineTable, v } from \"syncorejs\";\n\nexport default defineSchema({\n tasks: defineTable({\n text: v.string(),\n done: v.boolean()\n }).index(\"by_done\", [\"done\"])\n});\n`\n },\n {\n path: path.join(\"syncore\", \"functions\", \"tasks.ts\"),\n content: `import { mutation, query, v } from \"../_generated/server\";\n\nexport const list = query({\n args: {},\n handler: async (ctx) =>\n ctx.db.query(\"tasks\").withIndex(\"by_done\").order(\"asc\").collect()\n});\n\nexport const create = mutation({\n args: { text: v.string() },\n handler: async (ctx, args) =>\n ctx.db.insert(\"tasks\", { text: args.text, done: false })\n});\n`\n }\n ];\n\n switch (template) {\n case \"react-web\":\n files.push(\n {\n path: path.join(\"src\", \"syncore.worker.ts\"),\n content: `/// <reference lib=\"webworker\" />\n\nimport { createBrowserWorkerRuntime } from \"syncorejs/browser\";\nimport schema from \"../syncore/schema\";\nimport { functions } from \"../syncore/_generated/functions\";\n\nvoid createBrowserWorkerRuntime({\n endpoint: self,\n schema,\n functions,\n databaseName: \"syncore-app\",\n persistenceMode: \"opfs\"\n});\n`\n },\n {\n path: path.join(\"src\", \"syncore-provider.tsx\"),\n content: `import type { ReactNode } from \"react\";\nimport { SyncoreBrowserProvider } from \"syncorejs/browser/react\";\n\nexport function AppSyncoreProvider({ children }: { children: ReactNode }) {\n return (\n <SyncoreBrowserProvider workerUrl={new URL(\"./syncore.worker.ts\", import.meta.url)}>\n {children}\n </SyncoreBrowserProvider>\n );\n}\n`\n }\n );\n break;\n case \"expo\":\n files.push({\n path: path.join(\"lib\", \"syncore.ts\"),\n content: `import { createExpoSyncoreBootstrap } from \"syncorejs/expo\";\nimport schema from \"../syncore/schema\";\nimport { functions } from \"../syncore/_generated/functions\";\n\nexport const syncore = createExpoSyncoreBootstrap({\n schema,\n functions,\n databaseName: \"syncore-app.db\",\n storageDirectoryName: \"syncore-app-storage\"\n});\n`\n });\n break;\n case \"next\":\n files.push(\n {\n path: path.join(\"app\", \"syncore.worker.js\"),\n content: `/* eslint-disable */\n\nimport { createBrowserWorkerRuntime } from \"syncorejs/browser\";\nimport schema from \"../syncore/schema\";\nimport { functions } from \"../syncore/_generated/functions\";\n\nvoid createBrowserWorkerRuntime({\n endpoint: self,\n schema,\n functions,\n databaseName: \"syncore-app\",\n persistenceDatabaseName: \"syncore-app\",\n locateFile: () => \"/sql-wasm.wasm\",\n platform: \"browser-worker\"\n});\n`\n },\n {\n path: path.join(\"app\", \"syncore-provider.tsx\"),\n content: `\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { SyncoreNextProvider } from \"syncorejs/next\";\n\nconst createWorker = () =>\n new Worker(new URL(\"./syncore.worker.js\", import.meta.url), {\n type: \"module\"\n });\n\nexport function AppSyncoreProvider({ children }: { children: ReactNode }) {\n return (\n <SyncoreNextProvider createWorker={createWorker}>\n {children}\n </SyncoreNextProvider>\n );\n}\n`\n }\n );\n break;\n case \"node\":\n files.push({\n path: \"script.mjs\",\n content: `import path from \"node:path\";\nimport { withNodeSyncoreClient } from \"syncorejs/node\";\nimport { api } from \"./syncore/_generated/api.ts\";\nimport schema from \"./syncore/schema.ts\";\nimport { functions } from \"./syncore/_generated/functions.ts\";\n\nawait withNodeSyncoreClient(\n {\n databasePath: path.join(process.cwd(), \".syncore\", \"syncore.db\"),\n storageDirectory: path.join(process.cwd(), \".syncore\", \"storage\"),\n schema,\n functions\n },\n async (client) => {\n await client.mutation(api.tasks.create, { text: \"Run locally\" });\n console.log(await client.query(api.tasks.list));\n }\n);\n`\n });\n break;\n case \"electron\":\n files.push({\n path: path.join(\"src\", \"syncore-runtime.ts\"),\n content: `import path from \"node:path\";\nimport { app } from \"electron\";\nimport { createNodeSyncoreRuntime } from \"syncorejs/node\";\nimport schema from \"../syncore/schema.js\";\nimport { functions } from \"../syncore/_generated/functions.js\";\n\nexport function createAppSyncoreRuntime() {\n const userDataDirectory = app.getPath(\"userData\");\n return createNodeSyncoreRuntime({\n databasePath: path.join(userDataDirectory, \"syncore.db\"),\n storageDirectory: path.join(userDataDirectory, \"storage\"),\n schema,\n functions,\n platform: \"electron-main\"\n });\n}\n`\n });\n break;\n case \"minimal\":\n break;\n }\n\n return files;\n}\n\nfunction logScaffoldResult(\n result: ScaffoldProjectResult,\n heading: string\n): void {\n console.log(heading);\n console.log(`Using template: ${result.template}`);\n if (result.created.length > 0) {\n console.log(`Created: ${result.created.join(\", \")}`);\n }\n if (result.updated.length > 0) {\n console.log(`Updated: ${result.updated.join(\", \")}`);\n }\n if (result.skipped.length > 0) {\n console.log(`Kept existing: ${result.skipped.join(\", \")}`);\n }\n}\n\nasync function ensureProjectScaffolded(\n cwd: string,\n template: SyncoreTemplateName\n): Promise<void> {\n if (await hasSyncoreProject(cwd)) {\n return;\n }\n const result = await scaffoldProject(cwd, { template });\n logScaffoldResult(\n result,\n \"Syncore dev did not find a Syncore project, so it scaffolded one for you.\"\n );\n}\n\nasync function hasSyncoreProject(cwd: string): Promise<boolean> {\n return (\n (await fileExists(path.join(cwd, \"syncore.config.ts\"))) &&\n (await fileExists(path.join(cwd, \"syncore\", \"schema.ts\"))) &&\n (await fileExists(path.join(cwd, \"syncore\", \"functions\")))\n );\n}\n\nasync function resolveRequestedTemplate(\n cwd: string,\n requestedTemplate: string\n): Promise<SyncoreTemplateName> {\n if (requestedTemplate !== \"auto\") {\n if (!validTemplates.includes(requestedTemplate as SyncoreTemplateName)) {\n throw new Error(\n `Unknown template ${JSON.stringify(requestedTemplate)}. Expected one of ${validTemplates.join(\", \")} or auto.`\n );\n }\n return requestedTemplate as SyncoreTemplateName;\n }\n return detectProjectTemplate(cwd);\n}\n\nasync function detectProjectTemplate(\n cwd: string\n): Promise<SyncoreTemplateName> {\n const packageJson = await readPackageJson(cwd);\n const dependencies = {\n ...(packageJson?.dependencies ?? {}),\n ...(packageJson?.devDependencies ?? {})\n };\n\n if (\"expo\" in dependencies || \"react-native\" in dependencies) {\n return \"expo\";\n }\n if (\"electron\" in dependencies) {\n return \"electron\";\n }\n if (\"next\" in dependencies) {\n return \"next\";\n }\n if (\n \"vite\" in dependencies ||\n \"@vitejs/plugin-react\" in dependencies ||\n ((await fileExists(path.join(cwd, \"src\", \"main.tsx\"))) &&\n \"react\" in dependencies)\n ) {\n return \"react-web\";\n }\n if (packageJson) {\n return \"node\";\n }\n return \"minimal\";\n}\n\nasync function readPackageJson(cwd: string): Promise<PackageJsonShape | null> {\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!(await fileExists(packageJsonPath))) {\n return null;\n }\n try {\n return JSON.parse(\n await readFile(packageJsonPath, \"utf8\")\n ) as PackageJsonShape;\n } catch {\n return null;\n }\n}\n\nasync function ensurePackageScripts(\n cwd: string,\n template: SyncoreTemplateName\n): Promise<void> {\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!(await fileExists(packageJsonPath))) {\n return;\n }\n\n const packageJson = await readPackageJson(cwd);\n if (!packageJson) {\n return;\n }\n\n const nextPackageJson: PackageJsonShape = {\n ...packageJson,\n scripts: {\n ...(packageJson.scripts ?? {})\n }\n };\n\n nextPackageJson.scripts ??= {};\n nextPackageJson.scripts[\"syncorejs:dev\"] ??= \"syncorejs dev\";\n nextPackageJson.scripts[\"syncorejs:codegen\"] ??= \"syncorejs codegen\";\n\n maybeAddManagedDevScripts(nextPackageJson, template);\n\n if (stableStringify(nextPackageJson) === stableStringify(packageJson)) {\n return;\n }\n\n await writeFile(\n packageJsonPath,\n `${JSON.stringify(nextPackageJson, null, 2)}\\n`\n );\n}\n\nfunction maybeAddManagedDevScripts(\n packageJson: PackageJsonShape,\n template: SyncoreTemplateName\n): void {\n if (!supportsManagedCombinedDev(template)) {\n return;\n }\n\n packageJson.scripts ??= {};\n const scripts = packageJson.scripts;\n const currentDev = scripts.dev;\n if (!currentDev) {\n return;\n }\n\n if (\n scripts[\"dev:app\"] === currentDev &&\n scripts.dev === combinedDevCommand()\n ) {\n packageJson.devDependencies ??= {};\n packageJson.devDependencies.concurrently ??= \"^9.1.2\";\n return;\n }\n\n if (scripts[\"dev:app\"] && scripts[\"dev:app\"] !== currentDev) {\n return;\n }\n\n if (currentDev.includes(\"syncorejs:dev\") || currentDev.includes(\"dev:app\")) {\n return;\n }\n\n packageJson.devDependencies ??= {};\n packageJson.devDependencies.concurrently ??= \"^9.1.2\";\n scripts[\"dev:app\"] ??= currentDev;\n scripts.dev = combinedDevCommand();\n}\n\nfunction supportsManagedCombinedDev(template: SyncoreTemplateName): boolean {\n return (\n template === \"next\" || template === \"react-web\" || template === \"electron\"\n );\n}\n\nfunction combinedDevCommand(): string {\n return COMBINED_DEV_COMMAND;\n}\n\nasync function ensureGitignoreEntries(\n cwd: string,\n entries: string[]\n): Promise<void> {\n const gitignorePath = path.join(cwd, \".gitignore\");\n const existing = (await fileExists(gitignorePath))\n ? await readFile(gitignorePath, \"utf8\")\n : \"\";\n const lines = new Set(\n existing\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean)\n );\n let changed = false;\n for (const entry of entries) {\n if (!lines.has(entry)) {\n lines.add(entry);\n changed = true;\n }\n }\n if (!changed) {\n return;\n }\n const nextContent = `${[...lines].sort((left, right) => left.localeCompare(right)).join(\"\\n\")}\\n`;\n await writeFile(gitignorePath, nextContent);\n}\n\nasync function writeManagedFile(\n filePath: string,\n content: string,\n force = false\n): Promise<\"created\" | \"updated\" | \"skipped\"> {\n await mkdir(path.dirname(filePath), { recursive: true });\n if (!(await fileExists(filePath))) {\n await writeFile(filePath, content);\n return \"created\";\n }\n if (!force) {\n return \"skipped\";\n }\n const current = await readFile(filePath, \"utf8\");\n if (current === content) {\n return \"skipped\";\n }\n await writeFile(filePath, content);\n return \"updated\";\n}\n\nasync function importJsonlIntoProject(\n cwd: string,\n tableName: string,\n sourcePath: string\n): Promise<number> {\n const schema = await loadProjectSchema(cwd);\n const table = schema.getTable(tableName) as TableDefinition<\n Validator<unknown>\n >;\n const config = await loadProjectConfig(cwd);\n const databasePath = path.resolve(cwd, config.databasePath);\n const storageDirectory = path.resolve(cwd, config.storageDirectory);\n const sourceFilePath = path.resolve(cwd, sourcePath);\n await mkdir(path.dirname(databasePath), { recursive: true });\n await mkdir(storageDirectory, { recursive: true });\n const source = await readFile(sourceFilePath, \"utf8\");\n const rows = source\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n\n const database = new DatabaseSync(databasePath);\n try {\n ensureDatabaseReadyForImport(database, schema);\n let importedCount = 0;\n let lineNumber = 0;\n for (const line of rows) {\n lineNumber += 1;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (error) {\n throw new Error(\n `Invalid JSON on line ${lineNumber} of ${sourcePath}: ${formatError(error)}`\n );\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(\n `Line ${lineNumber} of ${sourcePath} must contain a JSON object.`\n );\n }\n const payload = { ...(parsed as Record<string, unknown>) };\n delete payload._id;\n delete payload._creationTime;\n const validated = table.validator.parse(payload) as Record<\n string,\n unknown\n >;\n const id = generateId();\n const creationTime = Date.now() + importedCount;\n const json = stableStringify(validated);\n database\n .prepare(\n `INSERT INTO ${quoteIdentifier(tableName)} (_id, _creationTime, _json) VALUES (?, ?, ?)`\n )\n .run(id, creationTime, json);\n syncSearchIndexesForImport(database, tableName, table, {\n _id: id,\n _creationTime: creationTime,\n _json: json\n });\n importedCount += 1;\n }\n return importedCount;\n } finally {\n database.close();\n }\n}\n\nasync function resolveDefaultSeedFile(\n cwd: string,\n tableName: string\n): Promise<string | null> {\n const candidates = [\n path.join(cwd, \"syncore\", \"seed\", `${tableName}.jsonl`),\n path.join(cwd, \"syncore\", \"seed.jsonl\")\n ];\n for (const candidate of candidates) {\n if (await fileExists(candidate)) {\n return path.relative(cwd, candidate).replaceAll(\"\\\\\", \"/\");\n }\n }\n return null;\n}\n\nfunction ensureDatabaseReadyForImport(\n database: DatabaseSync,\n schema: SyncoreSchema<Record<string, AnyTableDefinition>>\n): void {\n for (const tableName of schema.tableNames()) {\n const table = schema.getTable(tableName) as TableDefinition<\n Validator<unknown>\n >;\n database.exec(renderCreateTableStatement(tableName));\n for (const index of table.indexes) {\n database.exec(\n renderCreateIndexStatement(tableName, index.name, index.fields)\n );\n }\n for (const searchIndex of table.searchIndexes) {\n try {\n database.exec(renderCreateSearchIndexStatement(tableName, searchIndex));\n } catch (error) {\n if (\n !isUnsupportedFts5Statement(\n renderCreateSearchIndexStatement(tableName, searchIndex),\n error\n )\n ) {\n throw error;\n }\n }\n }\n }\n}\n\nfunction syncSearchIndexesForImport(\n database: DatabaseSync,\n tableName: string,\n table: TableDefinition<Validator<unknown>>,\n row: { _id: string; _creationTime: number; _json: string }\n): void {\n if (table.searchIndexes.length === 0) {\n return;\n }\n const payload = JSON.parse(row._json) as Record<string, unknown>;\n for (const searchIndex of table.searchIndexes) {\n const searchTable = searchIndexTableName(tableName, searchIndex.name);\n try {\n database\n .prepare(`DELETE FROM ${quoteIdentifier(searchTable)} WHERE _id = ?`)\n .run(row._id);\n database\n .prepare(\n `INSERT INTO ${quoteIdentifier(searchTable)} (_id, search_value) VALUES (?, ?)`\n )\n .run(row._id, toSearchValue(payload[searchIndex.searchField]));\n } catch (error) {\n if (\n !isUnsupportedFts5Statement(\n renderCreateSearchIndexStatement(tableName, searchIndex),\n error\n )\n ) {\n throw error;\n }\n }\n }\n}\n\nasync function listTypeScriptFiles(directory: string): Promise<string[]> {\n if (!(await fileExists(directory))) {\n return [];\n }\n const entries = await readdir(directory, { withFileTypes: true });\n const files = await Promise.all(\n entries.map(async (entry) => {\n const fullPath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n return listTypeScriptFiles(fullPath);\n }\n if (entry.isFile() && /\\.tsx?$/.test(entry.name)) {\n return [fullPath];\n }\n return [];\n })\n );\n return files.flat().sort((left, right) => left.localeCompare(right));\n}\n\ntype ApiModuleNode = {\n pathParts: string[];\n children: Map<string, ApiModuleNode>;\n functions: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }>;\n};\n\nfunction renderGeneratedApiInterfaces(\n functionEntries: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }>\n): string[] {\n const root = buildApiModuleTree(functionEntries);\n return renderGeneratedApiInterfaceNode(root);\n}\n\nfunction renderGeneratedApiInterfaceNode(node: ApiModuleNode): string[] {\n const childInterfaces = [...node.children.values()]\n .sort((left, right) =>\n left.pathParts.join(\"/\").localeCompare(right.pathParts.join(\"/\"))\n )\n .flatMap((child) => renderGeneratedApiInterfaceNode(child));\n\n const lines = [\n `/**`,\n ` * ${renderApiInterfaceDescription(node)}`,\n ` */`,\n `export interface ${renderApiInterfaceName(node)} {`\n ];\n\n for (const child of [...node.children.values()].sort((left, right) =>\n left.pathParts.join(\"/\").localeCompare(right.pathParts.join(\"/\"))\n )) {\n lines.push(\n ` /**`,\n ` * ${renderApiModulePropertyDescription(child)}`,\n ` */`,\n ` readonly ${renderPropertyKey(child.pathParts.at(-1) ?? \"\")}: ${renderApiInterfaceName(child)};`\n );\n }\n\n for (const entry of [...node.functions].sort((left, right) =>\n left.exportName.localeCompare(right.exportName)\n )) {\n lines.push(\n ` /**`,\n ` * ${renderApiFunctionPropertyDescription(entry)}`,\n ` */`,\n ` readonly ${renderPropertyKey(entry.exportName)}: FunctionReferenceFor<typeof ${renderFunctionImportName(entry)}>;`\n );\n }\n\n lines.push(`}`);\n return [...childInterfaces, lines.join(\"\\n\")];\n}\n\nfunction renderApiObject(\n functionEntries: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }>\n): string {\n const root = buildApiModuleTree(functionEntries);\n return renderApiObjectNode(root);\n}\n\nfunction renderApiObjectNode(node: ApiModuleNode): string {\n const properties: string[] = [];\n\n for (const child of [...node.children.values()].sort((left, right) =>\n left.pathParts.join(\"/\").localeCompare(right.pathParts.join(\"/\"))\n )) {\n properties.push(\n `${renderPropertyKey(child.pathParts.at(-1) ?? \"\")}: ${renderApiObjectNode(child)}`\n );\n }\n\n for (const entry of [...node.functions].sort((left, right) =>\n left.exportName.localeCompare(right.exportName)\n )) {\n properties.push(\n `${renderPropertyKey(entry.exportName)}: createFunctionReferenceFor<typeof ${renderFunctionImportName(entry)}>(\"${entry.kind}\", \"${entry.pathParts.join(\"/\")}/${entry.exportName}\")`\n );\n }\n\n return `{ ${properties.join(\", \")} }`;\n}\n\nfunction buildApiModuleTree(\n functionEntries: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }>\n): ApiModuleNode {\n const root: ApiModuleNode = {\n pathParts: [],\n children: new Map(),\n functions: []\n };\n\n for (const entry of functionEntries) {\n let cursor = root;\n for (const segment of entry.pathParts) {\n let child = cursor.children.get(segment);\n if (!child) {\n child = {\n pathParts: [...cursor.pathParts, segment],\n children: new Map(),\n functions: []\n };\n cursor.children.set(segment, child);\n }\n cursor = child;\n }\n cursor.functions.push(entry);\n }\n\n return root;\n}\n\nfunction renderGeneratedFunctionsInterface(\n functionEntries: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }>\n): string[] {\n const lines = [\n `/**`,\n ` * Type-safe runtime definitions for every function exported from \\`syncore/functions\\`.`,\n ` */`,\n `export interface SyncoreFunctionsRegistry extends SyncoreFunctionRegistry {`\n ];\n\n for (const entry of functionEntries\n .slice()\n .sort((left, right) =>\n `${left.pathParts.join(\"/\")}/${left.exportName}`.localeCompare(\n `${right.pathParts.join(\"/\")}/${right.exportName}`\n )\n )) {\n lines.push(\n ` /**`,\n ` * Runtime definition for the public Syncore ${entry.kind} \\`${entry.pathParts.join(\"/\")}/${entry.exportName}\\`.`,\n ` */`,\n ` readonly ${JSON.stringify(`${entry.pathParts.join(\"/\")}/${entry.exportName}`)}: typeof ${renderFunctionImportName(entry)};`\n );\n }\n\n lines.push(`}`);\n return [lines.join(\"\\n\")];\n}\n\nfunction renderApiInterfaceName(node: ApiModuleNode): string {\n if (node.pathParts.length === 0) {\n return \"SyncoreApi\";\n }\n return `SyncoreApi__${node.pathParts.map(toTypeNamePart).join(\"__\")}`;\n}\n\nfunction renderApiInterfaceDescription(node: ApiModuleNode): string {\n if (node.pathParts.length === 0) {\n return \"Type-safe references to every public Syncore function in this app.\";\n }\n\n if (node.children.size === 0) {\n return `Type-safe references to functions exported from \\`syncore/functions/${node.pathParts.join(\"/\")}.ts\\`.`;\n }\n\n return `Type-safe references to functions grouped under \\`syncore/functions/${node.pathParts.join(\"/\")}/*\\`.`;\n}\n\nfunction renderApiModulePropertyDescription(node: ApiModuleNode): string {\n if (node.children.size === 0) {\n return `Functions exported from \\`syncore/functions/${node.pathParts.join(\"/\")}.ts\\`.`;\n }\n return `Functions grouped under \\`syncore/functions/${node.pathParts.join(\"/\")}/*\\`.`;\n}\n\nfunction renderApiFunctionPropertyDescription(entry: {\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n}): string {\n return `Reference to the public Syncore ${entry.kind} \\`${entry.pathParts.join(\"/\")}/${entry.exportName}\\`.`;\n}\n\nfunction renderPropertyKey(key: string): string {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(key) ? key : JSON.stringify(key);\n}\n\nfunction toTypeNamePart(value: string): string {\n const sanitized = value.replace(/[^A-Za-z0-9_$]/g, \"_\");\n return /^[0-9]/u.test(sanitized) ? `_${sanitized}` : sanitized;\n}\n\nfunction renderFunctionImports(\n functionEntries: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }>,\n extension: \"\" | \".js\"\n): string[] {\n return functionEntries\n .slice()\n .sort((left, right) =>\n `${left.pathParts.join(\"/\")}/${left.exportName}`.localeCompare(\n `${right.pathParts.join(\"/\")}/${right.exportName}`\n )\n )\n .map((entry) => {\n const relativePath = `../functions/${entry.pathParts.join(\"/\")}${extension}`;\n return `import { ${entry.exportName} as ${renderFunctionImportName(entry)} } from ${JSON.stringify(relativePath)};`;\n });\n}\n\nfunction renderFunctionTypeImports(\n functionEntries: Array<{\n pathParts: string[];\n exportName: string;\n kind: \"query\" | \"mutation\" | \"action\";\n }>,\n extension: \"\" | \".js\"\n): string[] {\n return renderFunctionImports(functionEntries, extension).map((line) =>\n line.replace(/^import \\{/, \"import type {\")\n );\n}\n\nfunction renderFunctionImportName(entry: {\n pathParts: string[];\n exportName: string;\n}): string {\n return [\n ...entry.pathParts.map((segment) =>\n segment.replace(/[^a-zA-Z0-9_$]/g, \"_\")\n ),\n entry.exportName\n ].join(\"__\");\n}\n\nasync function loadProjectConfig(cwd: string): Promise<SyncoreConfig> {\n const filePath = path.join(cwd, \"syncore.config.ts\");\n const config = await loadDefaultExport<SyncoreConfig>(filePath);\n if (\n !config ||\n typeof config !== \"object\" ||\n typeof config.databasePath !== \"string\" ||\n typeof config.storageDirectory !== \"string\"\n ) {\n throw new Error(\n \"syncore.config.ts must export { databasePath, storageDirectory }.\"\n );\n }\n return config;\n}\n\nasync function loadProjectSchema(\n cwd: string\n): Promise<SyncoreSchema<Record<string, AnyTableDefinition>>> {\n const filePath = path.join(cwd, \"syncore\", \"schema.ts\");\n const schema =\n await loadDefaultExport<SyncoreSchema<Record<string, AnyTableDefinition>>>(\n filePath\n );\n if (\n !schema ||\n typeof schema !== \"object\" ||\n typeof schema.tableNames !== \"function\"\n ) {\n throw new Error(\"syncore/schema.ts must default export defineSchema(...).\");\n }\n return schema;\n}\n\nasync function loadDefaultExport<TValue>(filePath: string): Promise<TValue> {\n if (!(await fileExists(filePath))) {\n throw new Error(`Missing file: ${path.relative(process.cwd(), filePath)}`);\n }\n const moduleUrl = pathToFileURL(filePath).href;\n const loaded = (await tsImport(moduleUrl, {\n parentURL: import.meta.url\n })) as { default?: TValue };\n if (!(\"default\" in loaded)) {\n throw new Error(\n `File ${path.relative(process.cwd(), filePath)} must have a default export.`\n );\n }\n const resolvedDefault = unwrapDefaultExport(loaded.default);\n if (resolvedDefault === undefined) {\n throw new Error(\n `File ${path.relative(process.cwd(), filePath)} exported undefined.`\n );\n }\n return resolvedDefault;\n}\n\nasync function readStoredSnapshot(cwd: string): Promise<SchemaSnapshot | null> {\n const snapshotPath = path.join(\n cwd,\n \"syncore\",\n \"migrations\",\n migrationSnapshotFileName\n );\n if (!(await fileExists(snapshotPath))) {\n return null;\n }\n return parseSchemaSnapshot(await readFile(snapshotPath, \"utf8\"));\n}\n\nasync function writeStoredSnapshot(\n cwd: string,\n snapshot: SchemaSnapshot\n): Promise<void> {\n const migrationsDirectory = path.join(cwd, \"syncore\", \"migrations\");\n await mkdir(migrationsDirectory, { recursive: true });\n await writeFile(\n path.join(migrationsDirectory, migrationSnapshotFileName),\n `${JSON.stringify(snapshot, null, 2)}\\n`\n );\n}\n\nasync function getNextMigrationNumber(directory: string): Promise<number> {\n if (!(await fileExists(directory))) {\n return 1;\n }\n const migrationNumbers = (await readdir(directory))\n .map((name) => name.match(/^(\\d+)_.*\\.sql$/)?.[1])\n .filter((value): value is string => value !== undefined)\n .map((value) => Number.parseInt(value, 10));\n\n if (migrationNumbers.length === 0) {\n return 1;\n }\n return Math.max(...migrationNumbers) + 1;\n}\n\nasync function applyProjectMigrations(cwd: string): Promise<number> {\n const config = await loadProjectConfig(cwd);\n const databasePath = path.resolve(cwd, config.databasePath);\n const storageDirectory = path.resolve(cwd, config.storageDirectory);\n await mkdir(path.dirname(databasePath), { recursive: true });\n await mkdir(storageDirectory, { recursive: true });\n\n const database = new DatabaseSync(databasePath);\n database.exec(`\n CREATE TABLE IF NOT EXISTS \"_syncore_migrations\" (\n name TEXT PRIMARY KEY,\n applied_at TEXT NOT NULL\n );\n `);\n\n const migrationsDirectory = path.join(cwd, \"syncore\", \"migrations\");\n if (!(await fileExists(migrationsDirectory))) {\n database.close();\n return 0;\n }\n\n const appliedRows = database\n .prepare(`SELECT name FROM \"_syncore_migrations\" ORDER BY name ASC`)\n .all() as Array<{ name: string }>;\n const appliedNames = new Set(appliedRows.map((row) => row.name));\n const migrationFiles = (await readdir(migrationsDirectory))\n .filter((name) => /\\.sql$/i.test(name))\n .sort((left, right) => left.localeCompare(right));\n\n let appliedCount = 0;\n\n for (const fileName of migrationFiles) {\n if (appliedNames.has(fileName)) {\n continue;\n }\n\n const sql = await readFile(\n path.join(migrationsDirectory, fileName),\n \"utf8\"\n );\n database.exec(\"BEGIN\");\n try {\n applyMigrationSql(database, sql, fileName);\n database\n .prepare(\n `INSERT INTO \"_syncore_migrations\" (name, applied_at) VALUES (?, ?)`\n )\n .run(fileName, new Date().toISOString());\n database.exec(\"COMMIT\");\n appliedCount += 1;\n } catch (error) {\n database.exec(\"ROLLBACK\");\n database.close();\n throw error;\n }\n }\n\n database.close();\n return appliedCount;\n}\n\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await stat(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveFunctionImportExtension(\n cwd: string\n): Promise<\"\" | \".js\"> {\n const candidateConfigFiles = (await readdir(cwd, { withFileTypes: true }))\n .filter((entry) => entry.isFile() && /^tsconfig.*\\.json$/i.test(entry.name))\n .map((entry) => path.join(cwd, entry.name))\n .sort((left, right) => left.localeCompare(right));\n\n for (const filePath of candidateConfigFiles) {\n try {\n const rawConfig = JSON.parse(await readFile(filePath, \"utf8\")) as {\n compilerOptions?: {\n module?: string;\n moduleResolution?: string;\n };\n };\n const moduleResolution =\n rawConfig.compilerOptions?.moduleResolution?.toLowerCase();\n const moduleTarget = rawConfig.compilerOptions?.module?.toLowerCase();\n if (moduleResolution === \"nodenext\" || moduleTarget === \"nodenext\") {\n return \".js\";\n }\n } catch {\n continue;\n }\n }\n\n return \"\";\n}\n\nfunction formatError(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n\nasync function isLocalPortInUse(port: number): Promise<boolean> {\n return await new Promise((resolve) => {\n const socket = connectToNet({ host: \"127.0.0.1\", port });\n socket.once(\"connect\", () => {\n socket.end();\n resolve(true);\n });\n socket.once(\"error\", () => {\n resolve(false);\n });\n });\n}\n\nfunction slugify(value: string): string {\n const slug = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n return slug || \"auto\";\n}\n\nfunction applyMigrationSql(\n database: DatabaseSync,\n sql: string,\n fileName: string\n): void {\n const statements = sql\n .split(/;\\s*(?:\\r?\\n|$)/)\n .map((statement) => statement.trim())\n .filter(Boolean);\n\n for (const statement of statements) {\n try {\n database.exec(statement);\n } catch (error) {\n if (isUnsupportedFts5Statement(statement, error)) {\n console.warn(\n `Skipping FTS5 statement in ${fileName} because this SQLite build does not include FTS5 support.`\n );\n continue;\n }\n throw error;\n }\n }\n}\n\nasync function startDevHub(options: {\n cwd: string;\n template: SyncoreTemplateName;\n}): Promise<void> {\n const dashboardPort = resolvePortFromEnv(\"SYNCORE_DASHBOARD_PORT\", 4310);\n const devtoolsPort = resolvePortFromEnv(\"SYNCORE_DEVTOOLS_PORT\", 4311);\n await runDevProjectBootstrap(options.cwd, options.template);\n await setupDevProjectWatch(options.cwd, options.template);\n\n if (await isLocalPortInUse(devtoolsPort)) {\n console.log(\n `Syncore devtools hub already running at ws://127.0.0.1:${devtoolsPort}. Reusing existing hub/dashboard.`\n );\n return;\n }\n\n const httpServer = createServer((_request, response) => {\n response.writeHead(200, { \"content-type\": \"application/json\" });\n response.end(JSON.stringify({ ok: true, wsPort: devtoolsPort }));\n });\n const websocketServer = new WebSocketServer({ server: httpServer });\n const latestSnapshots = new Map<string, SyncoreDevtoolsMessage>();\n const runtimeSockets = new Map<string, WebSocket>();\n const socketRuntimeIds = new Map<WebSocket, Set<string>>();\n const dashboardSockets = new Set<WebSocket>();\n const hello: SyncoreDevtoolsMessage = {\n type: \"hello\",\n runtimeId: \"syncore-dev-hub\",\n platform: \"dev\"\n };\n\n websocketServer.on(\"connection\", (socket: WebSocket) => {\n dashboardSockets.add(socket);\n socket.send(JSON.stringify(hello));\n for (const snapshot of latestSnapshots.values()) {\n socket.send(JSON.stringify(snapshot));\n }\n\n socket.on(\"message\", (payload) => {\n const rawPayload = decodeWebSocketPayload(payload);\n if (rawPayload.length === 0) {\n return;\n }\n const message = JSON.parse(rawPayload) as\n | SyncoreDevtoolsMessage\n | (SyncoreDevtoolsRequest & { targetRuntimeId?: string });\n if (message.type === \"ping\") {\n socket.send(\n JSON.stringify({ type: \"pong\" } satisfies SyncoreDevtoolsMessage)\n );\n return;\n }\n if (message.type === \"request\") {\n const targetRuntimeId = message.targetRuntimeId;\n if (!targetRuntimeId) {\n return;\n }\n const target = runtimeSockets.get(targetRuntimeId);\n if (target && target.readyState === WebSocket.OPEN) {\n target.send(JSON.stringify(message));\n }\n return;\n }\n if (message.type === \"hello\") {\n dashboardSockets.delete(socket);\n runtimeSockets.set(message.runtimeId, socket);\n const runtimeIds = socketRuntimeIds.get(socket) ?? new Set<string>();\n runtimeIds.add(message.runtimeId);\n socketRuntimeIds.set(socket, runtimeIds);\n for (const client of dashboardSockets) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(JSON.stringify(message));\n }\n }\n return;\n }\n if (message.type === \"snapshot\") {\n latestSnapshots.set(message.snapshot.runtimeId, message);\n dashboardSockets.delete(socket);\n runtimeSockets.set(message.snapshot.runtimeId, socket);\n const runtimeIds = socketRuntimeIds.get(socket) ?? new Set<string>();\n runtimeIds.add(message.snapshot.runtimeId);\n socketRuntimeIds.set(socket, runtimeIds);\n }\n\n const encoded = JSON.stringify(message);\n if (message.type === \"response\") {\n for (const client of dashboardSockets) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(encoded);\n }\n }\n return;\n }\n for (const client of dashboardSockets) {\n if (client === socket || client.readyState !== WebSocket.OPEN) {\n continue;\n }\n client.send(encoded);\n }\n });\n\n socket.on(\"close\", () => {\n dashboardSockets.delete(socket);\n const runtimeIds = socketRuntimeIds.get(socket);\n if (!runtimeIds) {\n return;\n }\n for (const runtimeId of runtimeIds) {\n latestSnapshots.delete(runtimeId);\n if (runtimeSockets.get(runtimeId) === socket) {\n runtimeSockets.delete(runtimeId);\n }\n }\n socketRuntimeIds.delete(socket);\n });\n });\n\n const heartbeat = setInterval(() => {\n const event: SyncoreDevtoolsMessage = {\n type: \"event\",\n event: {\n type: \"log\",\n runtimeId: \"syncore-dev-hub\",\n level: \"info\",\n message: \"Syncore devtools hub is alive.\",\n timestamp: Date.now()\n }\n };\n const payload = JSON.stringify(event);\n for (const client of websocketServer.clients) {\n client.send(payload);\n }\n }, 4000);\n\n httpServer.on(\"error\", (error) => {\n console.error(`Syncore devtools hub failed: ${formatError(error)}`);\n process.exit(1);\n });\n\n httpServer.listen(devtoolsPort, \"127.0.0.1\", () => {\n void (async () => {\n console.log(`Syncore devtools hub: ws://127.0.0.1:${devtoolsPort}`);\n console.log(\n `Electron/Node runtimes: set devtoolsUrl to ws://127.0.0.1:${devtoolsPort}.`\n );\n console.log(\n `Web/Next apps: connect the dashboard or worker bridge to ws://127.0.0.1:${devtoolsPort}.`\n );\n console.log(\n \"Expo apps: use the same hub URL through LAN or adb reverse while developing.\"\n );\n const dashboardRoot = path.resolve(\n CORE_PACKAGE_ROOT,\n \"..\",\n \"..\",\n \"apps\",\n \"dashboard\"\n );\n if (await fileExists(path.join(dashboardRoot, \"vite.config.ts\"))) {\n try {\n const viteModule = await import(\"vite\");\n const server = await viteModule.createServer({\n configFile: path.join(dashboardRoot, \"vite.config.ts\"),\n root: dashboardRoot,\n server: {\n port: dashboardPort\n }\n });\n await server.listen();\n console.log(`Dashboard shell: http://127.0.0.1:${dashboardPort}`);\n } catch (error) {\n console.log(\n `Dashboard source not started automatically: ${formatError(error)}`\n );\n }\n }\n })();\n });\n\n const close = () => {\n clearInterval(heartbeat);\n websocketServer.close();\n httpServer.close();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", close);\n process.on(\"SIGTERM\", close);\n}\n\nasync function setupDevProjectWatch(\n cwd: string,\n template: SyncoreTemplateName\n): Promise<void> {\n const snapshot = await createDevWatchSnapshot(cwd);\n if (snapshot.size === 0) {\n return;\n }\n\n console.log(\"Watching syncore/ for changes.\");\n let lastSnapshot = snapshot;\n const interval = setInterval(() => {\n void (async () => {\n const nextSnapshot = await createDevWatchSnapshot(cwd);\n if (!areDevWatchSnapshotsEqual(lastSnapshot, nextSnapshot)) {\n lastSnapshot = nextSnapshot;\n scheduleDevProjectBootstrap(cwd, template);\n }\n })();\n }, 500);\n\n const dispose = () => {\n clearInterval(interval);\n };\n\n process.once(\"SIGINT\", dispose);\n process.once(\"SIGTERM\", dispose);\n}\n\nfunction scheduleDevProjectBootstrap(\n cwd: string,\n template: SyncoreTemplateName\n): void {\n if (pendingDevBootstrap) {\n clearTimeout(pendingDevBootstrap);\n }\n pendingDevBootstrap = setTimeout(() => {\n void runDevProjectBootstrap(cwd, template);\n }, 150);\n}\n\nasync function runDevProjectBootstrap(\n cwd: string,\n template: SyncoreTemplateName\n): Promise<void> {\n if (devBootstrapInFlight) {\n scheduleDevProjectBootstrap(cwd, template);\n return;\n }\n\n devBootstrapInFlight = true;\n try {\n await ensureProjectScaffolded(cwd, template);\n await runCodegen(cwd);\n const schema = await loadProjectSchema(cwd);\n const currentSnapshot = createSchemaSnapshot(schema);\n const storedSnapshot = await readStoredSnapshot(cwd);\n const plan = diffSchemaSnapshots(storedSnapshot, currentSnapshot);\n\n if (plan.destructiveChanges.length > 0) {\n console.error(\"Syncore dev blocked by destructive schema changes:\");\n for (const destructiveChange of plan.destructiveChanges) {\n console.error(`- ${destructiveChange}`);\n }\n return;\n }\n\n if (storedSnapshot?.hash !== currentSnapshot.hash) {\n await writeStoredSnapshot(cwd, currentSnapshot);\n if (plan.statements.length > 0 || plan.warnings.length > 0) {\n console.log(\n `Schema snapshot updated (${plan.statements.length} statement(s), ${plan.warnings.length} warning(s)).`\n );\n } else {\n console.log(\"Schema snapshot updated.\");\n }\n }\n\n for (const warning of plan.warnings) {\n console.warn(`Syncore dev warning: ${warning}`);\n }\n\n const appliedCount = await applyProjectMigrations(cwd);\n console.log(\n `Syncore dev is ready. Codegen refreshed; ${appliedCount} migration(s) applied.`\n );\n } catch (error) {\n console.error(`Syncore dev bootstrap failed: ${formatError(error)}`);\n } finally {\n devBootstrapInFlight = false;\n }\n}\n\nasync function createDevWatchSnapshot(\n cwd: string\n): Promise<Map<string, number>> {\n const snapshot = new Map<string, number>();\n const filesToCheck = [\n path.join(cwd, \"syncore.config.ts\"),\n path.join(cwd, \"syncore\", \"schema.ts\"),\n path.join(cwd, \".gitignore\"),\n path.join(cwd, \"package.json\")\n ];\n for (const file of filesToCheck) {\n if (await fileExists(file)) {\n const info = await stat(file);\n snapshot.set(file, info.mtimeMs);\n }\n }\n\n for (const directory of [\n path.join(cwd, \"syncore\", \"functions\"),\n path.join(cwd, \"syncore\", \"migrations\")\n ]) {\n for (const file of await listFilesRecursively(directory)) {\n const info = await stat(file);\n snapshot.set(file, info.mtimeMs);\n }\n }\n\n return snapshot;\n}\n\nasync function listFilesRecursively(directory: string): Promise<string[]> {\n if (!(await fileExists(directory))) {\n return [];\n }\n\n const entries = await readdir(directory, { withFileTypes: true });\n const files = await Promise.all(\n entries.map(async (entry) => {\n const fullPath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n return listFilesRecursively(fullPath);\n }\n if (entry.isFile()) {\n return [fullPath];\n }\n return [];\n })\n );\n\n return files.flat().sort((left, right) => left.localeCompare(right));\n}\n\nfunction areDevWatchSnapshotsEqual(\n left: Map<string, number>,\n right: Map<string, number>\n): boolean {\n if (left.size !== right.size) {\n return false;\n }\n for (const [filePath, leftTimestamp] of left) {\n if (right.get(filePath) !== leftTimestamp) {\n return false;\n }\n }\n return true;\n}\n\nfunction decodeWebSocketPayload(\n payload: string | Buffer | ArrayBuffer | Buffer[]\n): string {\n if (typeof payload === \"string\") {\n return payload;\n }\n if (payload instanceof Buffer) {\n return payload.toString(\"utf8\");\n }\n if (Array.isArray(payload)) {\n return Buffer.concat(payload).toString(\"utf8\");\n }\n if (payload instanceof ArrayBuffer) {\n return Buffer.from(payload).toString(\"utf8\");\n }\n return Buffer.from(\n payload.buffer,\n payload.byteOffset,\n payload.byteLength\n ).toString(\"utf8\");\n}\n\nfunction isUnsupportedFts5Statement(\n statement: string,\n error: unknown\n): boolean {\n if (!/using\\s+fts5/i.test(statement)) {\n return false;\n }\n return error instanceof Error && /fts5/i.test(error.message);\n}\n\nfunction unwrapDefaultExport<TValue>(value: TValue): TValue {\n if (\n value &&\n typeof value === \"object\" &&\n \"default\" in (value as Record<string, unknown>) &&\n (value as Record<string, unknown>).default !== undefined\n ) {\n return unwrapDefaultExport(\n (value as Record<string, unknown>).default as TValue\n );\n }\n return value;\n}\n\nfunction resolvePortFromEnv(\n environmentVariable: string,\n fallback: number\n): number {\n const rawValue = process.env[environmentVariable];\n if (!rawValue) {\n return fallback;\n }\n\n const parsed = Number.parseInt(rawValue, 10);\n if (Number.isNaN(parsed) || parsed <= 0) {\n throw new Error(\n `${environmentVariable} must be a positive integer when provided.`\n );\n }\n\n return parsed;\n}\n\nfunction isCliEntryPoint(): boolean {\n const entryPath = process.argv[1];\n if (!entryPath) {\n return false;\n }\n return (\n path.resolve(entryPath) === path.resolve(fileURLToPath(import.meta.url))\n );\n}\n\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, sortValue(nested)])\n );\n }\n return value;\n}\n\nfunction quoteIdentifier(identifier: string): string {\n return `\"${identifier.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction toSearchValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value === null || value === undefined) {\n return \"\";\n }\n if (\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n typeof value === \"bigint\"\n ) {\n return String(value);\n }\n return stableStringify(value);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SyncoreRequestPayload, SyncoreResponsePayload } from "../../../devtools-protocol/src/index.js";
|
|
2
|
+
|
|
3
|
+
//#region ../core/src/runtime/devtools.d.ts
|
|
4
|
+
type DevtoolsRequestHandler = (payload: SyncoreRequestPayload) => Promise<SyncoreResponsePayload>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { DevtoolsRequestHandler };
|
|
7
|
+
//# sourceMappingURL=devtools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.d.ts","names":[],"sources":["../../../../../core/src/runtime/devtools.ts"],"mappings":";;;KAuBY,sBAAA,IACV,OAAA,EAAS,qBAAA,KACN,OAAA,CAAQ,sBAAA"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { describeValidator } from "../../../schema/src/validators.js";
|
|
2
|
+
import { createFunctionReference } from "./runtime.js";
|
|
3
|
+
//#region ../core/src/runtime/devtools.ts
|
|
4
|
+
function createDevtoolsRequestHandler(deps) {
|
|
5
|
+
const { driver, schema, functions, runtime } = deps;
|
|
6
|
+
return async (payload) => {
|
|
7
|
+
switch (payload.kind) {
|
|
8
|
+
case "fn.list": return {
|
|
9
|
+
kind: "fn.list.result",
|
|
10
|
+
functions: Object.entries(functions).filter((entry) => entry[1] !== void 0).map(([name, fn]) => {
|
|
11
|
+
const def = {
|
|
12
|
+
name,
|
|
13
|
+
type: fn.kind,
|
|
14
|
+
file: inferFileFromFunctionName(name)
|
|
15
|
+
};
|
|
16
|
+
const argsDesc = describeValidator(fn.argsValidator);
|
|
17
|
+
if (argsDesc.kind === "object") def.args = argsDesc.shape;
|
|
18
|
+
return def;
|
|
19
|
+
})
|
|
20
|
+
};
|
|
21
|
+
case "fn.run": {
|
|
22
|
+
const start = performance.now();
|
|
23
|
+
try {
|
|
24
|
+
let result;
|
|
25
|
+
switch (payload.functionType) {
|
|
26
|
+
case "query": {
|
|
27
|
+
const ref = createFunctionReference("query", payload.functionName);
|
|
28
|
+
result = await runtime.runQuery(ref, payload.args);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case "mutation": {
|
|
32
|
+
const ref = createFunctionReference("mutation", payload.functionName);
|
|
33
|
+
result = await runtime.runMutation(ref, payload.args);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case "action": {
|
|
37
|
+
const ref = createFunctionReference("action", payload.functionName);
|
|
38
|
+
result = await runtime.runAction(ref, payload.args);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
kind: "fn.run.result",
|
|
44
|
+
result,
|
|
45
|
+
durationMs: performance.now() - start
|
|
46
|
+
};
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return {
|
|
49
|
+
kind: "fn.run.result",
|
|
50
|
+
error: err instanceof Error ? err.message : String(err),
|
|
51
|
+
durationMs: performance.now() - start
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
case "schema.get": {
|
|
56
|
+
const tableNames = schema.tableNames();
|
|
57
|
+
return {
|
|
58
|
+
kind: "schema.result",
|
|
59
|
+
tables: await Promise.all(tableNames.map(async (name) => {
|
|
60
|
+
const table = schema.getTable(name);
|
|
61
|
+
const validatorDesc = describeValidator(table.validator);
|
|
62
|
+
const fields = validatorDesc.kind === "object" ? Object.entries(validatorDesc.shape).map(([fieldName, fieldDesc]) => {
|
|
63
|
+
const desc = fieldDesc;
|
|
64
|
+
const optional = desc.kind === "optional";
|
|
65
|
+
return {
|
|
66
|
+
name: fieldName,
|
|
67
|
+
type: optional ? desc.inner?.kind ?? "any" : desc.kind,
|
|
68
|
+
optional
|
|
69
|
+
};
|
|
70
|
+
}) : [];
|
|
71
|
+
fields.unshift({
|
|
72
|
+
name: "_id",
|
|
73
|
+
type: "string",
|
|
74
|
+
optional: false
|
|
75
|
+
}, {
|
|
76
|
+
name: "_creationTime",
|
|
77
|
+
type: "number",
|
|
78
|
+
optional: false
|
|
79
|
+
});
|
|
80
|
+
let documentCount = 0;
|
|
81
|
+
try {
|
|
82
|
+
const countRow = await driver.get(`SELECT COUNT(*) as count FROM "${name}"`);
|
|
83
|
+
if (countRow) documentCount = countRow.count;
|
|
84
|
+
} catch {}
|
|
85
|
+
return {
|
|
86
|
+
name,
|
|
87
|
+
fields,
|
|
88
|
+
indexes: table.indexes.map((idx) => ({
|
|
89
|
+
name: idx.name,
|
|
90
|
+
fields: idx.fields,
|
|
91
|
+
unique: false
|
|
92
|
+
})),
|
|
93
|
+
documentCount
|
|
94
|
+
};
|
|
95
|
+
}))
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
case "data.query": try {
|
|
99
|
+
let sql = `SELECT _id, _creationTime, _json FROM "${payload.table}"`;
|
|
100
|
+
const params = [];
|
|
101
|
+
if (payload.filters && payload.filters.length > 0) {
|
|
102
|
+
const conditions = payload.filters.map((filter) => {
|
|
103
|
+
const op = filterOperatorToSql(filter.operator);
|
|
104
|
+
params.push(normalizeFilterValue(filter));
|
|
105
|
+
return `json_extract(_json, '$.${filter.field}') ${op} ?`;
|
|
106
|
+
});
|
|
107
|
+
sql += ` WHERE ${conditions.join(" AND ")}`;
|
|
108
|
+
}
|
|
109
|
+
sql += " ORDER BY _creationTime DESC";
|
|
110
|
+
if (payload.limit) sql += ` LIMIT ${payload.limit}`;
|
|
111
|
+
return {
|
|
112
|
+
kind: "data.result",
|
|
113
|
+
rows: (await driver.all(sql, params)).map((row) => ({
|
|
114
|
+
_id: row._id,
|
|
115
|
+
_creationTime: row._creationTime,
|
|
116
|
+
...JSON.parse(row._json)
|
|
117
|
+
})),
|
|
118
|
+
totalCount: (await driver.get(`SELECT COUNT(*) as count FROM "${payload.table}"`))?.count ?? 0
|
|
119
|
+
};
|
|
120
|
+
} catch (err) {
|
|
121
|
+
return {
|
|
122
|
+
kind: "error",
|
|
123
|
+
message: err instanceof Error ? err.message : String(err)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
case "data.insert": try {
|
|
127
|
+
const id = generateId();
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
await driver.run(`INSERT INTO "${payload.table}" (_id, _creationTime, _json) VALUES (?, ?, ?)`, [
|
|
130
|
+
id,
|
|
131
|
+
now,
|
|
132
|
+
JSON.stringify(payload.document)
|
|
133
|
+
]);
|
|
134
|
+
return {
|
|
135
|
+
kind: "data.mutate.result",
|
|
136
|
+
success: true,
|
|
137
|
+
id
|
|
138
|
+
};
|
|
139
|
+
} catch (err) {
|
|
140
|
+
return {
|
|
141
|
+
kind: "data.mutate.result",
|
|
142
|
+
success: false,
|
|
143
|
+
error: err instanceof Error ? err.message : String(err)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
case "data.patch": try {
|
|
147
|
+
const existing = await driver.get(`SELECT _json FROM "${payload.table}" WHERE _id = ?`, [payload.id]);
|
|
148
|
+
if (!existing) return {
|
|
149
|
+
kind: "data.mutate.result",
|
|
150
|
+
success: false,
|
|
151
|
+
error: `Document ${payload.id} not found`
|
|
152
|
+
};
|
|
153
|
+
const doc = {
|
|
154
|
+
...JSON.parse(existing._json),
|
|
155
|
+
...payload.fields
|
|
156
|
+
};
|
|
157
|
+
await driver.run(`UPDATE "${payload.table}" SET _json = ? WHERE _id = ?`, [JSON.stringify(doc), payload.id]);
|
|
158
|
+
return {
|
|
159
|
+
kind: "data.mutate.result",
|
|
160
|
+
success: true,
|
|
161
|
+
id: payload.id
|
|
162
|
+
};
|
|
163
|
+
} catch (err) {
|
|
164
|
+
return {
|
|
165
|
+
kind: "data.mutate.result",
|
|
166
|
+
success: false,
|
|
167
|
+
error: err instanceof Error ? err.message : String(err)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
case "data.delete": try {
|
|
171
|
+
await driver.run(`DELETE FROM "${payload.table}" WHERE _id = ?`, [payload.id]);
|
|
172
|
+
return {
|
|
173
|
+
kind: "data.mutate.result",
|
|
174
|
+
success: true
|
|
175
|
+
};
|
|
176
|
+
} catch (err) {
|
|
177
|
+
return {
|
|
178
|
+
kind: "data.mutate.result",
|
|
179
|
+
success: false,
|
|
180
|
+
error: err instanceof Error ? err.message : String(err)
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
case "sql.execute": try {
|
|
184
|
+
const trimmed = payload.query.trim().toUpperCase();
|
|
185
|
+
if (trimmed.startsWith("SELECT") || trimmed.startsWith("PRAGMA") || trimmed.startsWith("EXPLAIN")) {
|
|
186
|
+
const rows = await driver.all(payload.query);
|
|
187
|
+
const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
188
|
+
return {
|
|
189
|
+
kind: "sql.result",
|
|
190
|
+
columns,
|
|
191
|
+
rows: rows.map((row) => columns.map((col) => row[col])),
|
|
192
|
+
rowsAffected: 0
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
kind: "sql.result",
|
|
197
|
+
columns: [],
|
|
198
|
+
rows: [],
|
|
199
|
+
rowsAffected: (await driver.run(payload.query)).changes
|
|
200
|
+
};
|
|
201
|
+
} catch (err) {
|
|
202
|
+
return {
|
|
203
|
+
kind: "sql.result",
|
|
204
|
+
columns: [],
|
|
205
|
+
rows: [],
|
|
206
|
+
rowsAffected: 0,
|
|
207
|
+
error: err instanceof Error ? err.message : String(err)
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
case "scheduler.list": try {
|
|
211
|
+
return {
|
|
212
|
+
kind: "scheduler.list.result",
|
|
213
|
+
jobs: (await driver.all(`SELECT * FROM "_scheduled_functions" ORDER BY run_at DESC LIMIT 200`)).map((row) => {
|
|
214
|
+
const job = {
|
|
215
|
+
id: row.id,
|
|
216
|
+
functionName: row.function_name,
|
|
217
|
+
args: JSON.parse(row.args_json),
|
|
218
|
+
scheduledAt: row.created_at,
|
|
219
|
+
runAt: row.run_at,
|
|
220
|
+
status: mapJobStatus(row.status)
|
|
221
|
+
};
|
|
222
|
+
if (row.schedule_json) try {
|
|
223
|
+
const schedule = JSON.parse(row.schedule_json);
|
|
224
|
+
if (schedule.cron) job.cronSchedule = schedule.cron;
|
|
225
|
+
} catch {}
|
|
226
|
+
if (row.status === "completed" || row.status === "failed") job.completedAt = row.updated_at;
|
|
227
|
+
return job;
|
|
228
|
+
})
|
|
229
|
+
};
|
|
230
|
+
} catch {
|
|
231
|
+
return {
|
|
232
|
+
kind: "scheduler.list.result",
|
|
233
|
+
jobs: []
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
case "scheduler.cancel": try {
|
|
237
|
+
await driver.run(`UPDATE "_scheduled_functions" SET status = 'cancelled', updated_at = ? WHERE id = ? AND status = 'scheduled'`, [Date.now(), payload.jobId]);
|
|
238
|
+
return {
|
|
239
|
+
kind: "scheduler.cancel.result",
|
|
240
|
+
success: true
|
|
241
|
+
};
|
|
242
|
+
} catch (err) {
|
|
243
|
+
return {
|
|
244
|
+
kind: "scheduler.cancel.result",
|
|
245
|
+
success: false,
|
|
246
|
+
error: err instanceof Error ? err.message : String(err)
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
default: return {
|
|
250
|
+
kind: "error",
|
|
251
|
+
message: `Unknown request kind: ${payload.kind}`
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function inferFileFromFunctionName(name) {
|
|
257
|
+
const parts = name.split(":");
|
|
258
|
+
if (parts.length > 1) return parts[0] + ".ts";
|
|
259
|
+
return "unknown";
|
|
260
|
+
}
|
|
261
|
+
function normalizeFilterValue(filter) {
|
|
262
|
+
switch (filter.operator) {
|
|
263
|
+
case "contains": return `%${String(filter.value)}%`;
|
|
264
|
+
case "startsWith": return `${String(filter.value)}%`;
|
|
265
|
+
default: return filter.value;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function filterOperatorToSql(op) {
|
|
269
|
+
switch (op) {
|
|
270
|
+
case "eq": return "=";
|
|
271
|
+
case "neq": return "!=";
|
|
272
|
+
case "gt": return ">";
|
|
273
|
+
case "gte": return ">=";
|
|
274
|
+
case "lt": return "<";
|
|
275
|
+
case "lte": return "<=";
|
|
276
|
+
case "contains": return "LIKE";
|
|
277
|
+
case "startsWith": return "LIKE";
|
|
278
|
+
default: return "=";
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function mapJobStatus(status) {
|
|
282
|
+
switch (status) {
|
|
283
|
+
case "scheduled": return "pending";
|
|
284
|
+
case "completed": return "completed";
|
|
285
|
+
case "failed": return "failed";
|
|
286
|
+
case "cancelled":
|
|
287
|
+
case "skipped": return "cancelled";
|
|
288
|
+
default: return "pending";
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function generateId() {
|
|
292
|
+
const chars = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
293
|
+
let id = "";
|
|
294
|
+
for (let i = 0; i < 24; i++) id += chars[Math.floor(Math.random() * 36)];
|
|
295
|
+
return id;
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
export { createDevtoolsRequestHandler };
|
|
299
|
+
|
|
300
|
+
//# sourceMappingURL=devtools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.js","names":[],"sources":["../../../../../core/src/runtime/devtools.ts"],"sourcesContent":["import type {\n DataFilter,\n SchedulerJob,\n SyncoreRequestPayload,\n SyncoreResponsePayload\n} from \"@syncore/devtools-protocol\";\nimport { describeValidator } from \"@syncore/schema\";\nimport type { TableDefinition, Validator } from \"@syncore/schema\";\nimport type {\n AnySyncoreSchema,\n SyncoreRuntimeOptions,\n SyncoreSqlDriver\n} from \"./runtime.js\";\nimport { createFunctionReference } from \"./runtime.js\";\nimport type { SyncoreRuntime } from \"./runtime.js\";\n\nexport interface DevtoolsRequestHandlerDeps {\n driver: SyncoreSqlDriver;\n schema: AnySyncoreSchema;\n functions: SyncoreRuntimeOptions<AnySyncoreSchema>[\"functions\"];\n runtime: SyncoreRuntime<AnySyncoreSchema>;\n}\n\nexport type DevtoolsRequestHandler = (\n payload: SyncoreRequestPayload\n) => Promise<SyncoreResponsePayload>;\n\nexport function createDevtoolsRequestHandler(\n deps: DevtoolsRequestHandlerDeps\n): DevtoolsRequestHandler {\n const { driver, schema, functions, runtime } = deps;\n\n return async (payload): Promise<SyncoreResponsePayload> => {\n switch (payload.kind) {\n case \"fn.list\": {\n const defs = Object.entries(functions)\n .filter(\n (entry): entry is [string, NonNullable<(typeof entry)[1]>] =>\n entry[1] !== undefined\n )\n .map(([name, fn]) => {\n const def: {\n name: string;\n type: \"query\" | \"mutation\" | \"action\";\n file: string;\n args?: Record<string, unknown>;\n } = {\n name,\n type: fn.kind,\n file: inferFileFromFunctionName(name)\n };\n const argsDesc = describeValidator(fn.argsValidator);\n if (argsDesc.kind === \"object\") {\n def.args = argsDesc.shape as Record<string, unknown>;\n }\n return def;\n });\n return { kind: \"fn.list.result\", functions: defs };\n }\n\n case \"fn.run\": {\n const start = performance.now();\n try {\n let result: unknown;\n switch (payload.functionType) {\n case \"query\": {\n const ref = createFunctionReference(\n \"query\",\n payload.functionName\n );\n result = await runtime.runQuery(ref, payload.args);\n break;\n }\n case \"mutation\": {\n const ref = createFunctionReference(\n \"mutation\",\n payload.functionName\n );\n result = await runtime.runMutation(ref, payload.args);\n break;\n }\n case \"action\": {\n const ref = createFunctionReference(\n \"action\",\n payload.functionName\n );\n result = await runtime.runAction(ref, payload.args);\n break;\n }\n }\n return {\n kind: \"fn.run.result\",\n result,\n durationMs: performance.now() - start\n };\n } catch (err) {\n return {\n kind: \"fn.run.result\",\n error: err instanceof Error ? err.message : String(err),\n durationMs: performance.now() - start\n };\n }\n }\n\n case \"schema.get\": {\n const tableNames = schema.tableNames();\n const tables = await Promise.all(\n tableNames.map(async (name) => {\n const table = schema.getTable(name) as TableDefinition<\n Validator<unknown>\n >;\n const validatorDesc = describeValidator(table.validator);\n const fields =\n validatorDesc.kind === \"object\"\n ? Object.entries(validatorDesc.shape).map(\n ([fieldName, fieldDesc]) => {\n const desc = fieldDesc as {\n kind: string;\n inner?: { kind: string };\n };\n const optional = desc.kind === \"optional\";\n const innerKind = optional\n ? (desc.inner?.kind ?? \"any\")\n : desc.kind;\n return {\n name: fieldName,\n type: innerKind,\n optional\n };\n }\n )\n : [];\n\n fields.unshift(\n { name: \"_id\", type: \"string\", optional: false },\n { name: \"_creationTime\", type: \"number\", optional: false }\n );\n\n let documentCount = 0;\n try {\n const countRow = await driver.get<{ count: number }>(\n `SELECT COUNT(*) as count FROM \"${name}\"`\n );\n if (countRow) {\n documentCount = countRow.count;\n }\n } catch {\n /* table may not exist yet */\n }\n\n return {\n name,\n fields,\n indexes: table.indexes.map(\n (idx: { name: string; fields: string[] }) => ({\n name: idx.name,\n fields: idx.fields,\n unique: false\n })\n ),\n documentCount\n };\n })\n );\n return { kind: \"schema.result\", tables };\n }\n\n case \"data.query\": {\n try {\n let sql = `SELECT _id, _creationTime, _json FROM \"${payload.table}\"`;\n const params: unknown[] = [];\n\n if (payload.filters && payload.filters.length > 0) {\n const conditions = payload.filters.map((filter) => {\n const op = filterOperatorToSql(filter.operator);\n params.push(normalizeFilterValue(filter));\n return `json_extract(_json, '$.${filter.field}') ${op} ?`;\n });\n sql += ` WHERE ${conditions.join(\" AND \")}`;\n }\n\n sql += \" ORDER BY _creationTime DESC\";\n if (payload.limit) {\n sql += ` LIMIT ${payload.limit}`;\n }\n\n const rawRows = await driver.all<{\n _id: string;\n _creationTime: number;\n _json: string;\n }>(sql, params);\n\n const rows = rawRows.map((row) => ({\n _id: row._id,\n _creationTime: row._creationTime,\n ...(JSON.parse(row._json) as Record<string, unknown>)\n }));\n\n const countRow = await driver.get<{ count: number }>(\n `SELECT COUNT(*) as count FROM \"${payload.table}\"`\n );\n\n return {\n kind: \"data.result\",\n rows,\n totalCount: countRow?.count ?? 0\n };\n } catch (err) {\n return {\n kind: \"error\",\n message: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n case \"data.insert\": {\n try {\n const id = generateId();\n const now = Date.now();\n await driver.run(\n `INSERT INTO \"${payload.table}\" (_id, _creationTime, _json) VALUES (?, ?, ?)`,\n [id, now, JSON.stringify(payload.document)]\n );\n return { kind: \"data.mutate.result\", success: true, id };\n } catch (err) {\n return {\n kind: \"data.mutate.result\",\n success: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n case \"data.patch\": {\n try {\n const existing = await driver.get<{ _json: string }>(\n `SELECT _json FROM \"${payload.table}\" WHERE _id = ?`,\n [payload.id]\n );\n if (!existing) {\n return {\n kind: \"data.mutate.result\",\n success: false,\n error: `Document ${payload.id} not found`\n };\n }\n const doc = {\n ...(JSON.parse(existing._json) as Record<string, unknown>),\n ...payload.fields\n };\n await driver.run(\n `UPDATE \"${payload.table}\" SET _json = ? WHERE _id = ?`,\n [JSON.stringify(doc), payload.id]\n );\n return { kind: \"data.mutate.result\", success: true, id: payload.id };\n } catch (err) {\n return {\n kind: \"data.mutate.result\",\n success: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n case \"data.delete\": {\n try {\n await driver.run(`DELETE FROM \"${payload.table}\" WHERE _id = ?`, [\n payload.id\n ]);\n return { kind: \"data.mutate.result\", success: true };\n } catch (err) {\n return {\n kind: \"data.mutate.result\",\n success: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n case \"sql.execute\": {\n try {\n const trimmed = payload.query.trim().toUpperCase();\n if (\n trimmed.startsWith(\"SELECT\") ||\n trimmed.startsWith(\"PRAGMA\") ||\n trimmed.startsWith(\"EXPLAIN\")\n ) {\n const rows = await driver.all<Record<string, unknown>>(\n payload.query\n );\n const columns = rows.length > 0 ? Object.keys(rows[0]!) : [];\n return {\n kind: \"sql.result\",\n columns,\n rows: rows.map((row) => columns.map((col) => row[col])),\n rowsAffected: 0\n };\n }\n\n const result = await driver.run(payload.query);\n return {\n kind: \"sql.result\",\n columns: [],\n rows: [],\n rowsAffected: result.changes\n };\n } catch (err) {\n return {\n kind: \"sql.result\",\n columns: [],\n rows: [],\n rowsAffected: 0,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n case \"scheduler.list\": {\n try {\n const rows = await driver.all<{\n id: string;\n function_name: string;\n args_json: string;\n status: string;\n run_at: number;\n created_at: number;\n updated_at: number;\n schedule_json: string | null;\n }>(\n `SELECT * FROM \"_scheduled_functions\" ORDER BY run_at DESC LIMIT 200`\n );\n\n const jobs: SchedulerJob[] = rows.map((row) => {\n const job: SchedulerJob = {\n id: row.id,\n functionName: row.function_name,\n args: JSON.parse(row.args_json) as Record<string, unknown>,\n scheduledAt: row.created_at,\n runAt: row.run_at,\n status: mapJobStatus(row.status)\n };\n if (row.schedule_json) {\n try {\n const schedule = JSON.parse(row.schedule_json) as {\n cron?: string;\n };\n if (schedule.cron) {\n job.cronSchedule = schedule.cron;\n }\n } catch {\n /* ignore parse errors */\n }\n }\n if (row.status === \"completed\" || row.status === \"failed\") {\n job.completedAt = row.updated_at;\n }\n return job;\n });\n\n return { kind: \"scheduler.list.result\", jobs };\n } catch {\n return { kind: \"scheduler.list.result\", jobs: [] };\n }\n }\n\n case \"scheduler.cancel\": {\n try {\n await driver.run(\n `UPDATE \"_scheduled_functions\" SET status = 'cancelled', updated_at = ? WHERE id = ? AND status = 'scheduled'`,\n [Date.now(), payload.jobId]\n );\n return { kind: \"scheduler.cancel.result\", success: true };\n } catch (err) {\n return {\n kind: \"scheduler.cancel.result\",\n success: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n default:\n return {\n kind: \"error\",\n message: `Unknown request kind: ${(payload as { kind: string }).kind}`\n };\n }\n };\n}\n\nfunction inferFileFromFunctionName(name: string): string {\n const parts = name.split(\":\");\n if (parts.length > 1) {\n return parts[0]! + \".ts\";\n }\n return \"unknown\";\n}\n\nfunction normalizeFilterValue(filter: DataFilter): unknown {\n switch (filter.operator) {\n case \"contains\":\n return `%${String(filter.value)}%`;\n case \"startsWith\":\n return `${String(filter.value)}%`;\n default:\n return filter.value;\n }\n}\n\nfunction filterOperatorToSql(op: string): string {\n switch (op) {\n case \"eq\":\n return \"=\";\n case \"neq\":\n return \"!=\";\n case \"gt\":\n return \">\";\n case \"gte\":\n return \">=\";\n case \"lt\":\n return \"<\";\n case \"lte\":\n return \"<=\";\n case \"contains\":\n return \"LIKE\";\n case \"startsWith\":\n return \"LIKE\";\n default:\n return \"=\";\n }\n}\n\nfunction mapJobStatus(\n status: string\n): \"pending\" | \"running\" | \"completed\" | \"failed\" | \"cancelled\" {\n switch (status) {\n case \"scheduled\":\n return \"pending\";\n case \"completed\":\n return \"completed\";\n case \"failed\":\n return \"failed\";\n case \"cancelled\":\n case \"skipped\":\n return \"cancelled\";\n default:\n return \"pending\";\n }\n}\n\nfunction generateId(): string {\n const chars = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n let id = \"\";\n for (let i = 0; i < 24; i++) {\n id += chars[Math.floor(Math.random() * chars.length)];\n }\n return id;\n}\n"],"mappings":"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"}
|