@lota-sdk/core 0.4.7 → 0.4.9

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 (259) hide show
  1. package/package.json +11 -12
  2. package/src/ai/embedding-cache.ts +94 -22
  3. package/src/ai-gateway/ai-gateway.ts +738 -223
  4. package/src/config/agent-defaults.ts +176 -75
  5. package/src/config/agent-types.ts +54 -4
  6. package/src/config/constants.ts +8 -2
  7. package/src/config/logger.ts +286 -19
  8. package/src/config/model-constants.ts +1 -0
  9. package/src/config/thread-defaults.ts +33 -21
  10. package/src/create-runtime.ts +725 -383
  11. package/src/db/base.service.ts +52 -28
  12. package/src/db/cursor-pagination.ts +71 -30
  13. package/src/db/memory-store.helpers.ts +4 -7
  14. package/src/db/memory-store.ts +856 -598
  15. package/src/db/memory.ts +398 -275
  16. package/src/db/record-id.ts +32 -10
  17. package/src/db/schema-fingerprint.ts +30 -12
  18. package/src/db/service-normalization.ts +255 -0
  19. package/src/db/service.ts +726 -761
  20. package/src/db/startup.ts +140 -66
  21. package/src/db/transaction-conflict.ts +15 -0
  22. package/src/effect/awaitable-effect.ts +87 -0
  23. package/src/effect/errors.ts +121 -0
  24. package/src/effect/helpers.ts +98 -0
  25. package/src/effect/index.ts +22 -0
  26. package/src/effect/layers.ts +228 -0
  27. package/src/effect/runtime-ref.ts +25 -0
  28. package/src/effect/runtime.ts +31 -0
  29. package/src/effect/services.ts +57 -0
  30. package/src/effect/zod.ts +43 -0
  31. package/src/embeddings/provider.ts +122 -71
  32. package/src/index.ts +46 -1
  33. package/src/openrouter/direct-provider.ts +29 -0
  34. package/src/queues/autonomous-job.queue.ts +130 -74
  35. package/src/queues/context-compaction.queue.ts +60 -15
  36. package/src/queues/delayed-node-promotion.queue.ts +52 -15
  37. package/src/queues/document-processor.queue.ts +52 -77
  38. package/src/queues/memory-consolidation.queue.ts +47 -32
  39. package/src/queues/organization-learning.queue.ts +13 -4
  40. package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
  41. package/src/queues/plan-scheduler.queue.ts +107 -31
  42. package/src/queues/post-chat-memory.queue.ts +66 -24
  43. package/src/queues/queue-factory.ts +142 -52
  44. package/src/queues/standalone-worker.ts +39 -0
  45. package/src/queues/title-generation.queue.ts +54 -9
  46. package/src/redis/connection.ts +84 -32
  47. package/src/redis/index.ts +6 -8
  48. package/src/redis/org-memory-lock.ts +60 -27
  49. package/src/redis/redis-lease-lock.ts +200 -121
  50. package/src/redis/runtime-connection.ts +10 -0
  51. package/src/redis/stream-context.ts +84 -46
  52. package/src/runtime/agent-identity-overrides.ts +2 -2
  53. package/src/runtime/agent-runtime-policy.ts +4 -1
  54. package/src/runtime/agent-stream-helpers.ts +20 -9
  55. package/src/runtime/chat-run-orchestration.ts +102 -19
  56. package/src/runtime/chat-run-registry.ts +36 -2
  57. package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
  58. package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
  59. package/src/runtime/execution-plan-visibility.ts +2 -2
  60. package/src/runtime/execution-plan.ts +42 -15
  61. package/src/runtime/graph-designer.ts +11 -7
  62. package/src/runtime/helper-model.ts +135 -48
  63. package/src/runtime/index.ts +7 -7
  64. package/src/runtime/indexed-repositories-policy.ts +3 -3
  65. package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
  66. package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
  67. package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
  68. package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
  69. package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
  70. package/src/runtime/plugin-resolution.ts +144 -24
  71. package/src/runtime/plugin-types.ts +9 -1
  72. package/src/runtime/post-turn-side-effects.ts +197 -130
  73. package/src/runtime/retrieval-adapters.ts +38 -4
  74. package/src/runtime/runtime-config.ts +165 -61
  75. package/src/runtime/runtime-extensions.ts +21 -34
  76. package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
  77. package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
  78. package/src/runtime/social-chat/social-chat.ts +594 -0
  79. package/src/runtime/specialist-runner.ts +36 -10
  80. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
  81. package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
  82. package/src/runtime/thread-chat-helpers.ts +2 -2
  83. package/src/runtime/thread-plan-turn.ts +2 -1
  84. package/src/runtime/thread-turn-context.ts +172 -94
  85. package/src/runtime/turn-lifecycle.ts +93 -27
  86. package/src/services/agent-activity.service.ts +287 -203
  87. package/src/services/agent-executor.service.ts +329 -217
  88. package/src/services/artifact.service.ts +225 -148
  89. package/src/services/attachment.service.ts +137 -115
  90. package/src/services/autonomous-job.service.ts +888 -491
  91. package/src/services/chat-run-registry.service.ts +11 -1
  92. package/src/services/context-compaction.service.ts +136 -86
  93. package/src/services/document-chunk.service.ts +162 -90
  94. package/src/services/execution-plan/execution-plan-approval.ts +26 -0
  95. package/src/services/execution-plan/execution-plan-context.ts +29 -0
  96. package/src/services/execution-plan/execution-plan-graph.ts +256 -0
  97. package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
  98. package/src/services/execution-plan/execution-plan-spec.ts +75 -0
  99. package/src/services/execution-plan/execution-plan.service.ts +1041 -0
  100. package/src/services/feedback-loop.service.ts +132 -76
  101. package/src/services/global-orchestrator.service.ts +80 -170
  102. package/src/services/graph-full-routing.ts +182 -0
  103. package/src/services/index.ts +18 -20
  104. package/src/services/institutional-memory.service.ts +220 -123
  105. package/src/services/learned-skill.service.ts +364 -259
  106. package/src/services/memory/memory-conversation.ts +95 -0
  107. package/src/services/memory/memory-org-memory.ts +39 -0
  108. package/src/services/memory/memory-preseeded.ts +80 -0
  109. package/src/services/memory/memory-rerank.ts +297 -0
  110. package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
  111. package/src/services/memory/memory.service.ts +692 -0
  112. package/src/services/memory/rerank.service.ts +209 -0
  113. package/src/services/monitoring-window.service.ts +92 -70
  114. package/src/services/mutating-approval.service.ts +62 -53
  115. package/src/services/node-workspace.service.ts +141 -98
  116. package/src/services/notification.service.ts +17 -16
  117. package/src/services/organization-member.service.ts +120 -66
  118. package/src/services/organization.service.ts +144 -51
  119. package/src/services/ownership-dispatcher.service.ts +415 -264
  120. package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
  121. package/src/services/plan/plan-agent-query.service.ts +322 -0
  122. package/src/services/plan/plan-approval.service.ts +102 -0
  123. package/src/services/plan/plan-artifact.service.ts +60 -0
  124. package/src/services/plan/plan-builder.service.ts +76 -0
  125. package/src/services/plan/plan-checkpoint.service.ts +103 -0
  126. package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
  127. package/src/services/plan/plan-completion-side-effects.ts +175 -0
  128. package/src/services/plan/plan-coordination.service.ts +181 -0
  129. package/src/services/plan/plan-cycle.service.ts +398 -0
  130. package/src/services/plan/plan-deadline.service.ts +547 -0
  131. package/src/services/plan/plan-event-delivery.service.ts +261 -0
  132. package/src/services/plan/plan-executor-context.ts +35 -0
  133. package/src/services/plan/plan-executor-graph.ts +475 -0
  134. package/src/services/plan/plan-executor-helpers.ts +322 -0
  135. package/src/services/plan/plan-executor-persistence.ts +209 -0
  136. package/src/services/plan/plan-executor.service.ts +1654 -0
  137. package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
  138. package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
  139. package/src/services/plan/plan-run-serialization.ts +15 -0
  140. package/src/services/plan/plan-run.service.ts +644 -0
  141. package/src/services/plan/plan-scheduler.service.ts +385 -0
  142. package/src/services/plan/plan-template.service.ts +224 -0
  143. package/src/services/plan/plan-transaction-events.ts +33 -0
  144. package/src/services/plan/plan-validator.service.ts +907 -0
  145. package/src/services/plan/plan-workspace.service.ts +125 -0
  146. package/src/services/plugin-executor.service.ts +97 -68
  147. package/src/services/quality-metrics.service.ts +112 -94
  148. package/src/services/queue-job.service.ts +296 -230
  149. package/src/services/recent-activity-title.service.ts +65 -36
  150. package/src/services/recent-activity.service.ts +274 -259
  151. package/src/services/skill-resolver.service.ts +38 -12
  152. package/src/services/social-chat-history.service.ts +176 -125
  153. package/src/services/system-executor.service.ts +91 -61
  154. package/src/services/thread/thread-active-run.ts +203 -0
  155. package/src/services/thread/thread-bootstrap.ts +369 -0
  156. package/src/services/thread/thread-listing.ts +198 -0
  157. package/src/services/thread/thread-memory-block.ts +117 -0
  158. package/src/services/thread/thread-message.service.ts +363 -0
  159. package/src/services/thread/thread-record-store.ts +155 -0
  160. package/src/services/thread/thread-title.service.ts +74 -0
  161. package/src/services/thread/thread-turn-execution.ts +280 -0
  162. package/src/services/thread/thread-turn-message-context.ts +73 -0
  163. package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
  164. package/src/services/thread/thread-turn-streaming.ts +402 -0
  165. package/src/services/thread/thread-turn-tracing.ts +35 -0
  166. package/src/services/thread/thread-turn.ts +343 -0
  167. package/src/services/thread/thread.service.ts +335 -0
  168. package/src/services/user.service.ts +82 -32
  169. package/src/services/write-intent-validator.service.ts +63 -51
  170. package/src/storage/attachment-parser.ts +69 -27
  171. package/src/storage/attachment-storage.service.ts +331 -275
  172. package/src/storage/generated-document-storage.service.ts +66 -34
  173. package/src/system-agents/agent-result.ts +3 -1
  174. package/src/system-agents/context-compaction.agent.ts +2 -2
  175. package/src/system-agents/delegated-agent-factory.ts +159 -90
  176. package/src/system-agents/memory-reranker.agent.ts +2 -2
  177. package/src/system-agents/memory.agent.ts +2 -2
  178. package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
  179. package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
  180. package/src/system-agents/skill-extractor.agent.ts +2 -2
  181. package/src/system-agents/skill-manager.agent.ts +2 -2
  182. package/src/system-agents/thread-router.agent.ts +157 -113
  183. package/src/system-agents/title-generator.agent.ts +2 -2
  184. package/src/tools/execution-plan.tool.ts +220 -161
  185. package/src/tools/fetch-webpage.tool.ts +21 -17
  186. package/src/tools/firecrawl-client.ts +16 -6
  187. package/src/tools/index.ts +1 -0
  188. package/src/tools/memory-block.tool.ts +14 -6
  189. package/src/tools/plan-approval.tool.ts +49 -47
  190. package/src/tools/read-file-parts.tool.ts +44 -33
  191. package/src/tools/remember-memory.tool.ts +65 -45
  192. package/src/tools/search-web.tool.ts +26 -22
  193. package/src/tools/search.tool.ts +41 -29
  194. package/src/tools/team-think.tool.ts +124 -83
  195. package/src/tools/user-questions.tool.ts +4 -3
  196. package/src/tools/web-tool-shared.ts +6 -0
  197. package/src/utils/async.ts +17 -23
  198. package/src/utils/crypto.ts +21 -0
  199. package/src/utils/date-time.ts +40 -1
  200. package/src/utils/errors.ts +95 -16
  201. package/src/utils/hono-error-handler.ts +24 -39
  202. package/src/utils/index.ts +2 -1
  203. package/src/utils/null-proto-record.ts +41 -0
  204. package/src/utils/sse-keepalive.ts +124 -21
  205. package/src/workers/bootstrap.ts +186 -51
  206. package/src/workers/memory-consolidation.worker.ts +325 -237
  207. package/src/workers/organization-learning.worker.ts +50 -16
  208. package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
  209. package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
  210. package/src/workers/skill-extraction.runner.ts +176 -93
  211. package/src/workers/utils/file-section-chunker.ts +8 -10
  212. package/src/workers/utils/repo-structure-extractor.ts +349 -260
  213. package/src/workers/utils/repomix-file-sections.ts +2 -2
  214. package/src/workers/utils/thread-message-query.ts +97 -38
  215. package/src/workers/worker-utils.ts +56 -31
  216. package/src/config/debug-logger.ts +0 -47
  217. package/src/redis/connection-accessor.ts +0 -26
  218. package/src/runtime/context-compaction-runtime.ts +0 -87
  219. package/src/runtime/social-chat-agent-runner.ts +0 -118
  220. package/src/runtime/social-chat.ts +0 -516
  221. package/src/runtime/team-consultation-orchestrator.ts +0 -272
  222. package/src/services/adaptive-playbook.service.ts +0 -152
  223. package/src/services/artifact-provenance.service.ts +0 -172
  224. package/src/services/chat-attachments.service.ts +0 -17
  225. package/src/services/context-compaction-runtime.singleton.ts +0 -13
  226. package/src/services/execution-plan.service.ts +0 -1118
  227. package/src/services/memory.service.ts +0 -844
  228. package/src/services/plan-agent-heartbeat.service.ts +0 -136
  229. package/src/services/plan-agent-query.service.ts +0 -267
  230. package/src/services/plan-approval.service.ts +0 -83
  231. package/src/services/plan-artifact.service.ts +0 -50
  232. package/src/services/plan-builder.service.ts +0 -67
  233. package/src/services/plan-checkpoint.service.ts +0 -81
  234. package/src/services/plan-completion-side-effects.ts +0 -80
  235. package/src/services/plan-coordination.service.ts +0 -157
  236. package/src/services/plan-cycle.service.ts +0 -284
  237. package/src/services/plan-deadline.service.ts +0 -430
  238. package/src/services/plan-event-delivery.service.ts +0 -166
  239. package/src/services/plan-executor.service.ts +0 -1950
  240. package/src/services/plan-run.service.ts +0 -515
  241. package/src/services/plan-scheduler.service.ts +0 -240
  242. package/src/services/plan-template.service.ts +0 -177
  243. package/src/services/plan-validator.service.ts +0 -818
  244. package/src/services/plan-workspace.service.ts +0 -83
  245. package/src/services/thread-message.service.ts +0 -275
  246. package/src/services/thread-plan-registry.service.ts +0 -22
  247. package/src/services/thread-title.service.ts +0 -39
  248. package/src/services/thread-turn-preparation.service.ts +0 -1147
  249. package/src/services/thread-turn.ts +0 -172
  250. package/src/services/thread.service.ts +0 -869
  251. package/src/utils/env.ts +0 -8
  252. /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
  253. /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
  254. /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
  255. /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
  256. /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
  257. /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
  258. /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
  259. /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
@@ -1,7 +1,8 @@
1
+ import { Effect } from 'effect'
1
2
  import type { RecordIdValue } from 'surrealdb'
2
3
  import { RecordId, StringRecordId } from 'surrealdb'
3
4
 
4
- import { BadRequestError } from '../utils/errors'
5
+ import { BadRequestError } from '../effect/errors'
5
6
 
6
7
  export interface RecordIdShape {
7
8
  tb: string
@@ -21,13 +22,6 @@ interface NamedConstructor {
21
22
  name?: unknown
22
23
  }
23
24
 
24
- class InvalidRecordIdError extends BadRequestError {
25
- constructor(message: string) {
26
- super(message)
27
- this.name = 'InvalidRecordIdError'
28
- }
29
- }
30
-
31
25
  export function isSurrealRecordIdValue(value: unknown): boolean {
32
26
  if (!value || typeof value !== 'object') {
33
27
  return false
@@ -42,6 +36,23 @@ export function isSurrealRecordIdValue(value: unknown): boolean {
42
36
  return typeof constructorName === 'string' && SURREAL_RECORD_ID_CLASS_NAMES.has(constructorName)
43
37
  }
44
38
 
39
+ export function isRecordIdInput(value: unknown): value is RecordIdInput {
40
+ if (typeof value === 'string' || value instanceof RecordId || value instanceof StringRecordId) {
41
+ return true
42
+ }
43
+
44
+ if (isSurrealRecordIdValue(value)) {
45
+ return true
46
+ }
47
+
48
+ if (!value || typeof value !== 'object') {
49
+ return false
50
+ }
51
+
52
+ const record = value as { tb?: unknown; id?: unknown }
53
+ return typeof record.tb === 'string' && record.id !== undefined
54
+ }
55
+
45
56
  export function ensureRecordId(value: RecordIdInput, fallbackTable?: string): RecordId {
46
57
  if (value instanceof RecordId) {
47
58
  return value
@@ -58,7 +69,7 @@ export function ensureRecordId(value: RecordIdInput, fallbackTable?: string): Re
58
69
  return new RecordId(tableIdMatch[1], tableIdMatch[2])
59
70
  }
60
71
  if (!fallbackTable) {
61
- throw new InvalidRecordIdError('Missing table for record id')
72
+ throw new BadRequestError({ message: 'Missing table for record id' })
62
73
  }
63
74
  return new RecordId(fallbackTable, value)
64
75
  }
@@ -70,9 +81,20 @@ export function ensureRecordId(value: RecordIdInput, fallbackTable?: string): Re
70
81
  }
71
82
  }
72
83
 
73
- throw new InvalidRecordIdError('Invalid record id value')
84
+ throw new BadRequestError({ message: 'Invalid record id value' })
74
85
  }
75
86
 
76
87
  export function recordIdToString(value: RecordIdInput, fallbackTable?: string): string {
77
88
  return ensureRecordId(value, fallbackTable).toString()
78
89
  }
90
+
91
+ export function ensureRecordIdEffect(
92
+ value: RecordIdInput,
93
+ fallbackTable?: string,
94
+ ): Effect.Effect<RecordId, BadRequestError> {
95
+ return Effect.try({
96
+ try: () => ensureRecordId(value, fallbackTable),
97
+ catch: (error) =>
98
+ new BadRequestError({ message: error instanceof Error ? error.message : 'Invalid record id value' }),
99
+ })
100
+ }
@@ -1,20 +1,38 @@
1
+ import { Schema, Effect } from 'effect'
2
+
3
+ import { createSha256Hasher } from '../utils/crypto'
4
+
1
5
  function toSchemaFilePath(value: string | URL): string {
2
6
  return value instanceof URL ? value.pathname : value
3
7
  }
4
8
 
5
- export async function computeSchemaFingerprint(schemaFiles: readonly (string | URL)[]): Promise<string> {
6
- const hash = new Bun.CryptoHasher('sha256')
9
+ class SchemaFingerprintError extends Schema.TaggedErrorClass<SchemaFingerprintError>()('SchemaFingerprintError', {
10
+ message: Schema.String,
11
+ cause: Schema.Defect,
12
+ }) {}
13
+
14
+ export function computeSchemaFingerprint(schemaFiles: readonly (string | URL)[]): Promise<string> {
15
+ return Effect.runPromise(
16
+ Effect.gen(function* () {
17
+ const hash = createSha256Hasher()
18
+
19
+ for (const schemaFile of schemaFiles) {
20
+ const sortKey = toSchemaFilePath(schemaFile)
21
+ const file = schemaFile instanceof URL ? Bun.file(schemaFile.pathname) : Bun.file(schemaFile)
22
+
23
+ hash.update(sortKey)
24
+ hash.update('\0')
7
25
 
8
- // Sequential reads required: hash must be computed in deterministic file order
9
- for (const schemaFile of schemaFiles) {
10
- const sortKey = toSchemaFilePath(schemaFile)
11
- const file = schemaFile instanceof URL ? Bun.file(schemaFile.pathname) : Bun.file(schemaFile)
26
+ const contents = yield* Effect.tryPromise({
27
+ try: () => file.text(),
28
+ catch: (cause) => new SchemaFingerprintError({ message: `Failed to read schema file ${sortKey}.`, cause }),
29
+ })
12
30
 
13
- hash.update(sortKey)
14
- hash.update('\0')
15
- hash.update((await file.text()).trim())
16
- hash.update('\0')
17
- }
31
+ hash.update(contents.trim())
32
+ hash.update('\0')
33
+ }
18
34
 
19
- return hash.digest('hex')
35
+ return hash.digest('hex')
36
+ }),
37
+ )
20
38
  }
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Normalization helpers for SurrealDB service inputs.
3
+ *
4
+ * Functions in this module throw `SurrealDBError` on invalid inputs.
5
+ * Callers in `service.ts` invoke these inside `Effect.tryPromise` `try` blocks
6
+ * or `Effect.gen` generators, so thrown errors are caught by the surrounding
7
+ * `catch` handler and surfaced as typed `SurrealDBError` failures.
8
+ * Do not call these outside an Effect error boundary.
9
+ */
10
+ import { Schema } from 'effect'
11
+ import { BoundQuery, RecordId, StringRecordId, Table, and, eq } from 'surrealdb'
12
+ import type { ExprLike, Mutation } from 'surrealdb'
13
+ import type { z } from 'zod'
14
+
15
+ import { isRecord } from '../utils/string'
16
+ import type { RecordIdInput } from './record-id'
17
+ import { ensureRecordId, isRecordIdInput, isSurrealRecordIdValue } from './record-id'
18
+ import type { DatabaseTable } from './tables'
19
+
20
+ export class SurrealDBError extends Schema.TaggedErrorClass<SurrealDBError>()('SurrealDBError', {
21
+ message: Schema.String,
22
+ query: Schema.optional(Schema.String),
23
+ cause: Schema.optional(Schema.Defect),
24
+ }) {}
25
+
26
+ export type RecordMutation = Extract<Mutation, 'content' | 'replace' | 'merge'>
27
+
28
+ type TransactionQueryDescriptor = { query: string; bindings?: Record<string, unknown> }
29
+
30
+ type ParseSchema = <TSchema extends z.ZodTypeAny>(schema: TSchema, value: unknown) => z.infer<TSchema>
31
+
32
+ function isExplicitRecordIdValue(value: unknown): value is RecordIdInput {
33
+ if (value instanceof RecordId || value instanceof StringRecordId) {
34
+ return true
35
+ }
36
+
37
+ if (isSurrealRecordIdValue(value)) {
38
+ return true
39
+ }
40
+
41
+ if (!isRecord(value)) {
42
+ return false
43
+ }
44
+
45
+ return typeof value.tb === 'string' && value.id !== undefined && Object.keys(value).length === 2
46
+ }
47
+
48
+ export function configureMutation<
49
+ TBuilder extends {
50
+ content: (data: Record<string, unknown>) => TBuilder
51
+ replace: (data: Record<string, unknown>) => TBuilder
52
+ merge: (data: Record<string, unknown>) => TBuilder
53
+ },
54
+ >(builder: TBuilder, mutation: RecordMutation, data: Record<string, unknown>): TBuilder {
55
+ if (mutation === 'content') {
56
+ return builder.content(data)
57
+ }
58
+ if (mutation === 'replace') {
59
+ return builder.replace(data)
60
+ }
61
+ return builder.merge(data)
62
+ }
63
+
64
+ function isTransactionQueryDescriptor(value: unknown): value is TransactionQueryDescriptor {
65
+ return isRecord(value) && typeof value.query === 'string'
66
+ }
67
+
68
+ export function normalizeTransactionRecordId(value: unknown, context: string): RecordId {
69
+ if (!isRecordIdInput(value)) {
70
+ throw new SurrealDBError({ message: `Invalid record id for ${context}` })
71
+ }
72
+
73
+ return ensureRecordId(value)
74
+ }
75
+
76
+ export function normalizeRecordIdForTable(id: unknown, table: DatabaseTable): ReturnType<typeof ensureRecordId> {
77
+ try {
78
+ if (!isRecordIdInput(id)) {
79
+ throw new SurrealDBError({ message: `Invalid record id for table "${table}"` })
80
+ }
81
+
82
+ const recordId = ensureRecordId(id, table)
83
+ const resolvedTable = String(recordId.table)
84
+ if (resolvedTable !== table) {
85
+ throw new SurrealDBError({ message: `Record id table mismatch: expected "${table}" but got "${resolvedTable}"` })
86
+ }
87
+ return recordId
88
+ } catch (error) {
89
+ if (error instanceof SurrealDBError) {
90
+ throw error
91
+ }
92
+ if (error instanceof Error) {
93
+ throw new SurrealDBError({ message: `Invalid record id for table "${table}": ${error.message}`, cause: error })
94
+ }
95
+ throw new SurrealDBError({ message: `Invalid record id for table "${table}"` })
96
+ }
97
+ }
98
+
99
+ export function normalizeSurrealValue(value: unknown): unknown {
100
+ if (
101
+ value === null ||
102
+ value === undefined ||
103
+ value instanceof Date ||
104
+ value instanceof RecordId ||
105
+ value instanceof StringRecordId ||
106
+ value instanceof Table
107
+ ) {
108
+ return value
109
+ }
110
+
111
+ if (Array.isArray(value)) {
112
+ return value.map((entry) => normalizeSurrealValue(entry))
113
+ }
114
+
115
+ if (isExplicitRecordIdValue(value)) {
116
+ return ensureRecordId(value)
117
+ }
118
+
119
+ if (!isRecord(value)) {
120
+ return value
121
+ }
122
+
123
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, normalizeSurrealValue(entry)]))
124
+ }
125
+
126
+ export function normalizeQueryRows(
127
+ statement: unknown,
128
+ schema: z.ZodTypeAny | undefined,
129
+ parseSchema: ParseSchema,
130
+ ): unknown[] {
131
+ if (Array.isArray(statement)) {
132
+ return schema ? statement.map((row) => parseSchema(schema, row)) : statement
133
+ }
134
+ if (statement === null || statement === undefined) {
135
+ return []
136
+ }
137
+ return schema ? [parseSchema(schema, statement)] : [statement]
138
+ }
139
+
140
+ export function assertValidIdentifier(name: string, context: string): void {
141
+ if (!/^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(name)) {
142
+ throw new SurrealDBError({ message: `Invalid ${context}: "${name}"` })
143
+ }
144
+ }
145
+
146
+ export function buildFilterExpression(filter: Record<string, unknown>): ExprLike | undefined {
147
+ const entries = Object.entries(filter)
148
+ if (entries.length === 0) {
149
+ return undefined
150
+ }
151
+
152
+ const expressions = entries.map(([key, value]) => eq(key, normalizeSurrealValue(value)))
153
+ if (expressions.length === 1) {
154
+ return expressions[0]
155
+ }
156
+
157
+ return and(...expressions)
158
+ }
159
+
160
+ export function buildBoundFilterClauses(filter: Record<string, unknown>): {
161
+ clause: string
162
+ bindings: Record<string, unknown>
163
+ } {
164
+ const entries = Object.entries(filter)
165
+ if (entries.length === 0) {
166
+ throw new SurrealDBError({ message: 'Expected a non-empty filter' })
167
+ }
168
+
169
+ const bindings: Record<string, unknown> = {}
170
+ const clauses = entries.map(([field, value], index) => {
171
+ assertValidIdentifier(field, 'filter field')
172
+
173
+ const bindingKey = `filter_${index}`
174
+ bindings[bindingKey] = normalizeSurrealValue(value)
175
+ return `${field} = $${bindingKey}`
176
+ })
177
+
178
+ return { clause: clauses.join(' AND '), bindings }
179
+ }
180
+
181
+ export function normalizeBoundQuery<T extends unknown[] = unknown[]>(query: BoundQuery<T>): BoundQuery<T> {
182
+ return new BoundQuery<T>(query.query, normalizeBindings(query.bindings))
183
+ }
184
+
185
+ export function normalizeTransactionQuery(query: unknown): BoundQuery {
186
+ if (query instanceof BoundQuery) {
187
+ return new BoundQuery(query.query, normalizeBindings(query.bindings))
188
+ }
189
+
190
+ if (isTransactionQueryDescriptor(query)) {
191
+ return new BoundQuery(query.query, normalizeBindings(query.bindings))
192
+ }
193
+
194
+ throw new SurrealDBError({ message: 'Invalid transaction query' })
195
+ }
196
+
197
+ function normalizeBindings(bindings?: Record<string, unknown>): Record<string, unknown> | undefined {
198
+ if (!bindings) {
199
+ return undefined
200
+ }
201
+
202
+ const normalized = normalizeSurrealValue(bindings)
203
+ if (!isRecord(normalized)) {
204
+ throw new SurrealDBError({ message: 'Invalid bindings value' })
205
+ }
206
+
207
+ return normalized
208
+ }
209
+
210
+ export function normalizeMutationData(data: Record<string, unknown>): Record<string, unknown> {
211
+ return Object.fromEntries(
212
+ Object.entries(data)
213
+ .map(([key, value]) => [key, value === undefined ? undefined : normalizeSurrealValue(value)] as const)
214
+ .filter((entry): entry is readonly [string, unknown] => entry[1] !== undefined),
215
+ )
216
+ }
217
+
218
+ export function normalizeTableValue(value: unknown): Table<string> {
219
+ if (value instanceof Table) {
220
+ return new Table<string>(value.name as string)
221
+ }
222
+
223
+ if (typeof value === 'string' && value.length > 0) {
224
+ return new Table(value)
225
+ }
226
+
227
+ throw new SurrealDBError({ message: 'Invalid table value' })
228
+ }
229
+
230
+ export function normalizeCreateTarget(value: unknown): Table<string> | RecordId {
231
+ if (
232
+ isExplicitRecordIdValue(value) ||
233
+ (typeof value === 'string' && isRecordIdInput(value) && /^[A-Za-z_][A-Za-z0-9_]*:/.test(value))
234
+ ) {
235
+ return ensureRecordId(value)
236
+ }
237
+
238
+ return normalizeTableValue(value)
239
+ }
240
+
241
+ export function describeInvalidValue(value: unknown): string {
242
+ if (typeof value === 'string') {
243
+ return value
244
+ }
245
+
246
+ try {
247
+ const serialized = JSON.stringify(value)
248
+ if (typeof serialized === 'string') {
249
+ return serialized
250
+ }
251
+ return Object.prototype.toString.call(value)
252
+ } catch {
253
+ return Object.prototype.toString.call(value)
254
+ }
255
+ }