@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.
- package/package.json +11 -12
- package/src/ai/embedding-cache.ts +94 -22
- package/src/ai-gateway/ai-gateway.ts +738 -223
- package/src/config/agent-defaults.ts +176 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/constants.ts +8 -2
- package/src/config/logger.ts +286 -19
- package/src/config/model-constants.ts +1 -0
- package/src/config/thread-defaults.ts +33 -21
- package/src/create-runtime.ts +725 -383
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +856 -598
- package/src/db/memory.ts +398 -275
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +255 -0
- package/src/db/service.ts +726 -761
- package/src/db/startup.ts +140 -66
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +87 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +98 -0
- package/src/effect/index.ts +22 -0
- package/src/effect/layers.ts +228 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +31 -0
- package/src/effect/services.ts +57 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +122 -71
- package/src/index.ts +46 -1
- package/src/openrouter/direct-provider.ts +29 -0
- package/src/queues/autonomous-job.queue.ts +130 -74
- package/src/queues/context-compaction.queue.ts +60 -15
- package/src/queues/delayed-node-promotion.queue.ts +52 -15
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +13 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
- package/src/queues/plan-scheduler.queue.ts +107 -31
- package/src/queues/post-chat-memory.queue.ts +66 -24
- package/src/queues/queue-factory.ts +142 -52
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +54 -9
- package/src/redis/connection.ts +84 -32
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +10 -0
- package/src/redis/stream-context.ts +84 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +4 -1
- package/src/runtime/agent-stream-helpers.ts +20 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +11 -7
- package/src/runtime/helper-model.ts +135 -48
- package/src/runtime/index.ts +7 -7
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
- package/src/runtime/plugin-resolution.ts +144 -24
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +197 -130
- package/src/runtime/retrieval-adapters.ts +38 -4
- package/src/runtime/runtime-config.ts +165 -61
- package/src/runtime/runtime-extensions.ts +21 -34
- package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
- package/src/runtime/social-chat/social-chat.ts +594 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +172 -94
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +329 -217
- package/src/services/artifact.service.ts +225 -148
- package/src/services/attachment.service.ts +137 -115
- package/src/services/autonomous-job.service.ts +888 -491
- package/src/services/chat-run-registry.service.ts +11 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +162 -90
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +256 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +80 -170
- package/src/services/graph-full-routing.ts +182 -0
- package/src/services/index.ts +18 -20
- package/src/services/institutional-memory.service.ts +220 -123
- package/src/services/learned-skill.service.ts +364 -259
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-org-memory.ts +39 -0
- package/src/services/memory/memory-preseeded.ts +80 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
- package/src/services/memory/memory.service.ts +692 -0
- package/src/services/memory/rerank.service.ts +209 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +17 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +144 -51
- package/src/services/ownership-dispatcher.service.ts +415 -264
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/plan/plan-approval.service.ts +102 -0
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +175 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +398 -0
- package/src/services/plan/plan-deadline.service.ts +547 -0
- package/src/services/plan/plan-event-delivery.service.ts +261 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +475 -0
- package/src/services/plan/plan-executor-helpers.ts +322 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1654 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +644 -0
- package/src/services/plan/plan-scheduler.service.ts +385 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +33 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +125 -0
- package/src/services/plugin-executor.service.ts +97 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +296 -230
- package/src/services/recent-activity-title.service.ts +65 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +176 -125
- package/src/services/system-executor.service.ts +91 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +369 -0
- package/src/services/thread/thread-listing.ts +198 -0
- package/src/services/thread/thread-memory-block.ts +117 -0
- package/src/services/thread/thread-message.service.ts +363 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
- package/src/services/thread/thread-turn-streaming.ts +402 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +343 -0
- package/src/services/thread/thread.service.ts +335 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +331 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +2 -2
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/memory-reranker.agent.ts +2 -2
- package/src/system-agents/memory.agent.ts +2 -2
- package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
- package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
- package/src/system-agents/skill-extractor.agent.ts +2 -2
- package/src/system-agents/skill-manager.agent.ts +2 -2
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +2 -2
- package/src/tools/execution-plan.tool.ts +220 -161
- package/src/tools/fetch-webpage.tool.ts +21 -17
- package/src/tools/firecrawl-client.ts +16 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +49 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +26 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +124 -83
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +17 -23
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +95 -16
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +186 -51
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +56 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -844
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-approval.service.ts +0 -83
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
package/src/db/record-id.ts
CHANGED
|
@@ -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 '../
|
|
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
|
|
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
|
|
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
|
-
|
|
6
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
hash.update('\0')
|
|
17
|
-
}
|
|
31
|
+
hash.update(contents.trim())
|
|
32
|
+
hash.update('\0')
|
|
33
|
+
}
|
|
18
34
|
|
|
19
|
-
|
|
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
|
+
}
|