syncorejs 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/_vendor/cli/app.d.mts.map +1 -1
  2. package/dist/_vendor/cli/app.mjs +8 -5
  3. package/dist/_vendor/cli/app.mjs.map +1 -1
  4. package/dist/_vendor/cli/context.mjs.map +1 -1
  5. package/dist/_vendor/cli/dev-session.mjs.map +1 -1
  6. package/dist/_vendor/cli/doctor.mjs.map +1 -1
  7. package/dist/_vendor/cli/errors.mjs.map +1 -1
  8. package/dist/_vendor/cli/help.mjs.map +1 -1
  9. package/dist/_vendor/cli/index.mjs +9 -2
  10. package/dist/_vendor/cli/index.mjs.map +1 -1
  11. package/dist/_vendor/cli/messages.mjs.map +1 -1
  12. package/dist/_vendor/cli/preflight.mjs.map +1 -1
  13. package/dist/_vendor/cli/project.mjs +20 -20
  14. package/dist/_vendor/cli/project.mjs.map +1 -1
  15. package/dist/_vendor/cli/render.mjs.map +1 -1
  16. package/dist/_vendor/cli/targets.mjs.map +1 -1
  17. package/dist/_vendor/core/cli.d.mts +8 -2
  18. package/dist/_vendor/core/cli.d.mts.map +1 -1
  19. package/dist/_vendor/core/cli.mjs +238 -64
  20. package/dist/_vendor/core/cli.mjs.map +1 -1
  21. package/dist/_vendor/core/devtools-auth.mjs.map +1 -1
  22. package/dist/_vendor/core/runtime/components.d.mts.map +1 -1
  23. package/dist/_vendor/core/runtime/components.mjs.map +1 -1
  24. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  25. package/dist/_vendor/core/runtime/devtools.mjs +130 -23
  26. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  27. package/dist/_vendor/core/runtime/functions.d.mts +388 -6
  28. package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
  29. package/dist/_vendor/core/runtime/functions.mjs +72 -1
  30. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  31. package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
  32. package/dist/_vendor/core/runtime/id.mjs.map +1 -1
  33. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +11 -5
  34. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -1
  35. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +123 -20
  36. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -1
  37. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +56 -8
  38. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -1
  39. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +49 -14
  40. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -1
  41. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +4 -7
  42. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -1
  43. package/dist/_vendor/core/runtime/internal/engines/shared.mjs +76 -1
  44. package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -1
  45. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +1 -0
  46. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -1
  47. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +4 -3
  48. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -1
  49. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -1
  50. package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -1
  51. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +4 -0
  52. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -1
  53. package/dist/_vendor/core/runtime/runtime.d.mts +1040 -9
  54. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  55. package/dist/_vendor/core/runtime/runtime.mjs +63 -0
  56. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  57. package/dist/_vendor/core/transport.d.mts +2 -0
  58. package/dist/_vendor/core/transport.d.mts.map +1 -1
  59. package/dist/_vendor/core/transport.mjs +33 -24
  60. package/dist/_vendor/core/transport.mjs.map +1 -1
  61. package/dist/_vendor/devtools-protocol/index.d.ts +149 -4
  62. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  63. package/dist/_vendor/devtools-protocol/index.js.map +1 -1
  64. package/dist/_vendor/next/config.d.ts +3 -4
  65. package/dist/_vendor/next/config.d.ts.map +1 -1
  66. package/dist/_vendor/next/config.js +37 -19
  67. package/dist/_vendor/next/config.js.map +1 -1
  68. package/dist/_vendor/next/index.d.ts +109 -29
  69. package/dist/_vendor/next/index.d.ts.map +1 -1
  70. package/dist/_vendor/next/index.js +77 -17
  71. package/dist/_vendor/next/index.js.map +1 -1
  72. package/dist/_vendor/platform-expo/index.d.ts +146 -27
  73. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  74. package/dist/_vendor/platform-expo/index.js +76 -10
  75. package/dist/_vendor/platform-expo/index.js.map +1 -1
  76. package/dist/_vendor/platform-expo/react.js.map +1 -1
  77. package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
  78. package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
  79. package/dist/_vendor/platform-node/index.d.mts +173 -9
  80. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  81. package/dist/_vendor/platform-node/index.mjs +225 -94
  82. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  83. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  84. package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
  85. package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
  86. package/dist/_vendor/platform-web/external-change.d.ts +41 -0
  87. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
  88. package/dist/_vendor/platform-web/external-change.js +30 -0
  89. package/dist/_vendor/platform-web/external-change.js.map +1 -1
  90. package/dist/_vendor/platform-web/index.d.ts +307 -35
  91. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  92. package/dist/_vendor/platform-web/index.js +189 -23
  93. package/dist/_vendor/platform-web/index.js.map +1 -1
  94. package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
  95. package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
  96. package/dist/_vendor/platform-web/indexeddb.js +10 -0
  97. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  98. package/dist/_vendor/platform-web/opfs.d.ts +13 -0
  99. package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
  100. package/dist/_vendor/platform-web/opfs.js +12 -0
  101. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  102. package/dist/_vendor/platform-web/persistence.d.ts +54 -0
  103. package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
  104. package/dist/_vendor/platform-web/persistence.js +15 -0
  105. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  106. package/dist/_vendor/platform-web/react.d.ts +1 -2
  107. package/dist/_vendor/platform-web/react.d.ts.map +1 -1
  108. package/dist/_vendor/platform-web/react.js +2 -4
  109. package/dist/_vendor/platform-web/react.js.map +1 -1
  110. package/dist/_vendor/platform-web/sqljs.js +10 -1
  111. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  112. package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
  113. package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
  114. package/dist/_vendor/platform-web/worker.d.ts +60 -9
  115. package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
  116. package/dist/_vendor/platform-web/worker.js +37 -4
  117. package/dist/_vendor/platform-web/worker.js.map +1 -1
  118. package/dist/_vendor/react/index.d.ts +196 -13
  119. package/dist/_vendor/react/index.d.ts.map +1 -1
  120. package/dist/_vendor/react/index.js +208 -17
  121. package/dist/_vendor/react/index.js.map +1 -1
  122. package/dist/_vendor/schema/definition.d.ts +129 -0
  123. package/dist/_vendor/schema/definition.d.ts.map +1 -1
  124. package/dist/_vendor/schema/definition.js +99 -0
  125. package/dist/_vendor/schema/definition.js.map +1 -1
  126. package/dist/_vendor/schema/planner.d.ts.map +1 -1
  127. package/dist/_vendor/schema/planner.js.map +1 -1
  128. package/dist/_vendor/schema/validators.d.ts +180 -4
  129. package/dist/_vendor/schema/validators.d.ts.map +1 -1
  130. package/dist/_vendor/schema/validators.js +35 -1
  131. package/dist/_vendor/schema/validators.js.map +1 -1
  132. package/dist/_vendor/svelte/index.d.ts +205 -7
  133. package/dist/_vendor/svelte/index.d.ts.map +1 -1
  134. package/dist/_vendor/svelte/index.js +199 -6
  135. package/dist/_vendor/svelte/index.js.map +1 -1
  136. package/dist/browser.d.ts.map +1 -1
  137. package/dist/cli.js +3 -1
  138. package/dist/cli.js.map +1 -1
  139. package/dist/index.d.ts +1 -1
  140. package/package.json +24 -21
@@ -1 +1 @@
1
- {"version":3,"file":"schedulerEngine.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/schedulerEngine.ts"],"sourcesContent":["import type {\n FunctionReference,\n MisfirePolicy,\n RecurringJobDefinition\n} from \"../../functions.js\";\nimport type {\n JsonObject,\n SyncoreSqlDriver,\n UpdateScheduledJobOptions\n} from \"../../runtime.js\";\nimport { type DevtoolsEngine } from \"./devtoolsEngine.js\";\nimport {\n computeNextRun,\n parseMisfirePolicy,\n shouldRunMissedJob,\n stableStringify,\n type ScheduledJobRow\n} from \"./shared.js\";\nimport { generateId } from \"../../id.js\";\n\ntype SchedulerEngineDeps = {\n driver: SyncoreSqlDriver;\n runtimeId: string;\n devtools: DevtoolsEngine;\n recurringJobs: RecurringJobDefinition[];\n pollIntervalMs: number;\n runMutation: (\n reference: FunctionReference<\"mutation\", unknown, unknown>,\n args: JsonObject\n ) => Promise<unknown>;\n runAction: (\n reference: FunctionReference<\"action\", unknown, unknown>,\n args: JsonObject\n ) => Promise<unknown>;\n};\n\nexport class SchedulerEngine {\n private timer: ReturnType<typeof setInterval> | undefined;\n\n constructor(private readonly deps: SchedulerEngineDeps) {}\n\n async prepare(): Promise<void> {\n await this.deps.driver.exec(`\n CREATE TABLE IF NOT EXISTS \"_scheduled_functions\" (\n id TEXT PRIMARY KEY,\n function_name TEXT NOT NULL,\n function_kind TEXT NOT NULL,\n args_json TEXT NOT NULL,\n status TEXT NOT NULL,\n run_at INTEGER NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n recurring_name TEXT,\n schedule_json TEXT,\n timezone TEXT,\n misfire_policy TEXT NOT NULL,\n last_run_at INTEGER,\n window_ms INTEGER\n );\n `);\n }\n\n startPolling(): void {\n if (this.timer) {\n return;\n }\n this.timer = setInterval(() => {\n void this.processDueJobs();\n }, this.deps.pollIntervalMs);\n }\n\n stopPolling(): void {\n if (!this.timer) {\n return;\n }\n clearInterval(this.timer);\n this.timer = undefined;\n }\n\n async scheduleJob(\n runAt: number,\n reference: FunctionReference<\"mutation\" | \"action\", unknown, unknown>,\n args: JsonObject,\n misfirePolicy: MisfirePolicy,\n namespacePrefix?: string\n ): Promise<string> {\n const id = `${namespacePrefix ?? \"\"}${generateId()}`;\n const now = Date.now();\n await this.deps.driver.run(\n `INSERT INTO \"_scheduled_functions\"\n (id, function_name, function_kind, args_json, status, run_at, created_at, updated_at, recurring_name, schedule_json, timezone, misfire_policy, last_run_at, window_ms)\n VALUES (?, ?, ?, ?, 'scheduled', ?, ?, ?, NULL, NULL, NULL, ?, NULL, ?)`,\n [\n id,\n reference.name,\n reference.kind,\n stableStringify(args),\n runAt,\n now,\n now,\n misfirePolicy.type,\n misfirePolicy.type === \"windowed\" ? misfirePolicy.windowMs : null\n ]\n );\n this.notifySchedulerJobsChanged();\n return id;\n }\n\n async cancelScheduledJob(id: string): Promise<boolean> {\n const result = await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\"\n SET status = 'cancelled', updated_at = ?\n WHERE id = ? AND status = 'scheduled'`,\n [Date.now(), id]\n );\n if ((result.changes ?? 0) > 0) {\n this.notifySchedulerJobsChanged();\n return true;\n }\n return false;\n }\n\n async updateScheduledJob(options: UpdateScheduledJobOptions): Promise<boolean> {\n const existing = await this.deps.driver.get<{\n status: string;\n recurring_name: string | null;\n }>(\n `SELECT status, recurring_name FROM \"_scheduled_functions\" WHERE id = ?`,\n [options.id]\n );\n if (!existing || existing.status !== \"scheduled\" || !existing.recurring_name) {\n return false;\n }\n const now = Date.now();\n const runAt = options.runAt ?? computeNextRun(options.schedule, now);\n const result = await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\"\n SET args_json = ?, run_at = ?, updated_at = ?, schedule_json = ?, timezone = ?, misfire_policy = ?, window_ms = ?\n WHERE id = ? AND status = 'scheduled' AND recurring_name IS NOT NULL`,\n [\n stableStringify(options.args),\n runAt,\n now,\n stableStringify(options.schedule),\n \"timezone\" in options.schedule ? (options.schedule.timezone ?? null) : null,\n options.misfirePolicy.type,\n options.misfirePolicy.type === \"windowed\"\n ? options.misfirePolicy.windowMs\n : null,\n options.id\n ]\n );\n if ((result.changes ?? 0) > 0) {\n this.notifySchedulerJobsChanged();\n return true;\n }\n return false;\n }\n\n async syncRecurringJobs(): Promise<void> {\n for (const job of this.deps.recurringJobs) {\n const id = `recurring:${job.name}`;\n const existing = await this.deps.driver.get<ScheduledJobRow>(\n `SELECT * FROM \"_scheduled_functions\" WHERE id = ?`,\n [id]\n );\n if (existing) {\n continue;\n }\n const nextRunAt = computeNextRun(job.schedule, Date.now());\n await this.deps.driver.run(\n `INSERT INTO \"_scheduled_functions\"\n (id, function_name, function_kind, args_json, status, run_at, created_at, updated_at, recurring_name, schedule_json, timezone, misfire_policy, last_run_at, window_ms)\n VALUES (?, ?, ?, ?, 'scheduled', ?, ?, ?, ?, ?, ?, ?, NULL, ?)`,\n [\n id,\n job.function.name,\n job.function.kind,\n stableStringify(job.args),\n nextRunAt,\n Date.now(),\n Date.now(),\n job.name,\n stableStringify(job.schedule),\n \"timezone\" in job.schedule ? (job.schedule.timezone ?? null) : null,\n job.misfirePolicy.type,\n job.misfirePolicy.type === \"windowed\"\n ? job.misfirePolicy.windowMs\n : null\n ]\n );\n this.notifySchedulerJobsChanged();\n }\n }\n\n private notifySchedulerJobsChanged(): void {\n this.deps.devtools.notifyScopes([\"scheduler.jobs\"]);\n }\n\n private async processDueJobs(): Promise<void> {\n const now = Date.now();\n const dueJobs = await this.deps.driver.all<ScheduledJobRow>(\n `SELECT * FROM \"_scheduled_functions\" WHERE status = 'scheduled' AND run_at <= ? ORDER BY run_at ASC`,\n [now]\n );\n const executedJobIds: string[] = [];\n\n for (const job of dueJobs) {\n const misfirePolicy = parseMisfirePolicy(\n job.misfire_policy,\n job.window_ms\n );\n if (!shouldRunMissedJob(job.run_at, now, misfirePolicy)) {\n await this.advanceOrFinalizeJob(job, \"skipped\", now);\n continue;\n }\n\n try {\n if (job.function_kind === \"mutation\") {\n await this.deps.runMutation(\n { kind: \"mutation\", name: job.function_name },\n JSON.parse(job.args_json) as JsonObject\n );\n } else {\n await this.deps.runAction(\n { kind: \"action\", name: job.function_name },\n JSON.parse(job.args_json) as JsonObject\n );\n }\n executedJobIds.push(job.id);\n await this.advanceOrFinalizeJob(job, \"completed\", now);\n } catch (error) {\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\" SET status = 'failed', updated_at = ? WHERE id = ?`,\n [Date.now(), job.id]\n );\n this.notifySchedulerJobsChanged();\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"error\",\n message: `Scheduled job ${job.id} failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n timestamp: Date.now()\n });\n }\n }\n\n if (executedJobIds.length > 0) {\n this.deps.devtools.emit({\n type: \"scheduler.tick\",\n runtimeId: this.deps.runtimeId,\n executedJobIds,\n timestamp: Date.now()\n });\n this.notifySchedulerJobsChanged();\n }\n }\n\n private async advanceOrFinalizeJob(\n job: ScheduledJobRow,\n terminalStatus: ScheduledJobRow[\"status\"],\n executedAt: number\n ): Promise<void> {\n if (!job.recurring_name || !job.schedule_json) {\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\" SET status = ?, updated_at = ?, last_run_at = ? WHERE id = ?`,\n [terminalStatus, executedAt, executedAt, job.id]\n );\n this.notifySchedulerJobsChanged();\n return;\n }\n\n const schedule = readRecurringSchedule(job.schedule_json);\n if (!schedule) {\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\" SET status = ?, updated_at = ?, last_run_at = ? WHERE id = ?`,\n [terminalStatus, executedAt, executedAt, job.id]\n );\n this.notifySchedulerJobsChanged();\n return;\n }\n const nextRunAt = computeNextRun(schedule, executedAt + 1);\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\"\n SET status = 'scheduled', run_at = ?, updated_at = ?, last_run_at = ?\n WHERE id = ?`,\n [nextRunAt, executedAt, executedAt, job.id]\n );\n this.notifySchedulerJobsChanged();\n }\n}\n\nfunction readRecurringSchedule(\n scheduleJson: string | null\n): RecurringJobDefinition[\"schedule\"] | undefined {\n if (!scheduleJson) {\n return undefined;\n }\n try {\n const parsed: unknown = JSON.parse(scheduleJson);\n if (!isRecurringSchedule(parsed)) {\n return undefined;\n }\n return parsed;\n } catch {\n return undefined;\n }\n}\n\nfunction isRecurringSchedule(\n value: unknown\n): value is RecurringJobDefinition[\"schedule\"] {\n if (!value || typeof value !== \"object\" || !(\"type\" in value)) {\n return false;\n }\n const schedule = value as Record<string, unknown>;\n switch (schedule.type) {\n case \"interval\":\n return (\n (schedule.seconds === undefined || typeof schedule.seconds === \"number\") &&\n (schedule.minutes === undefined || typeof schedule.minutes === \"number\") &&\n (schedule.hours === undefined || typeof schedule.hours === \"number\")\n );\n case \"daily\":\n return (\n typeof schedule.hour === \"number\" &&\n typeof schedule.minute === \"number\" &&\n (schedule.timezone === undefined || typeof schedule.timezone === \"string\")\n );\n case \"weekly\":\n return (\n isDayOfWeek(schedule.dayOfWeek) &&\n typeof schedule.hour === \"number\" &&\n typeof schedule.minute === \"number\" &&\n (schedule.timezone === undefined || typeof schedule.timezone === \"string\")\n );\n default:\n return false;\n }\n}\n\nfunction isDayOfWeek(\n value: unknown\n): value is Extract<\n RecurringJobDefinition[\"schedule\"],\n { type: \"weekly\" }\n>[\"dayOfWeek\"] {\n return (\n value === \"sunday\" ||\n value === \"monday\" ||\n value === \"tuesday\" ||\n value === \"wednesday\" ||\n value === \"thursday\" ||\n value === \"friday\" ||\n value === \"saturday\"\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schedulerEngine.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/schedulerEngine.ts"],"sourcesContent":["import type {\n FunctionReference,\n MisfirePolicy,\n RecurringJobDefinition\n} from \"../../functions.js\";\nimport type {\n JsonObject,\n SyncoreSqlDriver,\n UpdateScheduledJobOptions\n} from \"../../runtime.js\";\nimport { type DevtoolsEngine } from \"./devtoolsEngine.js\";\nimport {\n computeNextRun,\n createDevtoolsPreview,\n parseMisfirePolicy,\n shouldRunMissedJob,\n stableStringify,\n type ScheduledJobRow\n} from \"./shared.js\";\nimport { generateId } from \"../../id.js\";\n\ntype SchedulerEngineDeps = {\n driver: SyncoreSqlDriver;\n runtimeId: string;\n devtools: DevtoolsEngine;\n recurringJobs: RecurringJobDefinition[];\n pollIntervalMs: number;\n runMutation: (\n reference: FunctionReference<\"mutation\", unknown, unknown>,\n args: JsonObject,\n meta?: { executionId?: string; schedulerJobId?: string; schedulerRun?: boolean }\n ) => Promise<unknown>;\n runAction: (\n reference: FunctionReference<\"action\", unknown, unknown>,\n args: JsonObject,\n meta?: { executionId?: string; schedulerJobId?: string; schedulerRun?: boolean }\n ) => Promise<unknown>;\n};\n\nexport class SchedulerEngine {\n private timer: ReturnType<typeof setInterval> | undefined;\n\n constructor(private readonly deps: SchedulerEngineDeps) {}\n\n async prepare(): Promise<void> {\n await this.deps.driver.exec(`\n CREATE TABLE IF NOT EXISTS \"_scheduled_functions\" (\n id TEXT PRIMARY KEY,\n function_name TEXT NOT NULL,\n function_kind TEXT NOT NULL,\n args_json TEXT NOT NULL,\n status TEXT NOT NULL,\n run_at INTEGER NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n recurring_name TEXT,\n schedule_json TEXT,\n timezone TEXT,\n misfire_policy TEXT NOT NULL,\n last_run_at INTEGER,\n window_ms INTEGER\n );\n `);\n }\n\n startPolling(): void {\n if (this.timer) {\n return;\n }\n this.timer = setInterval(() => {\n void this.processDueJobs();\n }, this.deps.pollIntervalMs);\n }\n\n stopPolling(): void {\n if (!this.timer) {\n return;\n }\n clearInterval(this.timer);\n this.timer = undefined;\n }\n\n async scheduleJob(\n runAt: number,\n reference: FunctionReference<\"mutation\" | \"action\", unknown, unknown>,\n args: JsonObject,\n misfirePolicy: MisfirePolicy,\n namespacePrefix?: string\n ): Promise<string> {\n const id = `${namespacePrefix ?? \"\"}${generateId()}`;\n const now = Date.now();\n await this.deps.driver.run(\n `INSERT INTO \"_scheduled_functions\"\n (id, function_name, function_kind, args_json, status, run_at, created_at, updated_at, recurring_name, schedule_json, timezone, misfire_policy, last_run_at, window_ms)\n VALUES (?, ?, ?, ?, 'scheduled', ?, ?, ?, NULL, NULL, NULL, ?, NULL, ?)`,\n [\n id,\n reference.name,\n reference.kind,\n stableStringify(args),\n runAt,\n now,\n now,\n misfirePolicy.type,\n misfirePolicy.type === \"windowed\" ? misfirePolicy.windowMs : null\n ]\n );\n this.notifySchedulerJobsChanged();\n return id;\n }\n\n async cancelScheduledJob(id: string): Promise<boolean> {\n const result = await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\"\n SET status = 'cancelled', updated_at = ?\n WHERE id = ? AND status = 'scheduled'`,\n [Date.now(), id]\n );\n if ((result.changes ?? 0) > 0) {\n this.notifySchedulerJobsChanged();\n return true;\n }\n return false;\n }\n\n async updateScheduledJob(options: UpdateScheduledJobOptions): Promise<boolean> {\n const existing = await this.deps.driver.get<{\n status: string;\n run_at: number;\n recurring_name: string | null;\n schedule_json: string | null;\n misfire_policy: string | null;\n window_ms: number | null;\n }>(\n `SELECT status, run_at, recurring_name, schedule_json, misfire_policy, window_ms\n FROM \"_scheduled_functions\" WHERE id = ?`,\n [options.id]\n );\n if (!existing || existing.status !== \"scheduled\") {\n return false;\n }\n const existingSchedule = existing.schedule_json\n ? (JSON.parse(existing.schedule_json) as RecurringJobDefinition[\"schedule\"])\n : undefined;\n const schedule = options.schedule ?? existingSchedule;\n const misfirePolicy =\n options.misfirePolicy ??\n parseMisfirePolicy(existing.misfire_policy ?? \"catch_up\", existing.window_ms);\n const now = Date.now();\n const runAt = options.runAt ?? (schedule ? computeNextRun(schedule, now) : existing.run_at);\n const result = await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\"\n SET args_json = ?, run_at = ?, updated_at = ?, schedule_json = ?, timezone = ?, misfire_policy = ?, window_ms = ?\n WHERE id = ? AND status = 'scheduled'`,\n [\n stableStringify(options.args),\n runAt,\n now,\n schedule ? stableStringify(schedule) : null,\n schedule && \"timezone\" in schedule ? (schedule.timezone ?? null) : null,\n misfirePolicy.type,\n misfirePolicy.type === \"windowed\" ? misfirePolicy.windowMs : null,\n options.id\n ]\n );\n if ((result.changes ?? 0) > 0) {\n this.notifySchedulerJobsChanged();\n return true;\n }\n return false;\n }\n\n async syncRecurringJobs(): Promise<void> {\n for (const job of this.deps.recurringJobs) {\n const id = `recurring:${job.name}`;\n const existing = await this.deps.driver.get<ScheduledJobRow>(\n `SELECT * FROM \"_scheduled_functions\" WHERE id = ?`,\n [id]\n );\n if (existing) {\n continue;\n }\n const nextRunAt = computeNextRun(job.schedule, Date.now());\n await this.deps.driver.run(\n `INSERT INTO \"_scheduled_functions\"\n (id, function_name, function_kind, args_json, status, run_at, created_at, updated_at, recurring_name, schedule_json, timezone, misfire_policy, last_run_at, window_ms)\n VALUES (?, ?, ?, ?, 'scheduled', ?, ?, ?, ?, ?, ?, ?, NULL, ?)`,\n [\n id,\n job.function.name,\n job.function.kind,\n stableStringify(job.args),\n nextRunAt,\n Date.now(),\n Date.now(),\n job.name,\n stableStringify(job.schedule),\n \"timezone\" in job.schedule ? (job.schedule.timezone ?? null) : null,\n job.misfirePolicy.type,\n job.misfirePolicy.type === \"windowed\"\n ? job.misfirePolicy.windowMs\n : null\n ]\n );\n this.notifySchedulerJobsChanged();\n }\n }\n\n private notifySchedulerJobsChanged(): void {\n this.deps.devtools.notifyScopes([\"scheduler.jobs\"]);\n }\n\n private async processDueJobs(): Promise<void> {\n const now = Date.now();\n const dueJobs = await this.deps.driver.all<ScheduledJobRow>(\n `SELECT * FROM \"_scheduled_functions\" WHERE status = 'scheduled' AND run_at <= ? ORDER BY run_at ASC`,\n [now]\n );\n const executedJobIds: string[] = [];\n const jobExecutions: Array<{\n jobId: string;\n executionId?: string;\n functionName: string;\n functionType: \"mutation\" | \"action\";\n argsPreview?: ReturnType<typeof createDevtoolsPreview>;\n resultPreview?: ReturnType<typeof createDevtoolsPreview>;\n error?: string;\n durationMs?: number;\n }> = [];\n\n for (const job of dueJobs) {\n const misfirePolicy = parseMisfirePolicy(\n job.misfire_policy,\n job.window_ms\n );\n if (!shouldRunMissedJob(job.run_at, now, misfirePolicy)) {\n await this.advanceOrFinalizeJob(job, \"skipped\", now);\n continue;\n }\n\n try {\n const args = JSON.parse(job.args_json) as JsonObject;\n const executionId = generateId();\n const startedAt = Date.now();\n let result: unknown;\n if (job.function_kind === \"mutation\") {\n result = await this.deps.runMutation(\n { kind: \"mutation\", name: job.function_name },\n args,\n { executionId, schedulerJobId: job.id, schedulerRun: true }\n );\n } else {\n result = await this.deps.runAction(\n { kind: \"action\", name: job.function_name },\n args,\n { executionId, schedulerJobId: job.id, schedulerRun: true }\n );\n }\n executedJobIds.push(job.id);\n jobExecutions.push({\n jobId: job.id,\n executionId,\n functionName: job.function_name,\n functionType: job.function_kind === \"mutation\" ? \"mutation\" : \"action\",\n argsPreview: createDevtoolsPreview(args),\n resultPreview: createDevtoolsPreview(result),\n durationMs: Date.now() - startedAt\n });\n await this.advanceOrFinalizeJob(job, \"completed\", now);\n } catch (error) {\n jobExecutions.push({\n jobId: job.id,\n functionName: job.function_name,\n functionType: job.function_kind === \"mutation\" ? \"mutation\" : \"action\",\n error: error instanceof Error ? error.message : String(error)\n });\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\" SET status = 'failed', updated_at = ? WHERE id = ?`,\n [Date.now(), job.id]\n );\n this.notifySchedulerJobsChanged();\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"error\",\n message: `Scheduled job ${job.id} failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n timestamp: Date.now()\n });\n }\n }\n\n if (jobExecutions.length > 0) {\n this.deps.devtools.emit({\n type: \"scheduler.tick\",\n runtimeId: this.deps.runtimeId,\n executionId: generateId(),\n executedJobIds,\n jobExecutions,\n timestamp: Date.now()\n });\n this.notifySchedulerJobsChanged();\n }\n }\n\n private async advanceOrFinalizeJob(\n job: ScheduledJobRow,\n terminalStatus: ScheduledJobRow[\"status\"],\n executedAt: number\n ): Promise<void> {\n if (!job.recurring_name || !job.schedule_json) {\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\" SET status = ?, updated_at = ?, last_run_at = ? WHERE id = ?`,\n [terminalStatus, executedAt, executedAt, job.id]\n );\n this.notifySchedulerJobsChanged();\n return;\n }\n\n const schedule = readRecurringSchedule(job.schedule_json);\n if (!schedule) {\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\" SET status = ?, updated_at = ?, last_run_at = ? WHERE id = ?`,\n [terminalStatus, executedAt, executedAt, job.id]\n );\n this.notifySchedulerJobsChanged();\n return;\n }\n const nextRunAt = computeNextRun(schedule, executedAt + 1);\n await this.deps.driver.run(\n `UPDATE \"_scheduled_functions\"\n SET status = 'scheduled', run_at = ?, updated_at = ?, last_run_at = ?\n WHERE id = ?`,\n [nextRunAt, executedAt, executedAt, job.id]\n );\n this.notifySchedulerJobsChanged();\n }\n}\n\nfunction readRecurringSchedule(\n scheduleJson: string | null\n): RecurringJobDefinition[\"schedule\"] | undefined {\n if (!scheduleJson) {\n return undefined;\n }\n try {\n const parsed: unknown = JSON.parse(scheduleJson);\n if (!isRecurringSchedule(parsed)) {\n return undefined;\n }\n return parsed;\n } catch {\n return undefined;\n }\n}\n\nfunction isRecurringSchedule(\n value: unknown\n): value is RecurringJobDefinition[\"schedule\"] {\n if (!value || typeof value !== \"object\" || !(\"type\" in value)) {\n return false;\n }\n const schedule = value as Record<string, unknown>;\n switch (schedule.type) {\n case \"interval\":\n return (\n (schedule.seconds === undefined || typeof schedule.seconds === \"number\") &&\n (schedule.minutes === undefined || typeof schedule.minutes === \"number\") &&\n (schedule.hours === undefined || typeof schedule.hours === \"number\")\n );\n case \"daily\":\n return (\n typeof schedule.hour === \"number\" &&\n typeof schedule.minute === \"number\" &&\n (schedule.timezone === undefined || typeof schedule.timezone === \"string\")\n );\n case \"weekly\":\n return (\n isDayOfWeek(schedule.dayOfWeek) &&\n typeof schedule.hour === \"number\" &&\n typeof schedule.minute === \"number\" &&\n (schedule.timezone === undefined || typeof schedule.timezone === \"string\")\n );\n default:\n return false;\n }\n}\n\nfunction isDayOfWeek(\n value: unknown\n): value is Extract<\n RecurringJobDefinition[\"schedule\"],\n { type: \"weekly\" }\n>[\"dayOfWeek\"] {\n return (\n value === \"sunday\" ||\n value === \"monday\" ||\n value === \"tuesday\" ||\n value === \"wednesday\" ||\n value === \"thursday\" ||\n value === \"friday\" ||\n value === \"saturday\"\n );\n}\n"],"mappings":";;;AAuCA,IAAa,kBAAb,MAA6B;CAGE;CAF7B;CAEA,YAAY,MAA4C;EAA3B,KAAA,OAAA;CAA4B;CAEzD,MAAM,UAAyB;EAC7B,MAAM,KAAK,KAAK,OAAO,KAAK;;;;;;;;;;;;;;;;;KAiB3B;CACH;CAEA,eAAqB;EACnB,IAAI,KAAK,OACP;EAEF,KAAK,QAAQ,kBAAkB;GAC7B,KAAU,eAAe;EAC3B,GAAG,KAAK,KAAK,cAAc;CAC7B;CAEA,cAAoB;EAClB,IAAI,CAAC,KAAK,OACR;EAEF,cAAc,KAAK,KAAK;EACxB,KAAK,QAAQ,KAAA;CACf;CAEA,MAAM,YACJ,OACA,WACA,MACA,eACA,iBACiB;EACjB,MAAM,KAAK,GAAG,mBAAmB,KAAK,WAAW;EACjD,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,KAAK,KAAK,OAAO,IACrB;;iFAGA;GACE;GACA,UAAU;GACV,UAAU;GACV,gBAAgB,IAAI;GACpB;GACA;GACA;GACA,cAAc;GACd,cAAc,SAAS,aAAa,cAAc,WAAW;EAC/D,CACF;EACA,KAAK,2BAA2B;EAChC,OAAO;CACT;CAEA,MAAM,mBAAmB,IAA8B;EAOrD,MAAK,MANgB,KAAK,KAAK,OAAO,IACpC;;+CAGA,CAAC,KAAK,IAAI,GAAG,EAAE,CACjB,GACY,WAAW,KAAK,GAAG;GAC7B,KAAK,2BAA2B;GAChC,OAAO;EACT;EACA,OAAO;CACT;CAEA,MAAM,mBAAmB,SAAsD;EAC7E,MAAM,WAAW,MAAM,KAAK,KAAK,OAAO,IAQtC;kDAEA,CAAC,QAAQ,EAAE,CACb;EACA,IAAI,CAAC,YAAY,SAAS,WAAW,aACnC,OAAO;EAET,MAAM,mBAAmB,SAAS,gBAC7B,KAAK,MAAM,SAAS,aAAa,IAClC,KAAA;EACJ,MAAM,WAAW,QAAQ,YAAY;EACrC,MAAM,gBACJ,QAAQ,iBACR,mBAAmB,SAAS,kBAAkB,YAAY,SAAS,SAAS;EAC9E,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,QAAQ,QAAQ,UAAU,WAAW,eAAe,UAAU,GAAG,IAAI,SAAS;EAgBpF,MAAK,MAfgB,KAAK,KAAK,OAAO,IACpC;;+CAGA;GACE,gBAAgB,QAAQ,IAAI;GAC5B;GACA;GACA,WAAW,gBAAgB,QAAQ,IAAI;GACvC,YAAY,cAAc,WAAY,SAAS,YAAY,OAAQ;GACnE,cAAc;GACd,cAAc,SAAS,aAAa,cAAc,WAAW;GAC7D,QAAQ;EACV,CACF,GACY,WAAW,KAAK,GAAG;GAC7B,KAAK,2BAA2B;GAChC,OAAO;EACT;EACA,OAAO;CACT;CAEA,MAAM,oBAAmC;EACvC,KAAK,MAAM,OAAO,KAAK,KAAK,eAAe;GACzC,MAAM,KAAK,aAAa,IAAI;GAK5B,IAAI,MAJmB,KAAK,KAAK,OAAO,IACtC,qDACA,CAAC,EAAE,CACL,GAEE;GAEF,MAAM,YAAY,eAAe,IAAI,UAAU,KAAK,IAAI,CAAC;GACzD,MAAM,KAAK,KAAK,OAAO,IACrB;;0EAGA;IACE;IACA,IAAI,SAAS;IACb,IAAI,SAAS;IACb,gBAAgB,IAAI,IAAI;IACxB;IACA,KAAK,IAAI;IACT,KAAK,IAAI;IACT,IAAI;IACJ,gBAAgB,IAAI,QAAQ;IAC5B,cAAc,IAAI,WAAY,IAAI,SAAS,YAAY,OAAQ;IAC/D,IAAI,cAAc;IAClB,IAAI,cAAc,SAAS,aACvB,IAAI,cAAc,WAClB;GACN,CACF;GACA,KAAK,2BAA2B;EAClC;CACF;CAEA,6BAA2C;EACzC,KAAK,KAAK,SAAS,aAAa,CAAC,gBAAgB,CAAC;CACpD;CAEA,MAAc,iBAAgC;EAC5C,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO,IACrC,uGACA,CAAC,GAAG,CACN;EACA,MAAM,iBAA2B,CAAC;EAClC,MAAM,gBASD,CAAC;EAEN,KAAK,MAAM,OAAO,SAAS;GACzB,MAAM,gBAAgB,mBACpB,IAAI,gBACJ,IAAI,SACN;GACA,IAAI,CAAC,mBAAmB,IAAI,QAAQ,KAAK,aAAa,GAAG;IACvD,MAAM,KAAK,qBAAqB,KAAK,WAAW,GAAG;IACnD;GACF;GAEA,IAAI;IACF,MAAM,OAAO,KAAK,MAAM,IAAI,SAAS;IACrC,MAAM,cAAc,WAAW;IAC/B,MAAM,YAAY,KAAK,IAAI;IAC3B,IAAI;IACJ,IAAI,IAAI,kBAAkB,YACxB,SAAS,MAAM,KAAK,KAAK,YACvB;KAAE,MAAM;KAAY,MAAM,IAAI;IAAc,GAC5C,MACA;KAAE;KAAa,gBAAgB,IAAI;KAAI,cAAc;IAAK,CAC5D;SAEA,SAAS,MAAM,KAAK,KAAK,UACvB;KAAE,MAAM;KAAU,MAAM,IAAI;IAAc,GAC1C,MACA;KAAE;KAAa,gBAAgB,IAAI;KAAI,cAAc;IAAK,CAC5D;IAEF,eAAe,KAAK,IAAI,EAAE;IAC1B,cAAc,KAAK;KACjB,OAAO,IAAI;KACX;KACA,cAAc,IAAI;KAClB,cAAc,IAAI,kBAAkB,aAAa,aAAa;KAC9D,aAAa,sBAAsB,IAAI;KACvC,eAAe,sBAAsB,MAAM;KAC3C,YAAY,KAAK,IAAI,IAAI;IAC3B,CAAC;IACD,MAAM,KAAK,qBAAqB,KAAK,aAAa,GAAG;GACvD,SAAS,OAAO;IACd,cAAc,KAAK;KACjB,OAAO,IAAI;KACX,cAAc,IAAI;KAClB,cAAc,IAAI,kBAAkB,aAAa,aAAa;KAC9D,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC9D,CAAC;IACD,MAAM,KAAK,KAAK,OAAO,IACrB,oFACA,CAAC,KAAK,IAAI,GAAG,IAAI,EAAE,CACrB;IACA,KAAK,2BAA2B;IAChC,KAAK,KAAK,SAAS,KAAK;KACtB,MAAM;KACN,WAAW,KAAK,KAAK;KACrB,OAAO;KACP,SAAS,iBAAiB,IAAI,GAAG,WAC/B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;KAEvD,WAAW,KAAK,IAAI;IACtB,CAAC;GACH;EACF;EAEA,IAAI,cAAc,SAAS,GAAG;GAC5B,KAAK,KAAK,SAAS,KAAK;IACtB,MAAM;IACN,WAAW,KAAK,KAAK;IACrB,aAAa,WAAW;IACxB;IACA;IACA,WAAW,KAAK,IAAI;GACtB,CAAC;GACD,KAAK,2BAA2B;EAClC;CACF;CAEA,MAAc,qBACZ,KACA,gBACA,YACe;EACf,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,eAAe;GAC7C,MAAM,KAAK,KAAK,OAAO,IACrB,8FACA;IAAC;IAAgB;IAAY;IAAY,IAAI;GAAE,CACjD;GACA,KAAK,2BAA2B;GAChC;EACF;EAEA,MAAM,WAAW,sBAAsB,IAAI,aAAa;EACxD,IAAI,CAAC,UAAU;GACb,MAAM,KAAK,KAAK,OAAO,IACrB,8FACA;IAAC;IAAgB;IAAY;IAAY,IAAI;GAAE,CACjD;GACA,KAAK,2BAA2B;GAChC;EACF;EACA,MAAM,YAAY,eAAe,UAAU,aAAa,CAAC;EACzD,MAAM,KAAK,KAAK,OAAO,IACrB;;sBAGA;GAAC;GAAW;GAAY;GAAY,IAAI;EAAE,CAC5C;EACA,KAAK,2BAA2B;CAClC;AACF;AAEA,SAAS,sBACP,cACgD;CAChD,IAAI,CAAC,cACH;CAEF,IAAI;EACF,MAAM,SAAkB,KAAK,MAAM,YAAY;EAC/C,IAAI,CAAC,oBAAoB,MAAM,GAC7B;EAEF,OAAO;CACT,QAAQ;EACN;CACF;AACF;AAEA,SAAS,oBACP,OAC6C;CAC7C,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,EAAE,UAAU,QACrD,OAAO;CAET,MAAM,WAAW;CACjB,QAAQ,SAAS,MAAjB;EACE,KAAK,YACH,QACG,SAAS,YAAY,KAAA,KAAa,OAAO,SAAS,YAAY,cAC9D,SAAS,YAAY,KAAA,KAAa,OAAO,SAAS,YAAY,cAC9D,SAAS,UAAU,KAAA,KAAa,OAAO,SAAS,UAAU;EAE/D,KAAK,SACH,OACE,OAAO,SAAS,SAAS,YACzB,OAAO,SAAS,WAAW,aAC1B,SAAS,aAAa,KAAA,KAAa,OAAO,SAAS,aAAa;EAErE,KAAK,UACH,OACE,YAAY,SAAS,SAAS,KAC9B,OAAO,SAAS,SAAS,YACzB,OAAO,SAAS,WAAW,aAC1B,SAAS,aAAa,KAAA,KAAa,OAAO,SAAS,aAAa;EAErE,SACE,OAAO;CACX;AACF;AAEA,SAAS,YACP,OAIa;CACb,OACE,UAAU,YACV,UAAU,YACV,UAAU,aACV,UAAU,eACV,UAAU,cACV,UAAU,YACV,UAAU;AAEd"}
@@ -2,6 +2,7 @@ import { getTableDefinition, quoteIdentifier, resolveSearchIndexTableName, searc
2
2
  import { createSchemaSnapshot, describeValidator, deserializeValue, diffSchemaSnapshots, parseSchemaSnapshot, renderCreateSearchIndexStatement, renderMigrationSql, serializeValue } from "../../../../schema/index.js";
3
3
  //#region src/runtime/internal/engines/schemaEngine.ts
4
4
  var SchemaEngine = class {
5
+ deps;
5
6
  disabledSearchIndexes = /* @__PURE__ */ new Set();
6
7
  constructor(deps) {
7
8
  this.deps = deps;
@@ -154,7 +155,8 @@ var SchemaEngine = class {
154
155
  return {
155
156
  name: fieldName,
156
157
  type: field.validator.kind,
157
- optional: field.optional
158
+ optional: field.optional,
159
+ ...field.validator.kind === "id" && field.validator.tableName ? { referenceTable: field.validator.tableName } : {}
158
160
  };
159
161
  }) : [];
160
162
  fields.unshift({
@@ -166,12 +168,7 @@ var SchemaEngine = class {
166
168
  type: "number",
167
169
  optional: false
168
170
  });
169
- let documentCount = 0;
170
- try {
171
- documentCount = (await this.deps.driver.get(`SELECT COUNT(*) as count FROM ${quoteIdentifier(name)}`))?.count ?? 0;
172
- } catch {
173
- documentCount = 0;
174
- }
171
+ const documentCount = await this.deps.driver.get(`SELECT COUNT(*) as count FROM ${quoteIdentifier(name)}`).then((countRow) => countRow?.count ?? 0).catch(() => 0);
175
172
  tables.push({
176
173
  name,
177
174
  ...table.options.tableName ? { displayName: table.options.tableName } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"schemaEngine.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/schemaEngine.ts"],"sourcesContent":["import {\n describeValidator,\n createSchemaSnapshot,\n deserializeValue,\n diffSchemaSnapshots,\n parseSchemaSnapshot,\n renderCreateSearchIndexStatement,\n renderMigrationSql,\n serializeValue,\n type Validator\n} from \"@syncore/schema\";\nimport type {\n TableDefinition\n} from \"@syncore/schema\";\nimport type {\n DevtoolsLiveQuerySnapshot,\n JsonObject,\n SyncoreDataModel,\n SyncoreSqlDriver\n} from \"../../runtime.js\";\nimport {\n getTableDefinition,\n quoteIdentifier,\n resolveSearchIndexTableName,\n searchIndexKey,\n stableStringify,\n toSearchValue,\n type DatabaseRow\n} from \"./shared.js\";\nimport { type DevtoolsEngine } from \"./devtoolsEngine.js\";\n\ntype RecordDocument = Record<string, unknown>;\ntype StructuredValidator = Validator<RecordDocument, RecordDocument, string>;\ntype StructuredTableDefinition = TableDefinition<StructuredValidator>;\ntype SystemDocumentFields = {\n _id: string;\n _creationTime: number;\n};\ntype StructuredRuntimeDocument = RecordDocument & SystemDocumentFields;\n\ntype SchemaEngineDeps<TSchema extends SyncoreDataModel> = {\n schema: TSchema;\n driver: SyncoreSqlDriver;\n runtimeId: string;\n devtools: DevtoolsEngine;\n};\n\nexport class SchemaEngine<\n TSchema extends SyncoreDataModel\n> {\n private readonly disabledSearchIndexes = new Set<string>();\n\n constructor(private readonly deps: SchemaEngineDeps<TSchema>) {}\n\n async prepare(): Promise<void> {\n await this.deps.driver.exec(`\n CREATE TABLE IF NOT EXISTS \"_syncore_migrations\" (\n id TEXT PRIMARY KEY,\n applied_at INTEGER NOT NULL,\n sql TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS \"_syncore_schema_state\" (\n id TEXT PRIMARY KEY,\n schema_hash TEXT NOT NULL,\n schema_json TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n `);\n try {\n await this.deps.driver.exec(\n `ALTER TABLE \"_syncore_schema_state\" ADD COLUMN schema_json TEXT NOT NULL DEFAULT '{}'`\n );\n } catch {\n // Column already exists.\n }\n }\n\n async applySchema(): Promise<void> {\n const nextSnapshot = createSchemaSnapshot(this.deps.schema);\n const stateRow = await this.deps.driver.get<{\n schema_hash: string;\n schema_json: string;\n }>(\n `SELECT schema_hash, schema_json FROM \"_syncore_schema_state\" WHERE id = 'current'`\n );\n let previousSnapshot = null;\n if (stateRow?.schema_json && stateRow.schema_json !== \"{}\") {\n try {\n previousSnapshot = parseSchemaSnapshot(stateRow.schema_json);\n } catch {\n previousSnapshot = null;\n }\n }\n const plan = diffSchemaSnapshots(previousSnapshot, nextSnapshot);\n\n if (plan.destructiveChanges.length > 0) {\n throw new Error(\n `Syncore detected destructive schema changes that require a manual migration:\\n${plan.destructiveChanges.join(\n \"\\n\"\n )}`\n );\n }\n\n for (const warning of plan.warnings) {\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: warning,\n timestamp: Date.now()\n });\n }\n\n for (const statement of plan.statements) {\n const searchKey = this.findSearchIndexKeyForStatement(statement);\n try {\n await this.deps.driver.exec(statement);\n } catch (error) {\n if (searchKey) {\n this.disabledSearchIndexes.add(searchKey);\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `FTS5 unavailable for ${searchKey}; falling back to LIKE search.`,\n timestamp: Date.now()\n });\n continue;\n }\n throw error;\n }\n }\n\n if (plan.statements.length > 0 || plan.warnings.length > 0) {\n const migrationSql = renderMigrationSql(plan, {\n title: \"Syncore automatic schema reconciliation\"\n });\n await this.deps.driver.run(\n `INSERT OR REPLACE INTO \"_syncore_migrations\" (id, applied_at, sql) VALUES (?, ?, ?)`,\n [nextSnapshot.hash, Date.now(), migrationSql]\n );\n }\n\n await this.deps.driver.run(\n `INSERT INTO \"_syncore_schema_state\" (id, schema_hash, schema_json, updated_at)\n VALUES ('current', ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET schema_hash = excluded.schema_hash, schema_json = excluded.schema_json, updated_at = excluded.updated_at`,\n [nextSnapshot.hash, stableStringify(nextSnapshot), Date.now()]\n );\n\n for (const tableName of this.deps.schema.tableNames()) {\n const table = this.getTableDefinition(tableName);\n for (const searchIndex of table.searchIndexes) {\n const key = searchIndexKey(tableName, searchIndex.name);\n try {\n await this.deps.driver.exec(\n renderCreateSearchIndexStatement(tableName, searchIndex)\n );\n this.disabledSearchIndexes.delete(key);\n } catch {\n const alreadyDisabled = this.disabledSearchIndexes.has(key);\n this.disabledSearchIndexes.add(key);\n if (!alreadyDisabled) {\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `FTS5 unavailable for ${key}; falling back to LIKE search.`,\n timestamp: Date.now()\n });\n }\n }\n }\n }\n }\n\n getTableDefinition(\n tableName: string\n ): StructuredTableDefinition {\n return getTableDefinition(this.deps.schema, tableName);\n }\n\n isSearchIndexDisabled(tableName: string, indexName: string): boolean {\n return this.disabledSearchIndexes.has(searchIndexKey(tableName, indexName));\n }\n\n validateDocument(tableName: string, value: JsonObject): JsonObject {\n const table = this.getTableDefinition(tableName);\n const validator: StructuredValidator = table.validator;\n const parsed = validator.parse(value);\n return this.ensureRecordDocument(\n serializeValue(validator, parsed),\n \"Validated Syncore document payload must serialize to a JSON object.\"\n );\n }\n\n deserializeDocument<TDocument>(tableName: string, row: DatabaseRow): TDocument {\n const table = this.getTableDefinition(tableName);\n const validator: StructuredValidator = table.validator;\n const payload = this.parseStoredDocument(row._json);\n const deserialized = this.ensureRecordDocument(\n deserializeValue(validator, payload),\n \"Stored Syncore document payload must deserialize to a JSON object.\"\n );\n const document: StructuredRuntimeDocument = {\n ...deserialized,\n _id: row._id,\n _creationTime: row._creationTime\n };\n return document as TDocument;\n }\n\n async syncSearchIndexes(\n tableName: string,\n row: DatabaseRow\n ): Promise<void> {\n const table = this.getTableDefinition(tableName);\n if (table.searchIndexes.length === 0) {\n return;\n }\n const payload = this.parseStoredDocument(row._json);\n for (const searchIndex of table.searchIndexes) {\n if (this.isSearchIndexDisabled(tableName, searchIndex.name)) {\n continue;\n }\n const searchTable = resolveSearchIndexTableName(tableName, searchIndex.name);\n await this.deps.driver.run(\n `DELETE FROM ${quoteIdentifier(searchTable)} WHERE _id = ?`,\n [row._id]\n );\n await this.deps.driver.run(\n `INSERT INTO ${quoteIdentifier(searchTable)} (_id, search_value) VALUES (?, ?)`,\n [row._id, toSearchValue(payload[searchIndex.searchField])]\n );\n }\n }\n\n private parseStoredDocument(json: string): RecordDocument {\n const value = JSON.parse(json) as unknown;\n return this.ensureRecordDocument(\n value,\n \"Stored Syncore document payload must be a JSON object.\"\n );\n }\n\n private ensureRecordDocument(\n value: unknown,\n message: string\n ): RecordDocument {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(message);\n }\n return value as RecordDocument;\n }\n\n async removeSearchIndexes(tableName: string, id: string): Promise<void> {\n const table = this.getTableDefinition(tableName);\n for (const searchIndex of table.searchIndexes) {\n if (this.isSearchIndexDisabled(tableName, searchIndex.name)) {\n continue;\n }\n await this.deps.driver.run(\n `DELETE FROM ${quoteIdentifier(\n resolveSearchIndexTableName(tableName, searchIndex.name)\n )} WHERE _id = ?`,\n [id]\n );\n }\n }\n\n async getSchemaTablesForDevtools(): Promise<\n DevtoolsLiveQuerySnapshot[\"schemaTables\"]\n > {\n const tables = [] as DevtoolsLiveQuerySnapshot[\"schemaTables\"];\n\n for (const name of this.deps.schema.tableNames()) {\n const table = this.getTableDefinition(name);\n const validator: StructuredValidator = table.validator;\n const validatorDesc = describeValidator(validator);\n const fields =\n validatorDesc.kind === \"object\"\n ? Object.entries(validatorDesc.shape).map(\n ([fieldName, fieldDesc]) => {\n const field = fieldDesc as {\n validator: { kind: string };\n optional: boolean;\n };\n return {\n name: fieldName,\n type: field.validator.kind,\n optional: field.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 this.deps.driver.get<{ count: number }>(\n `SELECT COUNT(*) as count FROM ${quoteIdentifier(name)}`\n );\n documentCount = countRow?.count ?? 0;\n } catch {\n documentCount = 0;\n }\n\n tables.push({\n name,\n ...(table.options.tableName ? { displayName: table.options.tableName } : {}),\n owner: table.options.componentPath ? \"component\" : \"root\",\n ...(table.options.componentPath\n ? { componentPath: table.options.componentPath }\n : {}),\n ...(table.options.componentName\n ? { componentName: table.options.componentName }\n : {}),\n fields,\n indexes: table.indexes.map((index) => ({\n name: index.name,\n fields: index.fields,\n unique: false\n })),\n documentCount\n });\n }\n\n return tables;\n }\n\n private findSearchIndexKeyForStatement(statement: string): string | null {\n for (const tableName of this.deps.schema.tableNames()) {\n const table = this.getTableDefinition(tableName);\n for (const searchIndex of table.searchIndexes) {\n if (\n statement === renderCreateSearchIndexStatement(tableName, searchIndex)\n ) {\n return searchIndexKey(tableName, searchIndex.name);\n }\n }\n }\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schemaEngine.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/schemaEngine.ts"],"sourcesContent":["import {\n describeValidator,\n createSchemaSnapshot,\n deserializeValue,\n diffSchemaSnapshots,\n parseSchemaSnapshot,\n renderCreateSearchIndexStatement,\n renderMigrationSql,\n serializeValue,\n type Validator\n} from \"@syncore/schema\";\nimport type {\n TableDefinition\n} from \"@syncore/schema\";\nimport type {\n DevtoolsLiveQuerySnapshot,\n JsonObject,\n SyncoreDataModel,\n SyncoreSqlDriver\n} from \"../../runtime.js\";\nimport {\n getTableDefinition,\n quoteIdentifier,\n resolveSearchIndexTableName,\n searchIndexKey,\n stableStringify,\n toSearchValue,\n type DatabaseRow\n} from \"./shared.js\";\nimport { type DevtoolsEngine } from \"./devtoolsEngine.js\";\n\ntype RecordDocument = Record<string, unknown>;\ntype StructuredValidator = Validator<RecordDocument, RecordDocument, string>;\ntype StructuredTableDefinition = TableDefinition<StructuredValidator>;\ntype SystemDocumentFields = {\n _id: string;\n _creationTime: number;\n};\ntype StructuredRuntimeDocument = RecordDocument & SystemDocumentFields;\n\ntype SchemaEngineDeps<TSchema extends SyncoreDataModel> = {\n schema: TSchema;\n driver: SyncoreSqlDriver;\n runtimeId: string;\n devtools: DevtoolsEngine;\n};\n\nexport class SchemaEngine<\n TSchema extends SyncoreDataModel\n> {\n private readonly disabledSearchIndexes = new Set<string>();\n\n constructor(private readonly deps: SchemaEngineDeps<TSchema>) {}\n\n async prepare(): Promise<void> {\n await this.deps.driver.exec(`\n CREATE TABLE IF NOT EXISTS \"_syncore_migrations\" (\n id TEXT PRIMARY KEY,\n applied_at INTEGER NOT NULL,\n sql TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS \"_syncore_schema_state\" (\n id TEXT PRIMARY KEY,\n schema_hash TEXT NOT NULL,\n schema_json TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n `);\n try {\n await this.deps.driver.exec(\n `ALTER TABLE \"_syncore_schema_state\" ADD COLUMN schema_json TEXT NOT NULL DEFAULT '{}'`\n );\n } catch {\n // Column already exists.\n }\n }\n\n async applySchema(): Promise<void> {\n const nextSnapshot = createSchemaSnapshot(this.deps.schema);\n const stateRow = await this.deps.driver.get<{\n schema_hash: string;\n schema_json: string;\n }>(\n `SELECT schema_hash, schema_json FROM \"_syncore_schema_state\" WHERE id = 'current'`\n );\n let previousSnapshot = null;\n if (stateRow?.schema_json && stateRow.schema_json !== \"{}\") {\n try {\n previousSnapshot = parseSchemaSnapshot(stateRow.schema_json);\n } catch {\n previousSnapshot = null;\n }\n }\n const plan = diffSchemaSnapshots(previousSnapshot, nextSnapshot);\n\n if (plan.destructiveChanges.length > 0) {\n throw new Error(\n `Syncore detected destructive schema changes that require a manual migration:\\n${plan.destructiveChanges.join(\n \"\\n\"\n )}`\n );\n }\n\n for (const warning of plan.warnings) {\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: warning,\n timestamp: Date.now()\n });\n }\n\n for (const statement of plan.statements) {\n const searchKey = this.findSearchIndexKeyForStatement(statement);\n try {\n await this.deps.driver.exec(statement);\n } catch (error) {\n if (searchKey) {\n this.disabledSearchIndexes.add(searchKey);\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `FTS5 unavailable for ${searchKey}; falling back to LIKE search.`,\n timestamp: Date.now()\n });\n continue;\n }\n throw error;\n }\n }\n\n if (plan.statements.length > 0 || plan.warnings.length > 0) {\n const migrationSql = renderMigrationSql(plan, {\n title: \"Syncore automatic schema reconciliation\"\n });\n await this.deps.driver.run(\n `INSERT OR REPLACE INTO \"_syncore_migrations\" (id, applied_at, sql) VALUES (?, ?, ?)`,\n [nextSnapshot.hash, Date.now(), migrationSql]\n );\n }\n\n await this.deps.driver.run(\n `INSERT INTO \"_syncore_schema_state\" (id, schema_hash, schema_json, updated_at)\n VALUES ('current', ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET schema_hash = excluded.schema_hash, schema_json = excluded.schema_json, updated_at = excluded.updated_at`,\n [nextSnapshot.hash, stableStringify(nextSnapshot), Date.now()]\n );\n\n for (const tableName of this.deps.schema.tableNames()) {\n const table = this.getTableDefinition(tableName);\n for (const searchIndex of table.searchIndexes) {\n const key = searchIndexKey(tableName, searchIndex.name);\n try {\n await this.deps.driver.exec(\n renderCreateSearchIndexStatement(tableName, searchIndex)\n );\n this.disabledSearchIndexes.delete(key);\n } catch {\n const alreadyDisabled = this.disabledSearchIndexes.has(key);\n this.disabledSearchIndexes.add(key);\n if (!alreadyDisabled) {\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `FTS5 unavailable for ${key}; falling back to LIKE search.`,\n timestamp: Date.now()\n });\n }\n }\n }\n }\n }\n\n getTableDefinition(\n tableName: string\n ): StructuredTableDefinition {\n return getTableDefinition(this.deps.schema, tableName);\n }\n\n isSearchIndexDisabled(tableName: string, indexName: string): boolean {\n return this.disabledSearchIndexes.has(searchIndexKey(tableName, indexName));\n }\n\n validateDocument(tableName: string, value: JsonObject): JsonObject {\n const table = this.getTableDefinition(tableName);\n const validator: StructuredValidator = table.validator;\n const parsed = validator.parse(value);\n return this.ensureRecordDocument(\n serializeValue(validator, parsed),\n \"Validated Syncore document payload must serialize to a JSON object.\"\n );\n }\n\n deserializeDocument<TDocument>(tableName: string, row: DatabaseRow): TDocument {\n const table = this.getTableDefinition(tableName);\n const validator: StructuredValidator = table.validator;\n const payload = this.parseStoredDocument(row._json);\n const deserialized = this.ensureRecordDocument(\n deserializeValue(validator, payload),\n \"Stored Syncore document payload must deserialize to a JSON object.\"\n );\n const document: StructuredRuntimeDocument = {\n ...deserialized,\n _id: row._id,\n _creationTime: row._creationTime\n };\n return document as TDocument;\n }\n\n async syncSearchIndexes(\n tableName: string,\n row: DatabaseRow\n ): Promise<void> {\n const table = this.getTableDefinition(tableName);\n if (table.searchIndexes.length === 0) {\n return;\n }\n const payload = this.parseStoredDocument(row._json);\n for (const searchIndex of table.searchIndexes) {\n if (this.isSearchIndexDisabled(tableName, searchIndex.name)) {\n continue;\n }\n const searchTable = resolveSearchIndexTableName(tableName, searchIndex.name);\n await this.deps.driver.run(\n `DELETE FROM ${quoteIdentifier(searchTable)} WHERE _id = ?`,\n [row._id]\n );\n await this.deps.driver.run(\n `INSERT INTO ${quoteIdentifier(searchTable)} (_id, search_value) VALUES (?, ?)`,\n [row._id, toSearchValue(payload[searchIndex.searchField])]\n );\n }\n }\n\n private parseStoredDocument(json: string): RecordDocument {\n const value = JSON.parse(json) as unknown;\n return this.ensureRecordDocument(\n value,\n \"Stored Syncore document payload must be a JSON object.\"\n );\n }\n\n private ensureRecordDocument(\n value: unknown,\n message: string\n ): RecordDocument {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(message);\n }\n return value as RecordDocument;\n }\n\n async removeSearchIndexes(tableName: string, id: string): Promise<void> {\n const table = this.getTableDefinition(tableName);\n for (const searchIndex of table.searchIndexes) {\n if (this.isSearchIndexDisabled(tableName, searchIndex.name)) {\n continue;\n }\n await this.deps.driver.run(\n `DELETE FROM ${quoteIdentifier(\n resolveSearchIndexTableName(tableName, searchIndex.name)\n )} WHERE _id = ?`,\n [id]\n );\n }\n }\n\n async getSchemaTablesForDevtools(): Promise<\n DevtoolsLiveQuerySnapshot[\"schemaTables\"]\n > {\n const tables = [] as DevtoolsLiveQuerySnapshot[\"schemaTables\"];\n\n for (const name of this.deps.schema.tableNames()) {\n const table = this.getTableDefinition(name);\n const validator: StructuredValidator = table.validator;\n const validatorDesc = describeValidator(validator);\n const fields =\n validatorDesc.kind === \"object\"\n ? Object.entries(validatorDesc.shape).map(\n ([fieldName, fieldDesc]) => {\n const field = fieldDesc as {\n validator: { kind: string; tableName?: string };\n optional: boolean;\n };\n return {\n name: fieldName,\n type: field.validator.kind,\n optional: field.optional,\n ...(field.validator.kind === \"id\" && field.validator.tableName\n ? { referenceTable: field.validator.tableName }\n : {})\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 const documentCount = await this.deps.driver\n .get<{ count: number }>(\n `SELECT COUNT(*) as count FROM ${quoteIdentifier(name)}`\n )\n .then((countRow) => countRow?.count ?? 0)\n .catch(() => 0);\n\n tables.push({\n name,\n ...(table.options.tableName ? { displayName: table.options.tableName } : {}),\n owner: table.options.componentPath ? \"component\" : \"root\",\n ...(table.options.componentPath\n ? { componentPath: table.options.componentPath }\n : {}),\n ...(table.options.componentName\n ? { componentName: table.options.componentName }\n : {}),\n fields,\n indexes: table.indexes.map((index) => ({\n name: index.name,\n fields: index.fields,\n unique: false\n })),\n documentCount\n });\n }\n\n return tables;\n }\n\n private findSearchIndexKeyForStatement(statement: string): string | null {\n for (const tableName of this.deps.schema.tableNames()) {\n const table = this.getTableDefinition(tableName);\n for (const searchIndex of table.searchIndexes) {\n if (\n statement === renderCreateSearchIndexStatement(tableName, searchIndex)\n ) {\n return searchIndexKey(tableName, searchIndex.name);\n }\n }\n }\n return null;\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,81 @@
1
1
  import { searchIndexTableName } from "../../../../schema/index.js";
2
2
  import { fromZonedTime, toZonedTime } from "date-fns-tz";
3
3
  //#region src/runtime/internal/engines/shared.ts
4
+ const PREVIEW_MAX_DEPTH = 5;
5
+ const PREVIEW_MAX_ARRAY_ITEMS = 50;
6
+ const PREVIEW_MAX_OBJECT_KEYS = 80;
7
+ const PREVIEW_MAX_STRING_LENGTH = 4e3;
8
+ function createDevtoolsPreview(value) {
9
+ const seen = /* @__PURE__ */ new WeakSet();
10
+ let truncated = false;
11
+ const preview = (input, depth) => {
12
+ if (typeof input === "string") {
13
+ if (input.length > PREVIEW_MAX_STRING_LENGTH) {
14
+ truncated = true;
15
+ return `${input.slice(0, PREVIEW_MAX_STRING_LENGTH)}...`;
16
+ }
17
+ return input;
18
+ }
19
+ if (input === null || typeof input === "number" || typeof input === "boolean") return input;
20
+ if (typeof input === "bigint") return `${input.toString()}n`;
21
+ if (input === void 0) return "[undefined]";
22
+ if (typeof input === "function") {
23
+ truncated = true;
24
+ return "[function]";
25
+ }
26
+ if (typeof input === "symbol") {
27
+ truncated = true;
28
+ return input.toString();
29
+ }
30
+ if (input instanceof Error) return {
31
+ name: input.name,
32
+ message: input.message,
33
+ ...input.stack ? { stack: input.stack } : {}
34
+ };
35
+ if (input instanceof Date) return input.toISOString();
36
+ if (typeof input !== "object") return String(input);
37
+ if (seen.has(input)) {
38
+ truncated = true;
39
+ return "[circular]";
40
+ }
41
+ if (depth >= PREVIEW_MAX_DEPTH) {
42
+ truncated = true;
43
+ return Array.isArray(input) ? "[array]" : "[object]";
44
+ }
45
+ seen.add(input);
46
+ if (Array.isArray(input)) {
47
+ const items = input.slice(0, PREVIEW_MAX_ARRAY_ITEMS).map((item) => preview(item, depth + 1));
48
+ if (input.length > PREVIEW_MAX_ARRAY_ITEMS) {
49
+ truncated = true;
50
+ items.push(`[${input.length - PREVIEW_MAX_ARRAY_ITEMS} more items]`);
51
+ }
52
+ seen.delete(input);
53
+ return items;
54
+ }
55
+ const entries = Object.entries(input);
56
+ const result = {};
57
+ for (const [key, nested] of entries.slice(0, PREVIEW_MAX_OBJECT_KEYS)) result[key] = preview(nested, depth + 1);
58
+ if (entries.length > PREVIEW_MAX_OBJECT_KEYS) {
59
+ truncated = true;
60
+ result.__truncatedKeys = entries.length - PREVIEW_MAX_OBJECT_KEYS;
61
+ }
62
+ seen.delete(input);
63
+ return result;
64
+ };
65
+ try {
66
+ return {
67
+ kind: "value",
68
+ value: preview(value, 0),
69
+ ...truncated ? { truncated: true } : {}
70
+ };
71
+ } catch (error) {
72
+ return {
73
+ kind: "error",
74
+ message: error instanceof Error ? error.message : String(error),
75
+ truncated: true
76
+ };
77
+ }
78
+ }
4
79
  function fieldExpression(tableAlias, field) {
5
80
  return `json_extract(${tableAlias ? `${tableAlias}.` : ""}_json, '$.${field}')`;
6
81
  }
@@ -172,6 +247,6 @@ function isDayOfWeek(value) {
172
247
  return value === "sunday" || value === "monday" || value === "tuesday" || value === "wednesday" || value === "thursday" || value === "friday" || value === "saturday";
173
248
  }
174
249
  //#endregion
175
- export { computeNextRun, devtoolsScopesForEvent, fieldExpression, getTableDefinition, inferDriverDatabasePath, normalizeOptionalArgs, omitSystemFields, parseCanonicalComponentFunctionName, parseComponentScopedIdentifier, parseMisfirePolicy, quoteIdentifier, resolveSearchIndexTableName, safeReadRecurringSchedule, searchIndexKey, shouldRunMissedJob, splitSchedulerArgs, stableStringify, toSearchValue };
250
+ export { computeNextRun, createDevtoolsPreview, devtoolsScopesForEvent, fieldExpression, getTableDefinition, inferDriverDatabasePath, normalizeOptionalArgs, omitSystemFields, parseCanonicalComponentFunctionName, parseComponentScopedIdentifier, parseMisfirePolicy, quoteIdentifier, resolveSearchIndexTableName, safeReadRecurringSchedule, searchIndexKey, shouldRunMissedJob, splitSchedulerArgs, stableStringify, toSearchValue };
176
251
 
177
252
  //# sourceMappingURL=shared.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/shared.ts"],"sourcesContent":["import { fromZonedTime, toZonedTime } from \"date-fns-tz\";\nimport type {\n SyncoreDevtoolsEvent,\n SyncoreDevtoolsEventOrigin\n} from \"@syncore/devtools-protocol\";\nimport {\n searchIndexTableName,\n type TableDefinition,\n type Validator\n} from \"@syncore/schema\";\nimport type {\n MisfirePolicy,\n RecurringSchedule,\n SyncoreFunctionKind\n} from \"../../functions.js\";\nimport type { SyncoreComponentFunctionMetadata } from \"../../components.js\";\nimport type {\n DevtoolsLiveQueryScope,\n JsonObject,\n QueryCondition,\n QueryExpression,\n SearchQuery,\n SyncoreDataModel,\n SyncoreExternalChangeReason\n} from \"../../runtime.js\";\n\nexport type DatabaseRow = {\n _id: string;\n _creationTime: number;\n _json: string;\n};\n\nexport type DependencyKey = string;\n\nexport type ActiveQueryRecord = {\n id: string;\n functionName: string;\n args: JsonObject;\n listeners: Set<() => void>;\n consumers: number;\n dependencyKeys: Set<DependencyKey>;\n lastResult: unknown;\n lastError: Error | undefined;\n lastRunAt: number;\n};\n\nexport type DevtoolsEventMeta = {\n origin?: SyncoreDevtoolsEventOrigin;\n};\n\nexport type ScheduledJobRow = {\n id: string;\n function_name: string;\n function_kind: SyncoreFunctionKind;\n args_json: string;\n status: \"scheduled\" | \"completed\" | \"failed\" | \"cancelled\" | \"skipped\";\n run_at: number;\n created_at: number;\n updated_at: number;\n recurring_name: string | null;\n schedule_json: string | null;\n timezone: string | null;\n misfire_policy: string;\n last_run_at: number | null;\n window_ms: number | null;\n};\n\nexport type StorageMetadataRow = {\n _id: string;\n _creationTime: number;\n file_name: string | null;\n content_type: string | null;\n size: number;\n path: string;\n};\n\nexport type StoragePendingRow = {\n _id: string;\n _creationTime: number;\n file_name: string | null;\n content_type: string | null;\n};\n\nexport type QuerySource =\n | { type: \"table\" }\n | { type: \"index\"; name: string; range: QueryCondition[] }\n | { type: \"search\"; name: string; query: SearchQuery };\n\nexport type ExecuteQueryBuilderOptions = {\n tableName: string;\n source: QuerySource;\n filterExpression: QueryExpression | undefined;\n orderDirection: \"asc\" | \"desc\";\n dependencyCollector?: Set<DependencyKey>;\n limit?: number;\n offset?: number;\n};\n\nexport type RuntimeExecutionState = {\n mutationDepth: number;\n changedTables: Set<string>;\n storageChanges: Array<{\n storageId: string;\n reason: Extract<\n SyncoreExternalChangeReason,\n \"storage-put\" | \"storage-delete\"\n >;\n }>;\n dependencyCollector?: Set<DependencyKey>;\n componentMetadata?: SyncoreComponentFunctionMetadata | undefined;\n};\n\nexport function fieldExpression(tableAlias: string, field: string): string {\n const prefix = tableAlias ? `${tableAlias}.` : \"\";\n return `json_extract(${prefix}_json, '$.${field}')`;\n}\n\nexport function quoteIdentifier(identifier: string): string {\n return `\"${identifier.replaceAll('\"', '\"\"')}\"`;\n}\n\nexport function stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nexport function 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\nexport function omitSystemFields<TDocument extends object>(\n document: TDocument\n): JsonObject {\n const clone = { ...(document as Record<string, unknown>) };\n delete clone._id;\n delete clone._creationTime;\n return clone;\n}\n\nexport function 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\nexport function parseMisfirePolicy(\n type: string,\n windowMs: number | null\n): MisfirePolicy {\n if (type === \"windowed\") {\n return { type, windowMs: windowMs ?? 0 };\n }\n if (type === \"skip\" || type === \"run_once_if_missed\") {\n return { type };\n }\n return { type: \"catch_up\" };\n}\n\nexport function shouldRunMissedJob(\n scheduledAt: number,\n now: number,\n policy: MisfirePolicy\n): boolean {\n if (scheduledAt >= now) {\n return true;\n }\n switch (policy.type) {\n case \"catch_up\":\n return true;\n case \"run_once_if_missed\":\n return true;\n case \"skip\":\n return false;\n case \"windowed\":\n return now - scheduledAt <= policy.windowMs;\n }\n}\n\nexport function computeNextRun(\n schedule: RecurringSchedule,\n fromTimestamp: number\n): number {\n switch (schedule.type) {\n case \"interval\":\n return fromTimestamp + intervalToMs(schedule);\n case \"daily\":\n return nextDailyOccurrence(fromTimestamp, schedule);\n case \"weekly\":\n return nextWeeklyOccurrence(fromTimestamp, schedule);\n }\n}\n\nexport function safeReadRecurringSchedule(\n scheduleJson: string | null\n): RecurringSchedule | undefined {\n if (!scheduleJson) {\n return undefined;\n }\n try {\n const parsed = JSON.parse(scheduleJson) as unknown;\n return isRecurringSchedule(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function normalizeOptionalArgs<TArgs>(\n args: [] | [TArgs] | readonly unknown[]\n): TArgs {\n return (args[0] ?? {}) as TArgs;\n}\n\nexport function splitSchedulerArgs(\n args: readonly unknown[]\n): [JsonObject, MisfirePolicy | undefined] {\n if (args.length === 0) {\n return [{}, undefined];\n }\n if (args.length === 1) {\n const [first] = args;\n if (isMisfirePolicy(first)) {\n return [{}, first];\n }\n return [(first ?? {}) as JsonObject, undefined];\n }\n return [(args[0] ?? {}) as JsonObject, args[1] as MisfirePolicy | undefined];\n}\n\nexport function inferDriverDatabasePath(driver: {\n filename?: string;\n databasePath?: string;\n}): string | undefined {\n return driver.databasePath ?? driver.filename;\n}\n\nexport function parseCanonicalComponentFunctionName(functionName: string):\n | {\n componentPath: string;\n visibility: \"public\" | \"internal\";\n localName: string;\n }\n | undefined {\n const match = /^components\\/(.+)\\/(public|internal)\\/(.+)$/.exec(functionName);\n if (!match) {\n return undefined;\n }\n return {\n componentPath: match[1] ?? \"\",\n visibility: (match[2] as \"public\" | \"internal\") ?? \"public\",\n localName: match[3] ?? \"\"\n };\n}\n\nexport function parseComponentScopedIdentifier(\n value: string\n): { componentPath: string; localId: string } | undefined {\n const match = /^component:([^:]+):(.+)$/.exec(value);\n if (!match) {\n return undefined;\n }\n return {\n componentPath: match[1] ?? \"\",\n localId: match[2] ?? \"\"\n };\n}\n\nexport function devtoolsScopesForEvent(\n event: SyncoreDevtoolsEvent\n): Set<DevtoolsLiveQueryScope> {\n switch (event.type) {\n case \"runtime.connected\":\n case \"runtime.disconnected\":\n return new Set([\"runtime.summary\", \"runtime.activeQueries\"]);\n case \"query.executed\":\n case \"query.invalidated\":\n return new Set([\"runtime.summary\", \"runtime.activeQueries\"]);\n case \"mutation.committed\":\n return new Set([\n \"runtime.summary\",\n ...event.changedTables.map((table: string) => `table:${table}` as const)\n ]);\n case \"scheduler.tick\":\n return new Set([\"scheduler.jobs\", \"runtime.summary\"]);\n case \"storage.updated\":\n return new Set([\"runtime.summary\"]);\n case \"action.completed\":\n case \"log\":\n return new Set([\"runtime.summary\"]);\n default:\n return new Set([\"runtime.summary\"]);\n }\n}\n\nexport function getTableDefinition<\n TSchema extends SyncoreDataModel\n>(\n schema: TSchema,\n tableName: string\n): TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>\n> {\n return schema.getTable(tableName as never) as TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>\n >;\n}\n\nexport function searchIndexKey(tableName: string, indexName: string): string {\n return `${tableName}:${indexName}`;\n}\n\nexport function resolveSearchIndexTableName(\n tableName: string,\n indexName: string\n): string {\n return searchIndexTableName(tableName, indexName);\n}\n\nfunction intervalToMs(schedule: {\n seconds?: number;\n minutes?: number;\n hours?: number;\n}): number {\n if (schedule.seconds) {\n return schedule.seconds * 1000;\n }\n if (schedule.minutes) {\n return schedule.minutes * 60 * 1000;\n }\n return (schedule.hours ?? 1) * 60 * 60 * 1000;\n}\n\nfunction nextDailyOccurrence(\n fromTimestamp: number,\n schedule: Extract<RecurringSchedule, { type: \"daily\" }>\n): number {\n const timezone = schedule.timezone ?? \"UTC\";\n const now = new Date(fromTimestamp);\n const zonedNow = toZonedTime(now, timezone);\n const zoned = new Date(zonedNow.getTime());\n zoned.setHours(schedule.hour, schedule.minute, 0, 0);\n if (zoned.getTime() <= zonedNow.getTime()) {\n zoned.setDate(zoned.getDate() + 1);\n }\n return fromZonedTime(zoned, timezone).getTime();\n}\n\nfunction nextWeeklyOccurrence(\n fromTimestamp: number,\n schedule: Extract<RecurringSchedule, { type: \"weekly\" }>\n): number {\n const timezone = schedule.timezone ?? \"UTC\";\n const now = new Date(fromTimestamp);\n const zonedNow = toZonedTime(now, timezone);\n const targetDay = [\n \"sunday\",\n \"monday\",\n \"tuesday\",\n \"wednesday\",\n \"thursday\",\n \"friday\",\n \"saturday\"\n ].indexOf(schedule.dayOfWeek);\n const zoned = new Date(zonedNow.getTime());\n const delta = (targetDay - zonedNow.getDay() + 7) % 7;\n zoned.setDate(zoned.getDate() + delta);\n zoned.setHours(schedule.hour, schedule.minute, 0, 0);\n if (zoned.getTime() <= zonedNow.getTime()) {\n zoned.setDate(zoned.getDate() + 7);\n }\n return fromZonedTime(zoned, timezone).getTime();\n}\n\nfunction isRecurringSchedule(value: unknown): value is RecurringSchedule {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n switch (value.type) {\n case \"interval\":\n return (\n isOptionalNumber(value.seconds) &&\n isOptionalNumber(value.minutes) &&\n isOptionalNumber(value.hours)\n );\n case \"daily\":\n return (\n typeof value.hour === \"number\" &&\n typeof value.minute === \"number\" &&\n isOptionalString(value.timezone)\n );\n case \"weekly\":\n return (\n isDayOfWeek(value.dayOfWeek) &&\n typeof value.hour === \"number\" &&\n typeof value.minute === \"number\" &&\n isOptionalString(value.timezone)\n );\n default:\n return false;\n }\n}\n\nfunction isMisfirePolicy(value: unknown): value is MisfirePolicy {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isOptionalNumber(value: unknown): value is number | undefined {\n return value === undefined || typeof value === \"number\";\n}\n\nfunction isOptionalString(value: unknown): value is string | undefined {\n return value === undefined || typeof value === \"string\";\n}\n\nfunction isDayOfWeek(\n value: unknown\n): value is Extract<RecurringSchedule, { type: \"weekly\" }>[\"dayOfWeek\"] {\n return (\n value === \"sunday\" ||\n value === \"monday\" ||\n value === \"tuesday\" ||\n value === \"wednesday\" ||\n value === \"thursday\" ||\n value === \"friday\" ||\n value === \"saturday\"\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/shared.ts"],"sourcesContent":["import { fromZonedTime, toZonedTime } from \"date-fns-tz\";\nimport type {\n DevtoolsPreview,\n DocumentChangePreview,\n SyncoreDevtoolsEvent,\n SyncoreDevtoolsEventOrigin\n} from \"@syncore/devtools-protocol\";\nimport {\n searchIndexTableName,\n type TableDefinition,\n type Validator\n} from \"@syncore/schema\";\nimport type {\n MisfirePolicy,\n RecurringSchedule,\n SyncoreFunctionKind\n} from \"../../functions.js\";\nimport type { SyncoreComponentFunctionMetadata } from \"../../components.js\";\nimport type {\n DevtoolsLiveQueryScope,\n JsonObject,\n QueryCondition,\n QueryExpression,\n SearchQuery,\n SyncoreDataModel,\n SyncoreExternalChangeReason\n} from \"../../runtime.js\";\n\nexport type DatabaseRow = {\n _id: string;\n _creationTime: number;\n _json: string;\n};\n\nexport type DependencyKey = string;\n\nexport type ActiveQueryRecord = {\n id: string;\n functionName: string;\n args: JsonObject;\n listeners: Set<() => void>;\n consumers: number;\n dependencyKeys: Set<DependencyKey>;\n lastResult: unknown;\n lastError: Error | undefined;\n lastRunAt: number;\n};\n\nexport type DevtoolsEventMeta = {\n origin?: SyncoreDevtoolsEventOrigin;\n executionId?: string;\n parentExecutionId?: string;\n schedulerJobId?: string;\n schedulerRun?: boolean;\n};\n\nexport type ScheduledJobRow = {\n id: string;\n function_name: string;\n function_kind: SyncoreFunctionKind;\n args_json: string;\n status: \"scheduled\" | \"completed\" | \"failed\" | \"cancelled\" | \"skipped\";\n run_at: number;\n created_at: number;\n updated_at: number;\n recurring_name: string | null;\n schedule_json: string | null;\n timezone: string | null;\n misfire_policy: string;\n last_run_at: number | null;\n window_ms: number | null;\n};\n\nexport type StorageMetadataRow = {\n _id: string;\n _creationTime: number;\n file_name: string | null;\n content_type: string | null;\n size: number;\n path: string;\n};\n\nexport type StoragePendingRow = {\n _id: string;\n _creationTime: number;\n file_name: string | null;\n content_type: string | null;\n};\n\nexport type QuerySource =\n | { type: \"table\" }\n | { type: \"index\"; name: string; range: QueryCondition[] }\n | { type: \"search\"; name: string; query: SearchQuery };\n\nexport type ExecuteQueryBuilderOptions = {\n tableName: string;\n source: QuerySource;\n filterExpression: QueryExpression | undefined;\n orderDirection: \"asc\" | \"desc\";\n dependencyCollector?: Set<DependencyKey>;\n limit?: number;\n offset?: number;\n};\n\nexport type RuntimeExecutionState = {\n executionId?: string;\n mutationDepth: number;\n changedTables: Set<string>;\n documentChanges: DocumentChangePreview[];\n storageChanges: Array<{\n storageId: string;\n reason: Extract<\n SyncoreExternalChangeReason,\n \"storage-put\" | \"storage-delete\"\n >;\n }>;\n dependencyCollector?: Set<DependencyKey>;\n componentMetadata?: SyncoreComponentFunctionMetadata | undefined;\n};\n\nconst PREVIEW_MAX_DEPTH = 5;\nconst PREVIEW_MAX_ARRAY_ITEMS = 50;\nconst PREVIEW_MAX_OBJECT_KEYS = 80;\nconst PREVIEW_MAX_STRING_LENGTH = 4000;\n\nexport function createDevtoolsPreview(value: unknown): DevtoolsPreview {\n const seen = new WeakSet<object>();\n let truncated = false;\n\n const preview = (input: unknown, depth: number): unknown => {\n if (typeof input === \"string\") {\n if (input.length > PREVIEW_MAX_STRING_LENGTH) {\n truncated = true;\n return `${input.slice(0, PREVIEW_MAX_STRING_LENGTH)}...`;\n }\n return input;\n }\n if (\n input === null ||\n typeof input === \"number\" ||\n typeof input === \"boolean\"\n ) {\n return input;\n }\n if (typeof input === \"bigint\") {\n return `${input.toString()}n`;\n }\n if (input === undefined) {\n return \"[undefined]\";\n }\n if (typeof input === \"function\") {\n truncated = true;\n return \"[function]\";\n }\n if (typeof input === \"symbol\") {\n truncated = true;\n return input.toString();\n }\n if (input instanceof Error) {\n return {\n name: input.name,\n message: input.message,\n ...(input.stack ? { stack: input.stack } : {})\n };\n }\n if (input instanceof Date) {\n return input.toISOString();\n }\n if (typeof input !== \"object\") {\n return String(input);\n }\n if (seen.has(input)) {\n truncated = true;\n return \"[circular]\";\n }\n if (depth >= PREVIEW_MAX_DEPTH) {\n truncated = true;\n return Array.isArray(input) ? \"[array]\" : \"[object]\";\n }\n\n seen.add(input);\n if (Array.isArray(input)) {\n const items = input\n .slice(0, PREVIEW_MAX_ARRAY_ITEMS)\n .map((item) => preview(item, depth + 1));\n if (input.length > PREVIEW_MAX_ARRAY_ITEMS) {\n truncated = true;\n items.push(`[${input.length - PREVIEW_MAX_ARRAY_ITEMS} more items]`);\n }\n seen.delete(input);\n return items;\n }\n\n const entries = Object.entries(input as Record<string, unknown>);\n const result: Record<string, unknown> = {};\n for (const [key, nested] of entries.slice(0, PREVIEW_MAX_OBJECT_KEYS)) {\n result[key] = preview(nested, depth + 1);\n }\n if (entries.length > PREVIEW_MAX_OBJECT_KEYS) {\n truncated = true;\n result.__truncatedKeys = entries.length - PREVIEW_MAX_OBJECT_KEYS;\n }\n seen.delete(input);\n return result;\n };\n\n try {\n return {\n kind: \"value\",\n value: preview(value, 0),\n ...(truncated ? { truncated: true } : {})\n };\n } catch (error) {\n return {\n kind: \"error\",\n message: error instanceof Error ? error.message : String(error),\n truncated: true\n };\n }\n}\n\nexport function fieldExpression(tableAlias: string, field: string): string {\n const prefix = tableAlias ? `${tableAlias}.` : \"\";\n return `json_extract(${prefix}_json, '$.${field}')`;\n}\n\nexport function quoteIdentifier(identifier: string): string {\n return `\"${identifier.replaceAll('\"', '\"\"')}\"`;\n}\n\nexport function stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nexport function 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\nexport function omitSystemFields<TDocument extends object>(\n document: TDocument\n): JsonObject {\n const clone = { ...(document as Record<string, unknown>) };\n delete clone._id;\n delete clone._creationTime;\n return clone;\n}\n\nexport function 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\nexport function parseMisfirePolicy(\n type: string,\n windowMs: number | null\n): MisfirePolicy {\n if (type === \"windowed\") {\n return { type, windowMs: windowMs ?? 0 };\n }\n if (type === \"skip\" || type === \"run_once_if_missed\") {\n return { type };\n }\n return { type: \"catch_up\" };\n}\n\nexport function shouldRunMissedJob(\n scheduledAt: number,\n now: number,\n policy: MisfirePolicy\n): boolean {\n if (scheduledAt >= now) {\n return true;\n }\n switch (policy.type) {\n case \"catch_up\":\n return true;\n case \"run_once_if_missed\":\n return true;\n case \"skip\":\n return false;\n case \"windowed\":\n return now - scheduledAt <= policy.windowMs;\n }\n}\n\nexport function computeNextRun(\n schedule: RecurringSchedule,\n fromTimestamp: number\n): number {\n switch (schedule.type) {\n case \"interval\":\n return fromTimestamp + intervalToMs(schedule);\n case \"daily\":\n return nextDailyOccurrence(fromTimestamp, schedule);\n case \"weekly\":\n return nextWeeklyOccurrence(fromTimestamp, schedule);\n }\n}\n\nexport function safeReadRecurringSchedule(\n scheduleJson: string | null\n): RecurringSchedule | undefined {\n if (!scheduleJson) {\n return undefined;\n }\n try {\n const parsed = JSON.parse(scheduleJson) as unknown;\n return isRecurringSchedule(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function normalizeOptionalArgs<TArgs>(\n args: [] | [TArgs] | readonly unknown[]\n): TArgs {\n return (args[0] ?? {}) as TArgs;\n}\n\nexport function splitSchedulerArgs(\n args: readonly unknown[]\n): [JsonObject, MisfirePolicy | undefined] {\n if (args.length === 0) {\n return [{}, undefined];\n }\n if (args.length === 1) {\n const [first] = args;\n if (isMisfirePolicy(first)) {\n return [{}, first];\n }\n return [(first ?? {}) as JsonObject, undefined];\n }\n return [(args[0] ?? {}) as JsonObject, args[1] as MisfirePolicy | undefined];\n}\n\nexport function inferDriverDatabasePath(driver: {\n filename?: string;\n databasePath?: string;\n}): string | undefined {\n return driver.databasePath ?? driver.filename;\n}\n\nexport function parseCanonicalComponentFunctionName(functionName: string):\n | {\n componentPath: string;\n visibility: \"public\" | \"internal\";\n localName: string;\n }\n | undefined {\n const match = /^components\\/(.+)\\/(public|internal)\\/(.+)$/.exec(functionName);\n if (!match) {\n return undefined;\n }\n return {\n componentPath: match[1] ?? \"\",\n visibility: (match[2] as \"public\" | \"internal\") ?? \"public\",\n localName: match[3] ?? \"\"\n };\n}\n\nexport function parseComponentScopedIdentifier(\n value: string\n): { componentPath: string; localId: string } | undefined {\n const match = /^component:([^:]+):(.+)$/.exec(value);\n if (!match) {\n return undefined;\n }\n return {\n componentPath: match[1] ?? \"\",\n localId: match[2] ?? \"\"\n };\n}\n\nexport function devtoolsScopesForEvent(\n event: SyncoreDevtoolsEvent\n): Set<DevtoolsLiveQueryScope> {\n switch (event.type) {\n case \"runtime.connected\":\n case \"runtime.disconnected\":\n return new Set([\"runtime.summary\", \"runtime.activeQueries\"]);\n case \"query.executed\":\n case \"query.invalidated\":\n return new Set([\"runtime.summary\", \"runtime.activeQueries\"]);\n case \"mutation.committed\":\n return new Set([\n \"runtime.summary\",\n ...event.changedTables.map((table: string) => `table:${table}` as const)\n ]);\n case \"scheduler.tick\":\n return new Set([\"scheduler.jobs\", \"runtime.summary\"]);\n case \"storage.updated\":\n return new Set([\"runtime.summary\"]);\n case \"action.completed\":\n case \"log\":\n return new Set([\"runtime.summary\"]);\n default:\n return new Set([\"runtime.summary\"]);\n }\n}\n\nexport function getTableDefinition<\n TSchema extends SyncoreDataModel\n>(\n schema: TSchema,\n tableName: string\n): TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>\n> {\n return schema.getTable(tableName as never) as TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>\n >;\n}\n\nexport function searchIndexKey(tableName: string, indexName: string): string {\n return `${tableName}:${indexName}`;\n}\n\nexport function resolveSearchIndexTableName(\n tableName: string,\n indexName: string\n): string {\n return searchIndexTableName(tableName, indexName);\n}\n\nfunction intervalToMs(schedule: {\n seconds?: number;\n minutes?: number;\n hours?: number;\n}): number {\n if (schedule.seconds) {\n return schedule.seconds * 1000;\n }\n if (schedule.minutes) {\n return schedule.minutes * 60 * 1000;\n }\n return (schedule.hours ?? 1) * 60 * 60 * 1000;\n}\n\nfunction nextDailyOccurrence(\n fromTimestamp: number,\n schedule: Extract<RecurringSchedule, { type: \"daily\" }>\n): number {\n const timezone = schedule.timezone ?? \"UTC\";\n const now = new Date(fromTimestamp);\n const zonedNow = toZonedTime(now, timezone);\n const zoned = new Date(zonedNow.getTime());\n zoned.setHours(schedule.hour, schedule.minute, 0, 0);\n if (zoned.getTime() <= zonedNow.getTime()) {\n zoned.setDate(zoned.getDate() + 1);\n }\n return fromZonedTime(zoned, timezone).getTime();\n}\n\nfunction nextWeeklyOccurrence(\n fromTimestamp: number,\n schedule: Extract<RecurringSchedule, { type: \"weekly\" }>\n): number {\n const timezone = schedule.timezone ?? \"UTC\";\n const now = new Date(fromTimestamp);\n const zonedNow = toZonedTime(now, timezone);\n const targetDay = [\n \"sunday\",\n \"monday\",\n \"tuesday\",\n \"wednesday\",\n \"thursday\",\n \"friday\",\n \"saturday\"\n ].indexOf(schedule.dayOfWeek);\n const zoned = new Date(zonedNow.getTime());\n const delta = (targetDay - zonedNow.getDay() + 7) % 7;\n zoned.setDate(zoned.getDate() + delta);\n zoned.setHours(schedule.hour, schedule.minute, 0, 0);\n if (zoned.getTime() <= zonedNow.getTime()) {\n zoned.setDate(zoned.getDate() + 7);\n }\n return fromZonedTime(zoned, timezone).getTime();\n}\n\nfunction isRecurringSchedule(value: unknown): value is RecurringSchedule {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n switch (value.type) {\n case \"interval\":\n return (\n isOptionalNumber(value.seconds) &&\n isOptionalNumber(value.minutes) &&\n isOptionalNumber(value.hours)\n );\n case \"daily\":\n return (\n typeof value.hour === \"number\" &&\n typeof value.minute === \"number\" &&\n isOptionalString(value.timezone)\n );\n case \"weekly\":\n return (\n isDayOfWeek(value.dayOfWeek) &&\n typeof value.hour === \"number\" &&\n typeof value.minute === \"number\" &&\n isOptionalString(value.timezone)\n );\n default:\n return false;\n }\n}\n\nfunction isMisfirePolicy(value: unknown): value is MisfirePolicy {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isOptionalNumber(value: unknown): value is number | undefined {\n return value === undefined || typeof value === \"number\";\n}\n\nfunction isOptionalString(value: unknown): value is string | undefined {\n return value === undefined || typeof value === \"string\";\n}\n\nfunction isDayOfWeek(\n value: unknown\n): value is Extract<RecurringSchedule, { type: \"weekly\" }>[\"dayOfWeek\"] {\n return (\n value === \"sunday\" ||\n value === \"monday\" ||\n value === \"tuesday\" ||\n value === \"wednesday\" ||\n value === \"thursday\" ||\n value === \"friday\" ||\n value === \"saturday\"\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { generateId } from "../../id.mjs";
2
2
  //#region src/runtime/internal/engines/storageEngine.ts
3
3
  var StorageEngine = class {
4
+ deps;
4
5
  constructor(deps) {
5
6
  this.deps = deps;
6
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"storageEngine.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/storageEngine.ts"],"sourcesContent":["import type {\n StorageObject,\n SyncoreSqlDriver,\n SyncoreStorageAdapter,\n SyncoreStorageApi,\n StorageWriteInput\n} from \"../../runtime.js\";\nimport {\n type RuntimeExecutionState,\n type StorageMetadataRow,\n type StoragePendingRow\n} from \"./shared.js\";\nimport { DevtoolsEngine } from \"./devtoolsEngine.js\";\nimport { generateId } from \"../../id.js\";\n\ntype StorageEngineDeps = {\n driver: SyncoreSqlDriver;\n storage: SyncoreStorageAdapter;\n runtimeId: string;\n devtools: DevtoolsEngine;\n};\n\nexport class StorageEngine {\n constructor(private readonly deps: StorageEngineDeps) {}\n\n async prepare(): Promise<void> {\n await this.deps.driver.exec(`\n CREATE TABLE IF NOT EXISTS \"_storage\" (\n _id TEXT PRIMARY KEY,\n _creationTime INTEGER NOT NULL,\n file_name TEXT,\n content_type TEXT,\n size INTEGER NOT NULL,\n path TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS \"_storage_pending\" (\n _id TEXT PRIMARY KEY,\n _creationTime INTEGER NOT NULL,\n file_name TEXT,\n content_type TEXT\n );\n `);\n }\n\n async reconcile(): Promise<void> {\n const pendingRows = await this.deps.driver.all<StoragePendingRow>(\n `SELECT _id, _creationTime, file_name, content_type FROM \"_storage_pending\"`\n );\n\n for (const pendingRow of pendingRows) {\n const committed = await this.deps.driver.get<\n Pick<StorageMetadataRow, \"_id\">\n >(`SELECT _id FROM \"_storage\" WHERE _id = ?`, [pendingRow._id]);\n if (!committed) {\n await this.deps.storage.delete(pendingRow._id);\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `Recovered interrupted storage write ${pendingRow._id}.`,\n timestamp: Date.now()\n });\n }\n await this.deps.driver.run(\n `DELETE FROM \"_storage_pending\" WHERE _id = ?`,\n [pendingRow._id]\n );\n }\n\n if (!this.deps.storage.list) {\n return;\n }\n\n const storedRows = await this.deps.driver.all<Pick<StorageMetadataRow, \"_id\">>(\n `SELECT _id FROM \"_storage\"`\n );\n const knownIds = new Set(storedRows.map((row) => row._id));\n const physicalObjects = await this.deps.storage.list();\n for (const object of physicalObjects) {\n if (knownIds.has(object.id)) {\n continue;\n }\n await this.deps.storage.delete(object.id);\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `Removed orphaned storage object ${object.id}.`,\n timestamp: Date.now()\n });\n }\n }\n\n createStorageApi(state: RuntimeExecutionState): SyncoreStorageApi {\n const componentMetadata = state.componentMetadata;\n const namespacePrefix = componentMetadata\n ? `component:${componentMetadata.componentPath}:`\n : \"\";\n const ensureStorageCapability = () => {\n if (\n componentMetadata &&\n !componentMetadata.grantedCapabilities.includes(\"storage\")\n ) {\n throw new Error(\n `Component ${JSON.stringify(componentMetadata.componentPath)} is not allowed to use storage.`\n );\n }\n };\n const scopedId = (id: string) => `${namespacePrefix}${id}`;\n\n return {\n put: async (input: StorageWriteInput) => {\n ensureStorageCapability();\n const id = scopedId(generateId());\n const createdAt = Date.now();\n await this.deps.driver.run(\n `INSERT OR REPLACE INTO \"_storage_pending\" (_id, _creationTime, file_name, content_type) VALUES (?, ?, ?, ?)`,\n [id, createdAt, input.fileName ?? null, input.contentType ?? null]\n );\n const object = await this.deps.storage.put(id, input);\n await this.deps.driver.withTransaction(async () => {\n await this.deps.driver.run(\n `INSERT OR REPLACE INTO \"_storage\" (_id, _creationTime, file_name, content_type, size, path) VALUES (?, ?, ?, ?, ?, ?)`,\n [\n id,\n createdAt,\n input.fileName ?? null,\n object.contentType,\n object.size,\n object.path\n ]\n );\n await this.deps.driver.run(\n `DELETE FROM \"_storage_pending\" WHERE _id = ?`,\n [id]\n );\n });\n this.deps.devtools.emit({\n type: \"storage.updated\",\n runtimeId: this.deps.runtimeId,\n storageId: id,\n ...(componentMetadata\n ? { componentPath: componentMetadata.componentPath }\n : {}),\n operation: \"put\",\n timestamp: Date.now()\n });\n state.storageChanges.push({\n storageId: id,\n reason: \"storage-put\"\n });\n return id;\n },\n get: async (id: string): Promise<StorageObject | null> => {\n ensureStorageCapability();\n state.dependencyCollector?.add(`storage:${id}`);\n const row = await this.deps.driver.get<StorageMetadataRow>(\n `SELECT _id, _creationTime, file_name, content_type, size, path FROM \"_storage\" WHERE _id = ?`,\n [id]\n );\n if (!row) {\n return null;\n }\n return {\n id: row._id,\n path: row.path,\n size: row.size,\n contentType: row.content_type\n };\n },\n read: async (id: string) => {\n ensureStorageCapability();\n state.dependencyCollector?.add(`storage:${id}`);\n const row = await this.deps.driver.get<Pick<StorageMetadataRow, \"_id\">>(\n `SELECT _id FROM \"_storage\" WHERE _id = ?`,\n [id]\n );\n if (!row) {\n return null;\n }\n return this.deps.storage.read(id);\n },\n delete: async (id: string) => {\n ensureStorageCapability();\n await this.deps.storage.delete(id);\n await this.deps.driver.withTransaction(async () => {\n await this.deps.driver.run(\n `DELETE FROM \"_storage\" WHERE _id = ?`,\n [id]\n );\n await this.deps.driver.run(\n `DELETE FROM \"_storage_pending\" WHERE _id = ?`,\n [id]\n );\n });\n this.deps.devtools.emit({\n type: \"storage.updated\",\n runtimeId: this.deps.runtimeId,\n storageId: id,\n ...(componentMetadata\n ? { componentPath: componentMetadata.componentPath }\n : {}),\n operation: \"delete\",\n timestamp: Date.now()\n });\n state.storageChanges.push({\n storageId: id,\n reason: \"storage-delete\"\n });\n }\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"storageEngine.mjs","names":[],"sources":["../../../../src/runtime/internal/engines/storageEngine.ts"],"sourcesContent":["import type {\n StorageObject,\n SyncoreSqlDriver,\n SyncoreStorageAdapter,\n SyncoreStorageApi,\n StorageWriteInput\n} from \"../../runtime.js\";\nimport {\n type RuntimeExecutionState,\n type StorageMetadataRow,\n type StoragePendingRow\n} from \"./shared.js\";\nimport { DevtoolsEngine } from \"./devtoolsEngine.js\";\nimport { generateId } from \"../../id.js\";\n\ntype StorageEngineDeps = {\n driver: SyncoreSqlDriver;\n storage: SyncoreStorageAdapter;\n runtimeId: string;\n devtools: DevtoolsEngine;\n};\n\nexport class StorageEngine {\n constructor(private readonly deps: StorageEngineDeps) {}\n\n async prepare(): Promise<void> {\n await this.deps.driver.exec(`\n CREATE TABLE IF NOT EXISTS \"_storage\" (\n _id TEXT PRIMARY KEY,\n _creationTime INTEGER NOT NULL,\n file_name TEXT,\n content_type TEXT,\n size INTEGER NOT NULL,\n path TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS \"_storage_pending\" (\n _id TEXT PRIMARY KEY,\n _creationTime INTEGER NOT NULL,\n file_name TEXT,\n content_type TEXT\n );\n `);\n }\n\n async reconcile(): Promise<void> {\n const pendingRows = await this.deps.driver.all<StoragePendingRow>(\n `SELECT _id, _creationTime, file_name, content_type FROM \"_storage_pending\"`\n );\n\n for (const pendingRow of pendingRows) {\n const committed = await this.deps.driver.get<\n Pick<StorageMetadataRow, \"_id\">\n >(`SELECT _id FROM \"_storage\" WHERE _id = ?`, [pendingRow._id]);\n if (!committed) {\n await this.deps.storage.delete(pendingRow._id);\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `Recovered interrupted storage write ${pendingRow._id}.`,\n timestamp: Date.now()\n });\n }\n await this.deps.driver.run(\n `DELETE FROM \"_storage_pending\" WHERE _id = ?`,\n [pendingRow._id]\n );\n }\n\n if (!this.deps.storage.list) {\n return;\n }\n\n const storedRows = await this.deps.driver.all<Pick<StorageMetadataRow, \"_id\">>(\n `SELECT _id FROM \"_storage\"`\n );\n const knownIds = new Set(storedRows.map((row) => row._id));\n const physicalObjects = await this.deps.storage.list();\n for (const object of physicalObjects) {\n if (knownIds.has(object.id)) {\n continue;\n }\n await this.deps.storage.delete(object.id);\n this.deps.devtools.emit({\n type: \"log\",\n runtimeId: this.deps.runtimeId,\n level: \"warn\",\n message: `Removed orphaned storage object ${object.id}.`,\n timestamp: Date.now()\n });\n }\n }\n\n createStorageApi(state: RuntimeExecutionState): SyncoreStorageApi {\n const componentMetadata = state.componentMetadata;\n const namespacePrefix = componentMetadata\n ? `component:${componentMetadata.componentPath}:`\n : \"\";\n const ensureStorageCapability = () => {\n if (\n componentMetadata &&\n !componentMetadata.grantedCapabilities.includes(\"storage\")\n ) {\n throw new Error(\n `Component ${JSON.stringify(componentMetadata.componentPath)} is not allowed to use storage.`\n );\n }\n };\n const scopedId = (id: string) => `${namespacePrefix}${id}`;\n\n return {\n put: async (input: StorageWriteInput) => {\n ensureStorageCapability();\n const id = scopedId(generateId());\n const createdAt = Date.now();\n await this.deps.driver.run(\n `INSERT OR REPLACE INTO \"_storage_pending\" (_id, _creationTime, file_name, content_type) VALUES (?, ?, ?, ?)`,\n [id, createdAt, input.fileName ?? null, input.contentType ?? null]\n );\n const object = await this.deps.storage.put(id, input);\n await this.deps.driver.withTransaction(async () => {\n await this.deps.driver.run(\n `INSERT OR REPLACE INTO \"_storage\" (_id, _creationTime, file_name, content_type, size, path) VALUES (?, ?, ?, ?, ?, ?)`,\n [\n id,\n createdAt,\n input.fileName ?? null,\n object.contentType,\n object.size,\n object.path\n ]\n );\n await this.deps.driver.run(\n `DELETE FROM \"_storage_pending\" WHERE _id = ?`,\n [id]\n );\n });\n this.deps.devtools.emit({\n type: \"storage.updated\",\n runtimeId: this.deps.runtimeId,\n storageId: id,\n ...(componentMetadata\n ? { componentPath: componentMetadata.componentPath }\n : {}),\n operation: \"put\",\n timestamp: Date.now()\n });\n state.storageChanges.push({\n storageId: id,\n reason: \"storage-put\"\n });\n return id;\n },\n get: async (id: string): Promise<StorageObject | null> => {\n ensureStorageCapability();\n state.dependencyCollector?.add(`storage:${id}`);\n const row = await this.deps.driver.get<StorageMetadataRow>(\n `SELECT _id, _creationTime, file_name, content_type, size, path FROM \"_storage\" WHERE _id = ?`,\n [id]\n );\n if (!row) {\n return null;\n }\n return {\n id: row._id,\n path: row.path,\n size: row.size,\n contentType: row.content_type\n };\n },\n read: async (id: string) => {\n ensureStorageCapability();\n state.dependencyCollector?.add(`storage:${id}`);\n const row = await this.deps.driver.get<Pick<StorageMetadataRow, \"_id\">>(\n `SELECT _id FROM \"_storage\" WHERE _id = ?`,\n [id]\n );\n if (!row) {\n return null;\n }\n return this.deps.storage.read(id);\n },\n delete: async (id: string) => {\n ensureStorageCapability();\n await this.deps.storage.delete(id);\n await this.deps.driver.withTransaction(async () => {\n await this.deps.driver.run(\n `DELETE FROM \"_storage\" WHERE _id = ?`,\n [id]\n );\n await this.deps.driver.run(\n `DELETE FROM \"_storage_pending\" WHERE _id = ?`,\n [id]\n );\n });\n this.deps.devtools.emit({\n type: \"storage.updated\",\n runtimeId: this.deps.runtimeId,\n storageId: id,\n ...(componentMetadata\n ? { componentPath: componentMetadata.componentPath }\n : {}),\n operation: \"delete\",\n timestamp: Date.now()\n });\n state.storageChanges.push({\n storageId: id,\n reason: \"storage-delete\"\n });\n }\n };\n }\n}\n"],"mappings":"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"}
@@ -11,6 +11,7 @@ import { ensureSupportedSystemFormats } from "./systemMeta.mjs";
11
11
  import { RuntimeStatusController } from "./runtimeStatus.mjs";
12
12
  //#region src/runtime/internal/runtimeKernel.ts
13
13
  var RuntimeKernel = class {
14
+ options;
14
15
  runtimeId = generateId();
15
16
  platform;
16
17
  externalChangeSourceId = generateId();
@@ -64,8 +65,8 @@ var RuntimeKernel = class {
64
65
  devtools: this.devtoolsEngine,
65
66
  recurringJobs: options.scheduler?.recurringJobs ?? [],
66
67
  pollIntervalMs: options.scheduler?.pollIntervalMs ?? 1e3,
67
- runMutation: (reference, args) => this.executionEngine.runMutation(reference, args),
68
- runAction: (reference, args) => this.executionEngine.runAction(reference, args)
68
+ runMutation: (reference, args, meta) => this.executionEngine.runMutation(reference, args, meta),
69
+ runAction: (reference, args, meta) => this.executionEngine.runAction(reference, args, meta)
69
70
  });
70
71
  this.reactivityEngine = new ReactivityEngine({
71
72
  runtimeId: this.runtimeId,
@@ -73,7 +74,7 @@ var RuntimeKernel = class {
73
74
  ...options.externalChangeSignal ? { externalChangeSignal: options.externalChangeSignal } : {},
74
75
  ...options.externalChangeApplier ? { externalChangeApplier: options.externalChangeApplier } : {},
75
76
  devtools: this.devtoolsEngine,
76
- runQuery: (reference, args) => this.executionEngine.runQuery(reference, args),
77
+ runQuery: (reference, args, meta) => this.executionEngine.runQuery(reference, args, meta),
77
78
  collectQueryDependencies: (functionName, args) => this.executionEngine.collectQueryDependencies(functionName, args)
78
79
  });
79
80
  this.executionEngine = new ExecutionEngine({
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeKernel.mjs","names":[],"sources":["../../../src/runtime/internal/runtimeKernel.ts"],"sourcesContent":["import type {\n CapabilityDescriptor,\n DevtoolsLiveQueryScope,\n QueryCtx,\n SyncoreDataModel,\n SyncoreResolvedComponents,\n SyncoreCapabilities,\n SyncoreClient,\n SyncoreRuntime,\n SyncoreRuntimeAdmin,\n SyncoreRuntimeOptions,\n SyncoreWatch,\n UpdateScheduledJobOptions\n} from \"../runtime.js\";\nimport type { FunctionReference } from \"../functions.js\";\nimport type {\n SyncoreDevtoolsEvent,\n SyncoreDevtoolsEventOrigin\n} from \"@syncore/devtools-protocol\";\nimport { generateId } from \"../id.js\";\nimport { DevtoolsEngine } from \"./engines/devtoolsEngine.js\";\nimport { ExecutionEngine } from \"./engines/executionEngine.js\";\nimport { ReactivityEngine } from \"./engines/reactivityEngine.js\";\nimport { SchedulerEngine } from \"./engines/schedulerEngine.js\";\nimport { SchemaEngine } from \"./engines/schemaEngine.js\";\nimport { StorageEngine } from \"./engines/storageEngine.js\";\nimport { inferDriverDatabasePath } from \"./engines/shared.js\";\nimport { TransactionCoordinator } from \"./transactionCoordinator.js\";\nimport { ensureSupportedSystemFormats } from \"./systemMeta.js\";\nimport { RuntimeStatusController } from \"./runtimeStatus.js\";\n\ntype DevtoolsEventMeta = {\n origin?: SyncoreDevtoolsEventOrigin;\n};\n\nexport class RuntimeKernel<\n TSchema extends SyncoreDataModel\n> {\n readonly runtimeId = generateId();\n readonly platform: string;\n readonly externalChangeSourceId = generateId();\n readonly driverDatabasePath: string | undefined;\n readonly capabilities: Readonly<SyncoreCapabilities>;\n readonly capabilityDescriptors: ReadonlyArray<CapabilityDescriptor>;\n readonly devtoolsEngine: DevtoolsEngine;\n readonly schemaEngine: SchemaEngine<TSchema>;\n readonly storageEngine: StorageEngine;\n readonly schedulerEngine: SchedulerEngine;\n readonly reactivityEngine: ReactivityEngine;\n readonly executionEngine: ExecutionEngine<TSchema>;\n readonly transactionCoordinator: TransactionCoordinator;\n readonly runtimeStatus: RuntimeStatusController;\n readonly admin: SyncoreRuntimeAdmin<TSchema>;\n private prepared = false;\n private started = false;\n\n constructor(\n private readonly options: SyncoreRuntimeOptions<TSchema>,\n runtime: SyncoreRuntime<TSchema>\n ) {\n this.platform = options.platform ?? \"node\";\n this.capabilityDescriptors = Object.freeze([\n ...(options.capabilityDescriptors ?? [])\n ]);\n this.capabilities = Object.freeze({\n ...(options.capabilities ?? {})\n });\n this.driverDatabasePath = inferDriverDatabasePath(\n options.driver as { filename?: string; databasePath?: string }\n );\n this.devtoolsEngine = new DevtoolsEngine({\n runtimeId: this.runtimeId,\n platform: this.platform,\n ...(options.devtools ? { sink: options.devtools } : {}),\n getActiveQueryInfos: () => this.reactivityEngine.getActiveQueryInfos(),\n getSchemaTables: () => this.schemaEngine.getSchemaTablesForDevtools()\n });\n this.schemaEngine = new SchemaEngine({\n schema: options.schema,\n driver: options.driver,\n runtimeId: this.runtimeId,\n devtools: this.devtoolsEngine\n });\n this.storageEngine = new StorageEngine({\n driver: options.driver,\n storage: options.storage,\n runtimeId: this.runtimeId,\n devtools: this.devtoolsEngine\n });\n this.transactionCoordinator = new TransactionCoordinator(options.driver);\n this.runtimeStatus = new RuntimeStatusController({\n kind: \"starting\",\n reason: \"booting\"\n });\n this.schedulerEngine = new SchedulerEngine({\n driver: options.driver,\n runtimeId: this.runtimeId,\n devtools: this.devtoolsEngine,\n recurringJobs: options.scheduler?.recurringJobs ?? [],\n pollIntervalMs: options.scheduler?.pollIntervalMs ?? 1000,\n runMutation: (reference, args) =>\n this.executionEngine.runMutation(reference, args),\n runAction: (reference, args) => this.executionEngine.runAction(reference, args)\n });\n this.reactivityEngine = new ReactivityEngine({\n runtimeId: this.runtimeId,\n externalChangeSourceId: this.externalChangeSourceId,\n ...(options.externalChangeSignal\n ? { externalChangeSignal: options.externalChangeSignal }\n : {}),\n ...(options.externalChangeApplier\n ? { externalChangeApplier: options.externalChangeApplier }\n : {}),\n devtools: this.devtoolsEngine,\n runQuery: (reference, args) => this.executionEngine.runQuery(reference, args),\n collectQueryDependencies: (functionName, args) =>\n this.executionEngine.collectQueryDependencies(functionName, args)\n });\n this.executionEngine = new ExecutionEngine({\n runtimeId: this.runtimeId,\n functions: options.functions,\n driver: options.driver,\n capabilities: this.capabilities,\n capabilityDescriptors: this.capabilityDescriptors,\n schema: this.schemaEngine,\n storage: this.storageEngine,\n scheduler: this.schedulerEngine,\n reactivity: this.reactivityEngine,\n devtools: this.devtoolsEngine,\n transactionCoordinator: this.transactionCoordinator,\n runtimeStatus: this.runtimeStatus\n });\n this.admin = {\n prepareForDirectAccess: () => this.prepareForDirectAccess(),\n createClient: () => this.createClient(),\n runQuery: (reference, args, meta) =>\n this.executionEngine.runQuery(reference, args, meta),\n runMutation: (reference, args, meta) =>\n this.executionEngine.runMutation(reference, args, meta),\n runAction: (reference, args, meta) =>\n this.executionEngine.runAction(reference, args, meta),\n runDevtoolsMutation: async (callback, meta) => {\n await this.prepareForDirectAccess();\n return this.executionEngine.runDevtoolsMutation(callback, meta);\n },\n getRuntimeSummary: () => this.devtoolsEngine.getRuntimeSummary(),\n getActiveQueryInfos: () => this.reactivityEngine.getActiveQueryInfos(),\n getRuntimeId: () => this.runtimeId,\n getDriverDatabasePath: () => this.driverDatabasePath,\n subscribeToDevtoolsEvents: (listener) =>\n this.devtoolsEngine.subscribeEvents(listener),\n subscribeToDevtoolsInvalidations: (listener) =>\n this.devtoolsEngine.subscribeInvalidations(listener),\n notifyDevtoolsScopes: (scopes) => this.devtoolsEngine.notifyScopes(scopes),\n forceRefreshDevtools: async (reason, scopes, meta) => {\n const resolvedScopes = new Set(scopes ?? []);\n if (resolvedScopes.size > 0) {\n await this.reactivityEngine.refreshQueriesForScopes(\n resolvedScopes,\n reason\n );\n }\n await this.devtoolsEngine.forceRefresh(\n reason,\n {\n refreshQueriesForScopes: (requestedScopes, refreshReason) =>\n this.reactivityEngine.refreshQueriesForScopes(\n requestedScopes,\n refreshReason\n )\n },\n meta,\n resolvedScopes\n );\n },\n cancelScheduledJob: async (id) => {\n await this.prepareForDirectAccess();\n return this.schedulerEngine.cancelScheduledJob(id);\n },\n updateScheduledJob: async (update: UpdateScheduledJobOptions) => {\n await this.prepareForDirectAccess();\n return this.schedulerEngine.updateScheduledJob(update);\n }\n };\n options.devtools?.attachRuntime?.(runtime);\n }\n\n async start(): Promise<void> {\n if (this.started) {\n return;\n }\n this.runtimeStatus.setStatus({\n kind: \"starting\",\n reason: \"booting\"\n });\n await this.prepareForDirectAccess();\n try {\n await this.runComponentHooks(\"onStart\");\n this.reactivityEngine.start();\n this.schedulerEngine.startPolling();\n this.started = true;\n this.runtimeStatus.setStatus({\n kind: \"ready\"\n });\n this.devtoolsEngine.emit({\n type: \"runtime.connected\",\n runtimeId: this.runtimeId,\n platform: this.platform,\n timestamp: Date.now()\n });\n } catch (error) {\n this.schedulerEngine.stopPolling();\n this.reactivityEngine.stop();\n await this.options.driver.close?.().catch(() => undefined);\n this.started = false;\n this.runtimeStatus.setStatus({\n kind: \"error\",\n reason: \"runtime-unavailable\",\n ...(error instanceof Error ? { error } : {})\n });\n throw error;\n }\n }\n\n async prepareForDirectAccess(): Promise<void> {\n if (this.prepared) {\n return;\n }\n await ensureSupportedSystemFormats(this.options.driver);\n await this.schemaEngine.prepare();\n await this.storageEngine.prepare();\n await this.schedulerEngine.prepare();\n await this.storageEngine.reconcile();\n await this.schemaEngine.applySchema();\n await this.schedulerEngine.syncRecurringJobs();\n this.prepared = true;\n }\n\n async stop(): Promise<void> {\n this.schedulerEngine.stopPolling();\n let stopError: unknown;\n if (this.started) {\n try {\n await this.runComponentHooks(\"onStop\");\n } catch (error) {\n stopError = error;\n }\n }\n this.reactivityEngine.stop();\n await this.options.driver.close?.();\n if (this.started) {\n this.devtoolsEngine.emit({\n type: \"runtime.disconnected\",\n runtimeId: this.runtimeId,\n timestamp: Date.now()\n });\n }\n this.started = false;\n this.runtimeStatus.setStatus({\n kind: \"unavailable\",\n reason: \"disposed\"\n });\n if (stopError) {\n throw stopError;\n }\n }\n\n createClient(): SyncoreClient {\n return this.executionEngine.createClient();\n }\n\n watchQuery<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n args: Record<string, unknown> = {}\n ): SyncoreWatch<TResult> {\n return this.executionEngine.watchQuery(reference, args);\n }\n\n private async runComponentHooks(\n hook: \"onStart\" | \"onStop\"\n ): Promise<void> {\n for (const component of this.options.components ?? []) {\n await this.runComponentHookTree(component, hook);\n }\n }\n\n private async runComponentHookTree(\n component: SyncoreResolvedComponents[number],\n hook: \"onStart\" | \"onStop\"\n ): Promise<void> {\n const handler = component[hook];\n if (handler) {\n await handler({\n runtimeId: this.runtimeId,\n platform: this.platform,\n componentPath: component.path,\n componentName: component.name,\n version: component.version,\n config: component.config,\n capabilities: component.grantedCapabilities,\n emitDevtools: (event: SyncoreDevtoolsEvent) => {\n this.devtoolsEngine.emit(event);\n }\n });\n }\n for (const child of component.children) {\n await this.runComponentHookTree(child, hook);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtimeKernel.mjs","names":[],"sources":["../../../src/runtime/internal/runtimeKernel.ts"],"sourcesContent":["import type {\n CapabilityDescriptor,\n DevtoolsLiveQueryScope,\n QueryCtx,\n SyncoreDataModel,\n SyncoreResolvedComponents,\n SyncoreCapabilities,\n SyncoreClient,\n SyncoreRuntime,\n SyncoreRuntimeAdmin,\n SyncoreRuntimeOptions,\n SyncoreWatch,\n UpdateScheduledJobOptions\n} from \"../runtime.js\";\nimport type { FunctionReference } from \"../functions.js\";\nimport type {\n SyncoreDevtoolsEvent,\n SyncoreDevtoolsEventOrigin\n} from \"@syncore/devtools-protocol\";\nimport { generateId } from \"../id.js\";\nimport { DevtoolsEngine } from \"./engines/devtoolsEngine.js\";\nimport { ExecutionEngine } from \"./engines/executionEngine.js\";\nimport { ReactivityEngine } from \"./engines/reactivityEngine.js\";\nimport { SchedulerEngine } from \"./engines/schedulerEngine.js\";\nimport { SchemaEngine } from \"./engines/schemaEngine.js\";\nimport { StorageEngine } from \"./engines/storageEngine.js\";\nimport { inferDriverDatabasePath } from \"./engines/shared.js\";\nimport { TransactionCoordinator } from \"./transactionCoordinator.js\";\nimport { ensureSupportedSystemFormats } from \"./systemMeta.js\";\nimport { RuntimeStatusController } from \"./runtimeStatus.js\";\n\ntype DevtoolsEventMeta = {\n origin?: SyncoreDevtoolsEventOrigin;\n executionId?: string;\n parentExecutionId?: string;\n schedulerJobId?: string;\n schedulerRun?: boolean;\n};\n\nexport class RuntimeKernel<\n TSchema extends SyncoreDataModel\n> {\n readonly runtimeId = generateId();\n readonly platform: string;\n readonly externalChangeSourceId = generateId();\n readonly driverDatabasePath: string | undefined;\n readonly capabilities: Readonly<SyncoreCapabilities>;\n readonly capabilityDescriptors: ReadonlyArray<CapabilityDescriptor>;\n readonly devtoolsEngine: DevtoolsEngine;\n readonly schemaEngine: SchemaEngine<TSchema>;\n readonly storageEngine: StorageEngine;\n readonly schedulerEngine: SchedulerEngine;\n readonly reactivityEngine: ReactivityEngine;\n readonly executionEngine: ExecutionEngine<TSchema>;\n readonly transactionCoordinator: TransactionCoordinator;\n readonly runtimeStatus: RuntimeStatusController;\n readonly admin: SyncoreRuntimeAdmin<TSchema>;\n private prepared = false;\n private started = false;\n\n constructor(\n private readonly options: SyncoreRuntimeOptions<TSchema>,\n runtime: SyncoreRuntime<TSchema>\n ) {\n this.platform = options.platform ?? \"node\";\n this.capabilityDescriptors = Object.freeze([\n ...(options.capabilityDescriptors ?? [])\n ]);\n this.capabilities = Object.freeze({\n ...(options.capabilities ?? {})\n });\n this.driverDatabasePath = inferDriverDatabasePath(\n options.driver as { filename?: string; databasePath?: string }\n );\n this.devtoolsEngine = new DevtoolsEngine({\n runtimeId: this.runtimeId,\n platform: this.platform,\n ...(options.devtools ? { sink: options.devtools } : {}),\n getActiveQueryInfos: () => this.reactivityEngine.getActiveQueryInfos(),\n getSchemaTables: () => this.schemaEngine.getSchemaTablesForDevtools()\n });\n this.schemaEngine = new SchemaEngine({\n schema: options.schema,\n driver: options.driver,\n runtimeId: this.runtimeId,\n devtools: this.devtoolsEngine\n });\n this.storageEngine = new StorageEngine({\n driver: options.driver,\n storage: options.storage,\n runtimeId: this.runtimeId,\n devtools: this.devtoolsEngine\n });\n this.transactionCoordinator = new TransactionCoordinator(options.driver);\n this.runtimeStatus = new RuntimeStatusController({\n kind: \"starting\",\n reason: \"booting\"\n });\n this.schedulerEngine = new SchedulerEngine({\n driver: options.driver,\n runtimeId: this.runtimeId,\n devtools: this.devtoolsEngine,\n recurringJobs: options.scheduler?.recurringJobs ?? [],\n pollIntervalMs: options.scheduler?.pollIntervalMs ?? 1000,\n runMutation: (reference, args, meta) =>\n this.executionEngine.runMutation(reference, args, meta),\n runAction: (reference, args, meta) =>\n this.executionEngine.runAction(reference, args, meta)\n });\n this.reactivityEngine = new ReactivityEngine({\n runtimeId: this.runtimeId,\n externalChangeSourceId: this.externalChangeSourceId,\n ...(options.externalChangeSignal\n ? { externalChangeSignal: options.externalChangeSignal }\n : {}),\n ...(options.externalChangeApplier\n ? { externalChangeApplier: options.externalChangeApplier }\n : {}),\n devtools: this.devtoolsEngine,\n runQuery: (reference, args, meta) =>\n this.executionEngine.runQuery(reference, args, meta),\n collectQueryDependencies: (functionName, args) =>\n this.executionEngine.collectQueryDependencies(functionName, args)\n });\n this.executionEngine = new ExecutionEngine({\n runtimeId: this.runtimeId,\n functions: options.functions,\n driver: options.driver,\n capabilities: this.capabilities,\n capabilityDescriptors: this.capabilityDescriptors,\n schema: this.schemaEngine,\n storage: this.storageEngine,\n scheduler: this.schedulerEngine,\n reactivity: this.reactivityEngine,\n devtools: this.devtoolsEngine,\n transactionCoordinator: this.transactionCoordinator,\n runtimeStatus: this.runtimeStatus\n });\n this.admin = {\n prepareForDirectAccess: () => this.prepareForDirectAccess(),\n createClient: () => this.createClient(),\n runQuery: (reference, args, meta) =>\n this.executionEngine.runQuery(reference, args, meta),\n runMutation: (reference, args, meta) =>\n this.executionEngine.runMutation(reference, args, meta),\n runAction: (reference, args, meta) =>\n this.executionEngine.runAction(reference, args, meta),\n runDevtoolsMutation: async (callback, meta) => {\n await this.prepareForDirectAccess();\n return this.executionEngine.runDevtoolsMutation(callback, meta);\n },\n getRuntimeSummary: () => this.devtoolsEngine.getRuntimeSummary(),\n getActiveQueryInfos: () => this.reactivityEngine.getActiveQueryInfos(),\n getRuntimeId: () => this.runtimeId,\n getDriverDatabasePath: () => this.driverDatabasePath,\n subscribeToDevtoolsEvents: (listener) =>\n this.devtoolsEngine.subscribeEvents(listener),\n subscribeToDevtoolsInvalidations: (listener) =>\n this.devtoolsEngine.subscribeInvalidations(listener),\n notifyDevtoolsScopes: (scopes) => this.devtoolsEngine.notifyScopes(scopes),\n forceRefreshDevtools: async (reason, scopes, meta) => {\n const resolvedScopes = new Set(scopes ?? []);\n if (resolvedScopes.size > 0) {\n await this.reactivityEngine.refreshQueriesForScopes(\n resolvedScopes,\n reason\n );\n }\n await this.devtoolsEngine.forceRefresh(\n reason,\n {\n refreshQueriesForScopes: (requestedScopes, refreshReason) =>\n this.reactivityEngine.refreshQueriesForScopes(\n requestedScopes,\n refreshReason\n )\n },\n meta,\n resolvedScopes\n );\n },\n cancelScheduledJob: async (id) => {\n await this.prepareForDirectAccess();\n return this.schedulerEngine.cancelScheduledJob(id);\n },\n updateScheduledJob: async (update: UpdateScheduledJobOptions) => {\n await this.prepareForDirectAccess();\n return this.schedulerEngine.updateScheduledJob(update);\n }\n };\n options.devtools?.attachRuntime?.(runtime);\n }\n\n async start(): Promise<void> {\n if (this.started) {\n return;\n }\n this.runtimeStatus.setStatus({\n kind: \"starting\",\n reason: \"booting\"\n });\n await this.prepareForDirectAccess();\n try {\n await this.runComponentHooks(\"onStart\");\n this.reactivityEngine.start();\n this.schedulerEngine.startPolling();\n this.started = true;\n this.runtimeStatus.setStatus({\n kind: \"ready\"\n });\n this.devtoolsEngine.emit({\n type: \"runtime.connected\",\n runtimeId: this.runtimeId,\n platform: this.platform,\n timestamp: Date.now()\n });\n } catch (error) {\n this.schedulerEngine.stopPolling();\n this.reactivityEngine.stop();\n await this.options.driver.close?.().catch(() => undefined);\n this.started = false;\n this.runtimeStatus.setStatus({\n kind: \"error\",\n reason: \"runtime-unavailable\",\n ...(error instanceof Error ? { error } : {})\n });\n throw error;\n }\n }\n\n async prepareForDirectAccess(): Promise<void> {\n if (this.prepared) {\n return;\n }\n await ensureSupportedSystemFormats(this.options.driver);\n await this.schemaEngine.prepare();\n await this.storageEngine.prepare();\n await this.schedulerEngine.prepare();\n await this.storageEngine.reconcile();\n await this.schemaEngine.applySchema();\n await this.schedulerEngine.syncRecurringJobs();\n this.prepared = true;\n }\n\n async stop(): Promise<void> {\n this.schedulerEngine.stopPolling();\n let stopError: unknown;\n if (this.started) {\n try {\n await this.runComponentHooks(\"onStop\");\n } catch (error) {\n stopError = error;\n }\n }\n this.reactivityEngine.stop();\n await this.options.driver.close?.();\n if (this.started) {\n this.devtoolsEngine.emit({\n type: \"runtime.disconnected\",\n runtimeId: this.runtimeId,\n timestamp: Date.now()\n });\n }\n this.started = false;\n this.runtimeStatus.setStatus({\n kind: \"unavailable\",\n reason: \"disposed\"\n });\n if (stopError) {\n throw stopError;\n }\n }\n\n createClient(): SyncoreClient {\n return this.executionEngine.createClient();\n }\n\n watchQuery<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n args: Record<string, unknown> = {}\n ): SyncoreWatch<TResult> {\n return this.executionEngine.watchQuery(reference, args);\n }\n\n private async runComponentHooks(\n hook: \"onStart\" | \"onStop\"\n ): Promise<void> {\n for (const component of this.options.components ?? []) {\n await this.runComponentHookTree(component, hook);\n }\n }\n\n private async runComponentHookTree(\n component: SyncoreResolvedComponents[number],\n hook: \"onStart\" | \"onStop\"\n ): Promise<void> {\n const handler = component[hook];\n if (handler) {\n await handler({\n runtimeId: this.runtimeId,\n platform: this.platform,\n componentPath: component.path,\n componentName: component.name,\n version: component.version,\n config: component.config,\n capabilities: component.grantedCapabilities,\n emitDevtools: (event: SyncoreDevtoolsEvent) => {\n this.devtoolsEngine.emit(event);\n }\n });\n }\n for (const child of component.children) {\n await this.runComponentHookTree(child, hook);\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeStatus.mjs","names":[],"sources":["../../../src/runtime/internal/runtimeStatus.ts"],"sourcesContent":["import type {\n SyncoreRuntimeStatus,\n SyncoreWatch\n} from \"../runtime.js\";\n\nexport class RuntimeStatusController {\n private status: SyncoreRuntimeStatus;\n private readonly listeners = new Set<() => void>();\n\n constructor(initialStatus: SyncoreRuntimeStatus) {\n this.status = initialStatus;\n }\n\n getStatus(): SyncoreRuntimeStatus {\n return this.status;\n }\n\n setStatus(nextStatus: SyncoreRuntimeStatus): void {\n this.status = nextStatus;\n for (const listener of this.listeners) {\n listener();\n }\n }\n\n watch(): SyncoreWatch<SyncoreRuntimeStatus> {\n return {\n onUpdate: (callback) => {\n this.listeners.add(callback);\n queueMicrotask(callback);\n return () => {\n this.listeners.delete(callback);\n };\n },\n localQueryResult: () => this.status,\n localQueryError: () => undefined\n };\n }\n}\n"],"mappings":";AAKA,IAAa,0BAAb,MAAqC;CACnC;CACA,4BAA6B,IAAI,KAAiB;CAElD,YAAY,eAAqC;AAC/C,OAAK,SAAS;;CAGhB,YAAkC;AAChC,SAAO,KAAK;;CAGd,UAAU,YAAwC;AAChD,OAAK,SAAS;AACd,OAAK,MAAM,YAAY,KAAK,UAC1B,WAAU;;CAId,QAA4C;AAC1C,SAAO;GACL,WAAW,aAAa;AACtB,SAAK,UAAU,IAAI,SAAS;AAC5B,mBAAe,SAAS;AACxB,iBAAa;AACX,UAAK,UAAU,OAAO,SAAS;;;GAGnC,wBAAwB,KAAK;GAC7B,uBAAuB,KAAA;GACxB"}
1
+ {"version":3,"file":"runtimeStatus.mjs","names":[],"sources":["../../../src/runtime/internal/runtimeStatus.ts"],"sourcesContent":["import type {\n SyncoreRuntimeStatus,\n SyncoreWatch\n} from \"../runtime.js\";\n\nexport class RuntimeStatusController {\n private status: SyncoreRuntimeStatus;\n private readonly listeners = new Set<() => void>();\n\n constructor(initialStatus: SyncoreRuntimeStatus) {\n this.status = initialStatus;\n }\n\n getStatus(): SyncoreRuntimeStatus {\n return this.status;\n }\n\n setStatus(nextStatus: SyncoreRuntimeStatus): void {\n this.status = nextStatus;\n for (const listener of this.listeners) {\n listener();\n }\n }\n\n watch(): SyncoreWatch<SyncoreRuntimeStatus> {\n return {\n onUpdate: (callback) => {\n this.listeners.add(callback);\n queueMicrotask(callback);\n return () => {\n this.listeners.delete(callback);\n };\n },\n localQueryResult: () => this.status,\n localQueryError: () => undefined\n };\n }\n}\n"],"mappings":";AAKA,IAAa,0BAAb,MAAqC;CACnC;CACA,4BAA6B,IAAI,IAAgB;CAEjD,YAAY,eAAqC;EAC/C,KAAK,SAAS;CAChB;CAEA,YAAkC;EAChC,OAAO,KAAK;CACd;CAEA,UAAU,YAAwC;EAChD,KAAK,SAAS;EACd,KAAK,MAAM,YAAY,KAAK,WAC1B,SAAS;CAEb;CAEA,QAA4C;EAC1C,OAAO;GACL,WAAW,aAAa;IACtB,KAAK,UAAU,IAAI,QAAQ;IAC3B,eAAe,QAAQ;IACvB,aAAa;KACX,KAAK,UAAU,OAAO,QAAQ;IAChC;GACF;GACA,wBAAwB,KAAK;GAC7B,uBAAuB,KAAA;EACzB;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"systemMeta.mjs","names":[],"sources":["../../../src/runtime/internal/systemMeta.ts"],"sourcesContent":["import type { SyncoreSqlDriver } from \"../runtime.js\";\n\nexport interface SystemFormatRegistry {\n schema_state_format_version: number;\n storage_format_version: number;\n scheduler_format_version: number;\n runtime_meta_version: number;\n}\n\nexport const CURRENT_SYSTEM_FORMATS: SystemFormatRegistry = {\n schema_state_format_version: 1,\n storage_format_version: 1,\n scheduler_format_version: 1,\n runtime_meta_version: 1\n};\n\nconst META_TABLE_NAME = \"_syncore_system_meta\";\n\nexport async function ensureSystemMetaTable(\n driver: SyncoreSqlDriver\n): Promise<void> {\n await driver.exec(`\n CREATE TABLE IF NOT EXISTS \"${META_TABLE_NAME}\" (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n `);\n}\n\nexport async function loadSystemFormats(\n driver: SyncoreSqlDriver\n): Promise<SystemFormatRegistry> {\n await ensureSystemMetaTable(driver);\n const rows = await driver.all<{ key: string; value: string }>(\n `SELECT key, value FROM \"${META_TABLE_NAME}\"`\n );\n const loaded = { ...CURRENT_SYSTEM_FORMATS };\n\n for (const row of rows) {\n if (!isSystemFormatKey(row.key)) {\n continue;\n }\n const parsed = Number.parseInt(row.value, 10);\n if (Number.isNaN(parsed)) {\n throw new Error(`Invalid Syncore system format value for \"${row.key}\".`);\n }\n loaded[row.key] = parsed;\n }\n\n return loaded;\n}\n\nexport async function ensureSupportedSystemFormats(\n driver: SyncoreSqlDriver\n): Promise<SystemFormatRegistry> {\n const loaded = await loadSystemFormats(driver);\n\n for (const key of systemFormatKeys()) {\n if (loaded[key] > CURRENT_SYSTEM_FORMATS[key]) {\n throw new Error(\n `Syncore system format \"${key}\" version ${loaded[key]} is newer than this runtime supports (${CURRENT_SYSTEM_FORMATS[key]}).`\n );\n }\n }\n\n const now = Date.now();\n for (const key of systemFormatKeys()) {\n if (loaded[key] === CURRENT_SYSTEM_FORMATS[key]) {\n await driver.run(\n `INSERT OR REPLACE INTO \"${META_TABLE_NAME}\" (key, value, updated_at) VALUES (?, ?, ?)`,\n [key, String(loaded[key]), now]\n );\n continue;\n }\n await driver.run(\n `INSERT OR REPLACE INTO \"${META_TABLE_NAME}\" (key, value, updated_at) VALUES (?, ?, ?)`,\n [key, String(CURRENT_SYSTEM_FORMATS[key]), now]\n );\n loaded[key] = CURRENT_SYSTEM_FORMATS[key];\n }\n\n return loaded;\n}\n\nfunction systemFormatKeys(): Array<keyof SystemFormatRegistry> {\n return Object.keys(CURRENT_SYSTEM_FORMATS) as Array<keyof SystemFormatRegistry>;\n}\n\nfunction isSystemFormatKey(value: string): value is keyof SystemFormatRegistry {\n return systemFormatKeys().includes(value as keyof SystemFormatRegistry);\n}\n"],"mappings":";AASA,MAAa,yBAA+C;CAC1D,6BAA6B;CAC7B,wBAAwB;CACxB,0BAA0B;CAC1B,sBAAsB;CACvB;AAED,MAAM,kBAAkB;AAExB,eAAsB,sBACpB,QACe;AACf,OAAM,OAAO,KAAK;kCACc,gBAAgB;;;;;IAK9C;;AAGJ,eAAsB,kBACpB,QAC+B;AAC/B,OAAM,sBAAsB,OAAO;CACnC,MAAM,OAAO,MAAM,OAAO,IACxB,2BAA2B,gBAAgB,GAC5C;CACD,MAAM,SAAS,EAAE,GAAG,wBAAwB;AAE5C,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,CAAC,kBAAkB,IAAI,IAAI,CAC7B;EAEF,MAAM,SAAS,OAAO,SAAS,IAAI,OAAO,GAAG;AAC7C,MAAI,OAAO,MAAM,OAAO,CACtB,OAAM,IAAI,MAAM,4CAA4C,IAAI,IAAI,IAAI;AAE1E,SAAO,IAAI,OAAO;;AAGpB,QAAO;;AAGT,eAAsB,6BACpB,QAC+B;CAC/B,MAAM,SAAS,MAAM,kBAAkB,OAAO;AAE9C,MAAK,MAAM,OAAO,kBAAkB,CAClC,KAAI,OAAO,OAAO,uBAAuB,KACvC,OAAM,IAAI,MACR,0BAA0B,IAAI,YAAY,OAAO,KAAK,wCAAwC,uBAAuB,KAAK,IAC3H;CAIL,MAAM,MAAM,KAAK,KAAK;AACtB,MAAK,MAAM,OAAO,kBAAkB,EAAE;AACpC,MAAI,OAAO,SAAS,uBAAuB,MAAM;AAC/C,SAAM,OAAO,IACX,2BAA2B,gBAAgB,8CAC3C;IAAC;IAAK,OAAO,OAAO,KAAK;IAAE;IAAI,CAChC;AACD;;AAEF,QAAM,OAAO,IACX,2BAA2B,gBAAgB,8CAC3C;GAAC;GAAK,OAAO,uBAAuB,KAAK;GAAE;GAAI,CAChD;AACD,SAAO,OAAO,uBAAuB;;AAGvC,QAAO;;AAGT,SAAS,mBAAsD;AAC7D,QAAO,OAAO,KAAK,uBAAuB;;AAG5C,SAAS,kBAAkB,OAAoD;AAC7E,QAAO,kBAAkB,CAAC,SAAS,MAAoC"}
1
+ {"version":3,"file":"systemMeta.mjs","names":[],"sources":["../../../src/runtime/internal/systemMeta.ts"],"sourcesContent":["import type { SyncoreSqlDriver } from \"../runtime.js\";\n\nexport interface SystemFormatRegistry {\n schema_state_format_version: number;\n storage_format_version: number;\n scheduler_format_version: number;\n runtime_meta_version: number;\n}\n\nexport const CURRENT_SYSTEM_FORMATS: SystemFormatRegistry = {\n schema_state_format_version: 1,\n storage_format_version: 1,\n scheduler_format_version: 1,\n runtime_meta_version: 1\n};\n\nconst META_TABLE_NAME = \"_syncore_system_meta\";\n\nexport async function ensureSystemMetaTable(\n driver: SyncoreSqlDriver\n): Promise<void> {\n await driver.exec(`\n CREATE TABLE IF NOT EXISTS \"${META_TABLE_NAME}\" (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n `);\n}\n\nexport async function loadSystemFormats(\n driver: SyncoreSqlDriver\n): Promise<SystemFormatRegistry> {\n await ensureSystemMetaTable(driver);\n const rows = await driver.all<{ key: string; value: string }>(\n `SELECT key, value FROM \"${META_TABLE_NAME}\"`\n );\n const loaded = { ...CURRENT_SYSTEM_FORMATS };\n\n for (const row of rows) {\n if (!isSystemFormatKey(row.key)) {\n continue;\n }\n const parsed = Number.parseInt(row.value, 10);\n if (Number.isNaN(parsed)) {\n throw new Error(`Invalid Syncore system format value for \"${row.key}\".`);\n }\n loaded[row.key] = parsed;\n }\n\n return loaded;\n}\n\nexport async function ensureSupportedSystemFormats(\n driver: SyncoreSqlDriver\n): Promise<SystemFormatRegistry> {\n const loaded = await loadSystemFormats(driver);\n\n for (const key of systemFormatKeys()) {\n if (loaded[key] > CURRENT_SYSTEM_FORMATS[key]) {\n throw new Error(\n `Syncore system format \"${key}\" version ${loaded[key]} is newer than this runtime supports (${CURRENT_SYSTEM_FORMATS[key]}).`\n );\n }\n }\n\n const now = Date.now();\n for (const key of systemFormatKeys()) {\n if (loaded[key] === CURRENT_SYSTEM_FORMATS[key]) {\n await driver.run(\n `INSERT OR REPLACE INTO \"${META_TABLE_NAME}\" (key, value, updated_at) VALUES (?, ?, ?)`,\n [key, String(loaded[key]), now]\n );\n continue;\n }\n await driver.run(\n `INSERT OR REPLACE INTO \"${META_TABLE_NAME}\" (key, value, updated_at) VALUES (?, ?, ?)`,\n [key, String(CURRENT_SYSTEM_FORMATS[key]), now]\n );\n loaded[key] = CURRENT_SYSTEM_FORMATS[key];\n }\n\n return loaded;\n}\n\nfunction systemFormatKeys(): Array<keyof SystemFormatRegistry> {\n return Object.keys(CURRENT_SYSTEM_FORMATS) as Array<keyof SystemFormatRegistry>;\n}\n\nfunction isSystemFormatKey(value: string): value is keyof SystemFormatRegistry {\n return systemFormatKeys().includes(value as keyof SystemFormatRegistry);\n}\n"],"mappings":";AASA,MAAa,yBAA+C;CAC1D,6BAA6B;CAC7B,wBAAwB;CACxB,0BAA0B;CAC1B,sBAAsB;AACxB;AAEA,MAAM,kBAAkB;AAExB,eAAsB,sBACpB,QACe;CACf,MAAM,OAAO,KAAK;kCACc,gBAAgB;;;;;GAK/C;AACH;AAEA,eAAsB,kBACpB,QAC+B;CAC/B,MAAM,sBAAsB,MAAM;CAClC,MAAM,OAAO,MAAM,OAAO,IACxB,2BAA2B,gBAAgB,EAC7C;CACA,MAAM,SAAS,EAAE,GAAG,uBAAuB;CAE3C,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,CAAC,kBAAkB,IAAI,GAAG,GAC5B;EAEF,MAAM,SAAS,OAAO,SAAS,IAAI,OAAO,EAAE;EAC5C,IAAI,OAAO,MAAM,MAAM,GACrB,MAAM,IAAI,MAAM,4CAA4C,IAAI,IAAI,GAAG;EAEzE,OAAO,IAAI,OAAO;CACpB;CAEA,OAAO;AACT;AAEA,eAAsB,6BACpB,QAC+B;CAC/B,MAAM,SAAS,MAAM,kBAAkB,MAAM;CAE7C,KAAK,MAAM,OAAO,iBAAiB,GACjC,IAAI,OAAO,OAAO,uBAAuB,MACvC,MAAM,IAAI,MACR,0BAA0B,IAAI,YAAY,OAAO,KAAK,wCAAwC,uBAAuB,KAAK,GAC5H;CAIJ,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,OAAO,iBAAiB,GAAG;EACpC,IAAI,OAAO,SAAS,uBAAuB,MAAM;GAC/C,MAAM,OAAO,IACX,2BAA2B,gBAAgB,8CAC3C;IAAC;IAAK,OAAO,OAAO,IAAI;IAAG;GAAG,CAChC;GACA;EACF;EACA,MAAM,OAAO,IACX,2BAA2B,gBAAgB,8CAC3C;GAAC;GAAK,OAAO,uBAAuB,IAAI;GAAG;EAAG,CAChD;EACA,OAAO,OAAO,uBAAuB;CACvC;CAEA,OAAO;AACT;AAEA,SAAS,mBAAsD;CAC7D,OAAO,OAAO,KAAK,sBAAsB;AAC3C;AAEA,SAAS,kBAAkB,OAAoD;CAC7E,OAAO,iBAAiB,EAAE,SAAS,KAAmC;AACxE"}