@sixb/core 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -4
- package/dist/actions/index.js +17 -17
- package/dist/actions/worker.js +7 -7
- package/dist/actions/worker.js.map +1 -1
- package/dist/agents/adapters.d.ts.map +1 -1
- package/dist/agents/builders.d.ts +8 -1
- package/dist/agents/builders.d.ts.map +1 -1
- package/dist/agents/context.js +2 -2
- package/dist/agents/errors.d.ts +15 -0
- package/dist/agents/errors.d.ts.map +1 -1
- package/dist/agents/index.d.ts +4 -4
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +30 -11
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/tool-definition.d.ts +9 -0
- package/dist/agents/tool-definition.d.ts.map +1 -0
- package/dist/agents/types.d.ts +64 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/validation.d.ts +14 -1
- package/dist/agents/validation.d.ts.map +1 -1
- package/dist/auth/index.js +4 -4
- package/dist/authorization/index.js +3 -3
- package/dist/blob-storage/browser.js +3 -2
- package/dist/blob-storage/browser.js.map +1 -1
- package/dist/blob-storage/index.js +4 -3
- package/dist/blob-storage/index.js.map +1 -1
- package/dist/blob-storage/validation.d.ts.map +1 -1
- package/dist/bootstrap/index.js +25 -25
- package/dist/broker/index.js +2 -2
- package/dist/{chunk-590dejbp.js → chunk-4hwxq5e6.js} +1 -1
- package/dist/{chunk-wj01s5hr.js → chunk-4tvj3ate.js} +1 -1
- package/dist/{chunk-tsk2bxs3.js → chunk-53s4asfm.js} +13 -13
- package/dist/{chunk-tsk2bxs3.js.map → chunk-53s4asfm.js.map} +3 -3
- package/dist/{chunk-8r8cw2xw.js → chunk-63te770v.js} +40 -5
- package/dist/{chunk-8r8cw2xw.js.map → chunk-63te770v.js.map} +3 -3
- package/dist/{chunk-vj723r3p.js → chunk-6rzdtvn5.js} +1 -1
- package/dist/{chunk-5yny9z0e.js → chunk-6zrpewy4.js} +1 -1
- package/dist/{chunk-nvamz5dv.js → chunk-86459jn0.js} +294 -22
- package/dist/chunk-86459jn0.js.map +22 -0
- package/dist/{chunk-p6r5g77m.js → chunk-8kv2sez0.js} +1 -1
- package/dist/{chunk-k41ajtz7.js → chunk-9k3hgv8h.js} +1 -1
- package/dist/{chunk-jdwx7vzs.js → chunk-avppcgt6.js} +7 -7
- package/dist/{chunk-jdwx7vzs.js.map → chunk-avppcgt6.js.map} +1 -1
- package/dist/{chunk-2gpr6jsz.js → chunk-b1bqvhpe.js} +2 -2
- package/dist/{chunk-pv1yad91.js → chunk-b5dp7gaf.js} +17 -90
- package/dist/{chunk-pv1yad91.js.map → chunk-b5dp7gaf.js.map} +5 -6
- package/dist/{chunk-1vffvydj.js → chunk-be9vm29v.js} +6 -6
- package/dist/chunk-be9vm29v.js.map +10 -0
- package/dist/{chunk-wxhdnwh4.js → chunk-bh8bwma3.js} +1 -1
- package/dist/{chunk-0psb6kdw.js → chunk-btcsywk4.js} +12 -16
- package/dist/{chunk-0psb6kdw.js.map → chunk-btcsywk4.js.map} +3 -3
- package/dist/{chunk-0fygrz37.js → chunk-exrfbt2d.js} +1 -1
- package/dist/{chunk-c3zd880g.js → chunk-f6kyyeef.js} +2 -2
- package/dist/{chunk-q4qzq0ea.js → chunk-hb9xcx9c.js} +3 -3
- package/dist/{chunk-4pycxcj3.js → chunk-hz8m927w.js} +6 -9
- package/dist/{chunk-4pycxcj3.js.map → chunk-hz8m927w.js.map} +3 -3
- package/dist/{chunk-btpe64e4.js → chunk-m9w0artv.js} +1 -1
- package/dist/{chunk-45tw90k7.js → chunk-md9jbrm9.js} +1 -1
- package/dist/{chunk-dhmj53mx.js → chunk-nbywkytr.js} +3 -3
- package/dist/{chunk-t358gywy.js → chunk-p7vj8xgb.js} +8 -8
- package/dist/{chunk-2s6sydsh.js → chunk-qzyemcj7.js} +294 -4
- package/dist/chunk-qzyemcj7.js.map +13 -0
- package/dist/{chunk-r65yscvk.js → chunk-r82k4z7z.js} +131 -13
- package/dist/chunk-r82k4z7z.js.map +13 -0
- package/dist/{chunk-aebzcsxr.js → chunk-raq0x6bd.js} +11 -9
- package/dist/{chunk-aebzcsxr.js.map → chunk-raq0x6bd.js.map} +4 -4
- package/dist/{chunk-hsv43v58.js → chunk-rgzed50y.js} +77 -22
- package/dist/chunk-rgzed50y.js.map +22 -0
- package/dist/{chunk-yvef9xwc.js → chunk-rjqm6ksg.js} +7 -7
- package/dist/{chunk-f2b5e2gf.js → chunk-sb0shdvv.js} +18 -3
- package/dist/{chunk-f2b5e2gf.js.map → chunk-sb0shdvv.js.map} +3 -3
- package/dist/{chunk-dcgrzj1t.js → chunk-xt6qx9sh.js} +1 -1
- package/dist/{chunk-mx84y05q.js → chunk-y2ygpd0m.js} +2 -2
- package/dist/{chunk-yxss87qa.js → chunk-yn947ck3.js} +1 -1
- package/dist/datasets/builders.d.ts +18 -5
- package/dist/datasets/builders.d.ts.map +1 -1
- package/dist/datasets/changes.d.ts +18 -0
- package/dist/datasets/changes.d.ts.map +1 -0
- package/dist/datasets/index.d.ts +3 -1
- package/dist/datasets/index.d.ts.map +1 -1
- package/dist/datasets/types.d.ts +2 -0
- package/dist/datasets/types.d.ts.map +1 -1
- package/dist/datasets/validation.d.ts.map +1 -1
- package/dist/events/index.js +2 -2
- package/dist/http/api-routes.d.ts.map +1 -1
- package/dist/http/index.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -58
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +8 -1
- package/dist/json.d.ts.map +1 -1
- package/dist/lake-storage/definition-updates.d.ts.map +1 -1
- package/dist/lake-storage/in-memory.d.ts +15 -1
- package/dist/lake-storage/in-memory.d.ts.map +1 -1
- package/dist/lake-storage/index.d.ts +3 -1
- package/dist/lake-storage/index.d.ts.map +1 -1
- package/dist/lake-storage/index.js +15 -7
- package/dist/lake-storage/index.js.map +1 -1
- package/dist/lake-storage/merge-validation.d.ts +10 -0
- package/dist/lake-storage/merge-validation.d.ts.map +1 -0
- package/dist/lake-storage/merge.d.ts +32 -0
- package/dist/lake-storage/merge.d.ts.map +1 -0
- package/dist/lake-storage/types.d.ts +3 -1
- package/dist/lake-storage/types.d.ts.map +1 -1
- package/dist/logging/index.js +3 -3
- package/dist/logging/types.js +2 -2
- package/dist/materialization/index.js +2 -2
- package/dist/materializer/index.js +15 -15
- package/dist/materializer/index.js.map +1 -1
- package/dist/objects/index.js +17 -17
- package/dist/objects/query/index.js +8 -8
- package/dist/ontology/index.js +5 -5
- package/dist/ontology/internal.js +7 -6
- package/dist/ontology/internal.js.map +3 -3
- package/dist/ontology/validation/normalize.d.ts.map +1 -1
- package/dist/projections/internal.js +4 -4
- package/dist/runtime/sixb.d.ts.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +16 -16
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/ontology/provider.js +4 -4
- package/dist/storage/sync-runs/index.d.ts +1 -1
- package/dist/storage/sync-runs/index.d.ts.map +1 -1
- package/dist/storage/sync-runs/types.d.ts +7 -3
- package/dist/storage/sync-runs/types.d.ts.map +1 -1
- package/dist/storage/types.d.ts +1 -1
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/workflow-runs/in-memory.d.ts.map +1 -1
- package/dist/storage/workflow-runs/types.d.ts +2 -0
- package/dist/storage/workflow-runs/types.d.ts.map +1 -1
- package/dist/syncs/builders.d.ts +11 -3
- package/dist/syncs/builders.d.ts.map +1 -1
- package/dist/syncs/index.d.ts +1 -1
- package/dist/syncs/index.d.ts.map +1 -1
- package/dist/syncs/types.d.ts +24 -19
- package/dist/syncs/types.d.ts.map +1 -1
- package/dist/syncs/validation.d.ts +14 -0
- package/dist/syncs/validation.d.ts.map +1 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +837 -583
- package/dist/testing/index.js.map +5 -4
- package/dist/testing/lake-merge-storage-contract.d.ts +7 -0
- package/dist/testing/lake-merge-storage-contract.d.ts.map +1 -0
- package/dist/testing/lake-storage-contract.d.ts.map +1 -1
- package/dist/workflows/index.js +23 -23
- package/package.json +1 -1
- package/src/agents/adapters.ts +1 -9
- package/src/agents/builders.ts +53 -3
- package/src/agents/errors.ts +22 -0
- package/src/agents/index.ts +22 -2
- package/src/agents/prompt.ts +2 -2
- package/src/agents/tool-definition.ts +93 -0
- package/src/agents/types.ts +101 -0
- package/src/agents/validation.ts +287 -3
- package/src/blob-storage/validation.ts +2 -10
- package/src/datasets/builders.ts +49 -5
- package/src/datasets/changes.ts +13 -0
- package/src/datasets/index.ts +3 -0
- package/src/datasets/types.ts +5 -0
- package/src/datasets/validation.ts +53 -11
- package/src/http/api-routes.ts +39 -4
- package/src/index.ts +18 -1
- package/src/json.ts +11 -4
- package/src/lake-storage/definition-updates.ts +21 -0
- package/src/lake-storage/in-memory.ts +284 -2
- package/src/lake-storage/index.ts +14 -0
- package/src/lake-storage/merge-validation.ts +117 -0
- package/src/lake-storage/merge.ts +35 -0
- package/src/lake-storage/types.ts +3 -1
- package/src/ontology/json-schema.ts +2 -1
- package/src/ontology/validation/normalize.ts +9 -15
- package/src/runtime/sixb.ts +16 -1
- package/src/storage/index.ts +1 -0
- package/src/storage/sync-runs/in-memory.ts +2 -2
- package/src/storage/sync-runs/index.ts +1 -0
- package/src/storage/sync-runs/types.ts +9 -4
- package/src/storage/types.ts +1 -0
- package/src/storage/workflow-runs/in-memory.ts +2 -0
- package/src/storage/workflow-runs/types.ts +2 -0
- package/src/syncs/builders.ts +31 -13
- package/src/syncs/index.ts +1 -0
- package/src/syncs/types.ts +44 -18
- package/src/syncs/validation.ts +77 -0
- package/src/testing/index.ts +4 -0
- package/src/testing/lake-merge-storage-contract.ts +302 -0
- package/src/testing/lake-storage-contract.ts +23 -0
- package/src/workflows/snapshot.ts +1 -10
- package/dist/chunk-1vffvydj.js.map +0 -10
- package/dist/chunk-2s6sydsh.js.map +0 -12
- package/dist/chunk-hsv43v58.js.map +0 -21
- package/dist/chunk-nvamz5dv.js.map +0 -21
- package/dist/chunk-r65yscvk.js.map +0 -11
- /package/dist/{chunk-590dejbp.js.map → chunk-4hwxq5e6.js.map} +0 -0
- /package/dist/{chunk-wj01s5hr.js.map → chunk-4tvj3ate.js.map} +0 -0
- /package/dist/{chunk-vj723r3p.js.map → chunk-6rzdtvn5.js.map} +0 -0
- /package/dist/{chunk-5yny9z0e.js.map → chunk-6zrpewy4.js.map} +0 -0
- /package/dist/{chunk-p6r5g77m.js.map → chunk-8kv2sez0.js.map} +0 -0
- /package/dist/{chunk-k41ajtz7.js.map → chunk-9k3hgv8h.js.map} +0 -0
- /package/dist/{chunk-2gpr6jsz.js.map → chunk-b1bqvhpe.js.map} +0 -0
- /package/dist/{chunk-wxhdnwh4.js.map → chunk-bh8bwma3.js.map} +0 -0
- /package/dist/{chunk-0fygrz37.js.map → chunk-exrfbt2d.js.map} +0 -0
- /package/dist/{chunk-c3zd880g.js.map → chunk-f6kyyeef.js.map} +0 -0
- /package/dist/{chunk-q4qzq0ea.js.map → chunk-hb9xcx9c.js.map} +0 -0
- /package/dist/{chunk-btpe64e4.js.map → chunk-m9w0artv.js.map} +0 -0
- /package/dist/{chunk-45tw90k7.js.map → chunk-md9jbrm9.js.map} +0 -0
- /package/dist/{chunk-dhmj53mx.js.map → chunk-nbywkytr.js.map} +0 -0
- /package/dist/{chunk-t358gywy.js.map → chunk-p7vj8xgb.js.map} +0 -0
- /package/dist/{chunk-yvef9xwc.js.map → chunk-rjqm6ksg.js.map} +0 -0
- /package/dist/{chunk-dcgrzj1t.js.map → chunk-xt6qx9sh.js.map} +0 -0
- /package/dist/{chunk-mx84y05q.js.map → chunk-y2ygpd0m.js.map} +0 -0
- /package/dist/{chunk-yxss87qa.js.map → chunk-yn947ck3.js.map} +0 -0
package/src/http/api-routes.ts
CHANGED
|
@@ -159,6 +159,13 @@ export const SIXB_API_ROUTES: readonly SixbApiRoute[] = [
|
|
|
159
159
|
accessToken: true,
|
|
160
160
|
agentApi: true,
|
|
161
161
|
},
|
|
162
|
+
{
|
|
163
|
+
operationId: "listObjectLinks",
|
|
164
|
+
method: "GET",
|
|
165
|
+
path: "/api/objects/:objectTypeId/:objectId/links",
|
|
166
|
+
accessToken: true,
|
|
167
|
+
agentApi: true,
|
|
168
|
+
},
|
|
162
169
|
// The four write routes. Bearer-capable because they now enforce scoped authorization
|
|
163
170
|
// (`edit:object` / `append:telemetry`), which is exactly the precondition this table's rule states.
|
|
164
171
|
// NOT agent-proxied: letting an agent turn write objects on its own is a separate decision, and
|
|
@@ -252,6 +259,20 @@ export const SIXB_API_ROUTES: readonly SixbApiRoute[] = [
|
|
|
252
259
|
accessToken: true,
|
|
253
260
|
agentApi: true,
|
|
254
261
|
},
|
|
262
|
+
{
|
|
263
|
+
operationId: "uploadFileRaw",
|
|
264
|
+
method: "POST",
|
|
265
|
+
path: "/api/files",
|
|
266
|
+
accessToken: true,
|
|
267
|
+
agentApi: true,
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
operationId: "listActionRuns",
|
|
271
|
+
method: "GET",
|
|
272
|
+
path: "/api/action-runs",
|
|
273
|
+
accessToken: true,
|
|
274
|
+
agentApi: true,
|
|
275
|
+
},
|
|
255
276
|
{
|
|
256
277
|
operationId: "getActionRun",
|
|
257
278
|
method: "GET",
|
|
@@ -278,21 +299,35 @@ export const SIXB_API_ROUTES: readonly SixbApiRoute[] = [
|
|
|
278
299
|
method: "GET",
|
|
279
300
|
path: "/api/workflows",
|
|
280
301
|
accessToken: true,
|
|
281
|
-
agentApi:
|
|
302
|
+
agentApi: true,
|
|
282
303
|
},
|
|
283
304
|
{
|
|
284
305
|
operationId: "getWorkflow",
|
|
285
306
|
method: "GET",
|
|
286
307
|
path: "/api/workflows/:workflowId",
|
|
287
308
|
accessToken: true,
|
|
288
|
-
agentApi:
|
|
309
|
+
agentApi: true,
|
|
289
310
|
},
|
|
290
311
|
{
|
|
291
312
|
operationId: "requestWorkflowRun",
|
|
292
313
|
method: "POST",
|
|
293
314
|
path: "/api/workflows/:workflowId/runs",
|
|
294
315
|
accessToken: true,
|
|
295
|
-
agentApi:
|
|
316
|
+
agentApi: true,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
operationId: "listWorkflowRuns",
|
|
320
|
+
method: "GET",
|
|
321
|
+
path: "/api/workflow-runs",
|
|
322
|
+
accessToken: true,
|
|
323
|
+
agentApi: true,
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
operationId: "getWorkflowRun",
|
|
327
|
+
method: "GET",
|
|
328
|
+
path: "/api/workflow-runs/:runId",
|
|
329
|
+
accessToken: true,
|
|
330
|
+
agentApi: true,
|
|
296
331
|
},
|
|
297
332
|
{
|
|
298
333
|
operationId: "cancelWorkflowRun",
|
|
@@ -313,7 +348,7 @@ export const SIXB_API_ROUTES: readonly SixbApiRoute[] = [
|
|
|
313
348
|
method: "GET",
|
|
314
349
|
path: "/api/workflow-runs/:runId/files/content",
|
|
315
350
|
accessToken: true,
|
|
316
|
-
agentApi:
|
|
351
|
+
agentApi: true,
|
|
317
352
|
},
|
|
318
353
|
{
|
|
319
354
|
operationId: "headWorkflowRunFileContent",
|
package/src/index.ts
CHANGED
|
@@ -140,9 +140,12 @@ export type {
|
|
|
140
140
|
DatasetColumnTypeOf,
|
|
141
141
|
DatasetColumnUnionOf,
|
|
142
142
|
DatasetDefinition,
|
|
143
|
+
DatasetPrimaryKey,
|
|
143
144
|
DatasetSchema,
|
|
145
|
+
MergeChange,
|
|
144
146
|
} from "./datasets"
|
|
145
147
|
export {
|
|
148
|
+
change,
|
|
146
149
|
col,
|
|
147
150
|
DatasetValidationError,
|
|
148
151
|
defineDataset,
|
|
@@ -154,7 +157,7 @@ export {
|
|
|
154
157
|
|
|
155
158
|
export type { Broker, BrokerCursor } from "./broker"
|
|
156
159
|
export { InMemoryBroker } from "./broker"
|
|
157
|
-
export type { JsonValue } from "./json"
|
|
160
|
+
export type { JsonValue, ReadonlyJsonValue } from "./json"
|
|
158
161
|
export {
|
|
159
162
|
assertJsonValue,
|
|
160
163
|
cloneJsonValue,
|
|
@@ -629,6 +632,7 @@ export type {
|
|
|
629
632
|
RequestSyncRunInput,
|
|
630
633
|
SyncBuilder,
|
|
631
634
|
SyncDefinition,
|
|
635
|
+
SyncMode,
|
|
632
636
|
SyncReadBuilder,
|
|
633
637
|
SyncReadContext,
|
|
634
638
|
SyncReadHandler,
|
|
@@ -867,10 +871,21 @@ export type {
|
|
|
867
871
|
AgentTextPart,
|
|
868
872
|
AgentToolCallPart,
|
|
869
873
|
AgentToolCallState,
|
|
874
|
+
AgentToolDefinition,
|
|
875
|
+
AgentToolDescriptionBuilder,
|
|
876
|
+
AgentToolHandler,
|
|
877
|
+
AgentToolHandlerResult,
|
|
878
|
+
AgentToolInputBuilder,
|
|
879
|
+
AgentToolInputSchema,
|
|
880
|
+
AgentToolRunBuilder,
|
|
881
|
+
AgentToolRunContext,
|
|
882
|
+
AgentToolRunInfo,
|
|
870
883
|
AgentUiMessage,
|
|
871
884
|
AgentUiMessagePart,
|
|
872
885
|
AgentUiToolPart,
|
|
873
886
|
DefineAgentConfig,
|
|
887
|
+
InferAgentToolInput,
|
|
888
|
+
InferAgentToolInputSchema,
|
|
874
889
|
RequestAgentRunInput,
|
|
875
890
|
RequestAgentRunResult,
|
|
876
891
|
} from "./agents"
|
|
@@ -878,9 +893,11 @@ export {
|
|
|
878
893
|
AGENT_REASONING_LEVELS,
|
|
879
894
|
AgentDefinitionError,
|
|
880
895
|
AgentRequestError,
|
|
896
|
+
AgentToolPublicError,
|
|
881
897
|
agentContext,
|
|
882
898
|
agentContextIdentity,
|
|
883
899
|
defineAgent,
|
|
900
|
+
defineAgentTool,
|
|
884
901
|
isAgentDefinition,
|
|
885
902
|
MAX_AGENT_APP_STATE_ENTRY_BYTES,
|
|
886
903
|
MAX_AGENT_APP_STATE_TOTAL_BYTES,
|
package/src/json.ts
CHANGED
|
@@ -3,6 +3,13 @@ export type JsonObject = { [key: string]: JsonValue }
|
|
|
3
3
|
export type JsonArray = JsonValue[]
|
|
4
4
|
export type JsonValue = JsonPrimitive | JsonObject | JsonArray
|
|
5
5
|
|
|
6
|
+
/** JSON-compatible input that also accepts readonly containers from typed application code. */
|
|
7
|
+
export type ReadonlyJsonObject = {
|
|
8
|
+
readonly [key: string]: ReadonlyJsonValue
|
|
9
|
+
}
|
|
10
|
+
export type ReadonlyJsonArray = readonly ReadonlyJsonValue[]
|
|
11
|
+
export type ReadonlyJsonValue = JsonPrimitive | ReadonlyJsonObject | ReadonlyJsonArray
|
|
12
|
+
|
|
6
13
|
export function isJsonValue(value: unknown): value is JsonValue {
|
|
7
14
|
return getInvalidJsonValueReason(value) === undefined
|
|
8
15
|
}
|
|
@@ -14,8 +21,8 @@ export function assertJsonValue(value: unknown, label = "value"): asserts value
|
|
|
14
21
|
}
|
|
15
22
|
}
|
|
16
23
|
|
|
17
|
-
export function cloneJsonValue(value:
|
|
18
|
-
assertJsonValue(value)
|
|
24
|
+
export function cloneJsonValue(value: ReadonlyJsonValue, label = "value"): JsonValue {
|
|
25
|
+
assertJsonValue(value, label)
|
|
19
26
|
return JSON.parse(JSON.stringify(value)) as JsonValue
|
|
20
27
|
}
|
|
21
28
|
|
|
@@ -74,7 +81,7 @@ export function getInvalidJsonValueReason(
|
|
|
74
81
|
return undefined
|
|
75
82
|
}
|
|
76
83
|
|
|
77
|
-
if (
|
|
84
|
+
if (isPlainRecord(value)) {
|
|
78
85
|
if (seen.has(value)) {
|
|
79
86
|
return `${label} contains a circular reference`
|
|
80
87
|
}
|
|
@@ -101,7 +108,7 @@ export function getInvalidJsonValueReason(
|
|
|
101
108
|
return `${label} is ${describeNonJsonValue(value)}`
|
|
102
109
|
}
|
|
103
110
|
|
|
104
|
-
function
|
|
111
|
+
export function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
105
112
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
106
113
|
return false
|
|
107
114
|
}
|
|
@@ -36,6 +36,7 @@ export function planDatasetDefinitionUpdate(
|
|
|
36
36
|
requested: DatasetDefinition
|
|
37
37
|
): DatasetDefinitionUpdatePlan {
|
|
38
38
|
assertSameDataset(existing, requested)
|
|
39
|
+
assertPrimaryKeyUnchanged(existing, requested)
|
|
39
40
|
|
|
40
41
|
const addedColumns = getAddedColumnsAfterValidatingExistingColumns(existing, requested)
|
|
41
42
|
assertAddedColumnsAreNullable(requested.id, addedColumns)
|
|
@@ -98,6 +99,24 @@ function assertSameDataset(existing: DatasetDefinition, requested: DatasetDefini
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
function assertPrimaryKeyUnchanged(
|
|
103
|
+
existing: DatasetDefinition,
|
|
104
|
+
requested: DatasetDefinition
|
|
105
|
+
): void {
|
|
106
|
+
const existingPrimaryKey = existing.primaryKey
|
|
107
|
+
const requestedPrimaryKey = requested.primaryKey
|
|
108
|
+
const unchanged =
|
|
109
|
+
existingPrimaryKey === undefined || requestedPrimaryKey === undefined
|
|
110
|
+
? existingPrimaryKey === requestedPrimaryKey
|
|
111
|
+
: areDefinitionValuesEqual(existingPrimaryKey, requestedPrimaryKey)
|
|
112
|
+
|
|
113
|
+
if (!unchanged) {
|
|
114
|
+
throw new LakeStorageError(
|
|
115
|
+
`[SixbLake] Dataset '${requested.id}' cannot be redefined with an incompatible primaryKey. Primary keys are immutable.`
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
101
120
|
function getAddedColumnsAfterValidatingExistingColumns(
|
|
102
121
|
existing: DatasetDefinition,
|
|
103
122
|
requested: DatasetDefinition
|
|
@@ -193,6 +212,7 @@ function mergeDatasetDefinition(
|
|
|
193
212
|
)
|
|
194
213
|
|
|
195
214
|
const columns = [...cloneColumns(existing.schema.columns), ...cloneColumns(addedColumns)]
|
|
215
|
+
const primaryKey = existing.primaryKey
|
|
196
216
|
const partitionBy = requested.partitionBy ?? existing.partitionBy
|
|
197
217
|
const description = requested.description ?? existing.description
|
|
198
218
|
|
|
@@ -200,6 +220,7 @@ function mergeDatasetDefinition(
|
|
|
200
220
|
kind: "dataset",
|
|
201
221
|
id: requested.id,
|
|
202
222
|
schema: { columns },
|
|
223
|
+
...(primaryKey !== undefined ? { primaryKey: structuredClone(primaryKey) } : {}),
|
|
203
224
|
...(partitionBy !== undefined ? { partitionBy: [...partitionBy] } : {}),
|
|
204
225
|
...(description !== undefined ? { description } : {}),
|
|
205
226
|
}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto"
|
|
2
|
-
import type { DatasetDefinition, DatasetSchema } from "../datasets"
|
|
2
|
+
import type { DatasetDefinition, DatasetSchema, MergeChange } from "../datasets"
|
|
3
3
|
import { getDatasetRowValidationError } from "../datasets/validation"
|
|
4
4
|
import { mergeStrictDatasetDefinition } from "./definition-updates"
|
|
5
5
|
import { LakeStorageError } from "./errors"
|
|
6
|
+
import type {
|
|
7
|
+
BeginDatasetMergeInput,
|
|
8
|
+
CommitDatasetMergeInput,
|
|
9
|
+
DatasetMergeCommitResult,
|
|
10
|
+
LakeMergeSession,
|
|
11
|
+
} from "./merge"
|
|
12
|
+
import {
|
|
13
|
+
cloneDatasetMergeChange,
|
|
14
|
+
encodeDatasetPrimaryKey,
|
|
15
|
+
getDatasetMergeChangeValidationError,
|
|
16
|
+
getDatasetPrimaryKeyColumns,
|
|
17
|
+
} from "./merge-validation"
|
|
6
18
|
import type {
|
|
7
19
|
BeginDatasetWriteInput,
|
|
8
20
|
CommitDatasetWriteInput,
|
|
@@ -74,6 +86,7 @@ function errorMessage(error: unknown): string {
|
|
|
74
86
|
|
|
75
87
|
class InMemoryLakeWriteSession implements LakeWriteSession {
|
|
76
88
|
private readonly rows: DatasetRow[] = []
|
|
89
|
+
private readonly primaryKeys = new Set<string>()
|
|
77
90
|
private closed = false
|
|
78
91
|
|
|
79
92
|
constructor(
|
|
@@ -84,13 +97,30 @@ class InMemoryLakeWriteSession implements LakeWriteSession {
|
|
|
84
97
|
async writeRows(rows: Iterable<DatasetRow> | AsyncIterable<DatasetRow>): Promise<void> {
|
|
85
98
|
this.assertOpen()
|
|
86
99
|
|
|
100
|
+
const stagedRows: DatasetRow[] = []
|
|
101
|
+
const stagedPrimaryKeys = new Set<string>()
|
|
87
102
|
for await (const row of rows) {
|
|
88
103
|
const validationError = getDatasetRowValidationError(row, this.input.dataset)
|
|
89
104
|
if (validationError) {
|
|
90
105
|
throw new LakeStorageError(`[LakeStorage] ${validationError}`)
|
|
91
106
|
}
|
|
92
107
|
|
|
93
|
-
this.
|
|
108
|
+
if (getDatasetPrimaryKeyColumns(this.input.dataset) !== null) {
|
|
109
|
+
const primaryKey = encodeDatasetPrimaryKey(this.input.dataset, row)
|
|
110
|
+
if (this.primaryKeys.has(primaryKey) || stagedPrimaryKeys.has(primaryKey)) {
|
|
111
|
+
throw new LakeStorageError(
|
|
112
|
+
`[LakeStorage] Dataset '${this.input.dataset.id}' write contains duplicate primary key ${primaryKey}.`
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
stagedPrimaryKeys.add(primaryKey)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
stagedRows.push(cloneRow(row))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.rows.push(...stagedRows)
|
|
122
|
+
for (const primaryKey of stagedPrimaryKeys) {
|
|
123
|
+
this.primaryKeys.add(primaryKey)
|
|
94
124
|
}
|
|
95
125
|
}
|
|
96
126
|
|
|
@@ -116,11 +146,63 @@ class InMemoryLakeWriteSession implements LakeWriteSession {
|
|
|
116
146
|
}
|
|
117
147
|
}
|
|
118
148
|
|
|
149
|
+
class InMemoryLakeMergeSession implements LakeMergeSession {
|
|
150
|
+
private readonly changes: MergeChange<DatasetRow, DatasetRow>[] = []
|
|
151
|
+
private closed = false
|
|
152
|
+
|
|
153
|
+
constructor(
|
|
154
|
+
private readonly storage: InMemoryLakeStorage,
|
|
155
|
+
private readonly input: BeginDatasetMergeInput,
|
|
156
|
+
private readonly baseVersionId: string | null
|
|
157
|
+
) {}
|
|
158
|
+
|
|
159
|
+
async writeChanges(
|
|
160
|
+
changes:
|
|
161
|
+
| Iterable<MergeChange<DatasetRow, DatasetRow>>
|
|
162
|
+
| AsyncIterable<MergeChange<DatasetRow, DatasetRow>>
|
|
163
|
+
): Promise<void> {
|
|
164
|
+
this.assertOpen()
|
|
165
|
+
|
|
166
|
+
const stagedChanges: MergeChange<DatasetRow, DatasetRow>[] = []
|
|
167
|
+
for await (const change of changes) {
|
|
168
|
+
const validationError = getDatasetMergeChangeValidationError(change, this.input.dataset)
|
|
169
|
+
if (validationError) {
|
|
170
|
+
throw new LakeStorageError(`[LakeStorage] ${validationError}`)
|
|
171
|
+
}
|
|
172
|
+
stagedChanges.push(cloneDatasetMergeChange(change))
|
|
173
|
+
}
|
|
174
|
+
this.changes.push(...stagedChanges)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async commit(input?: CommitDatasetMergeInput): Promise<DatasetMergeCommitResult> {
|
|
178
|
+
this.assertOpen()
|
|
179
|
+
this.closed = true
|
|
180
|
+
return this.storage.commitMerge({
|
|
181
|
+
merge: this.input,
|
|
182
|
+
baseVersionId: this.baseVersionId,
|
|
183
|
+
changes: this.changes,
|
|
184
|
+
commit: input,
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async abort(): Promise<void> {
|
|
189
|
+
this.closed = true
|
|
190
|
+
this.changes.length = 0
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private assertOpen(): void {
|
|
194
|
+
if (this.closed) {
|
|
195
|
+
throw new LakeStorageError("[LakeStorage] Merge session is already closed")
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
119
200
|
export class InMemoryLakeStorage implements LakeStorage {
|
|
120
201
|
private readonly datasets = new Map<string, DatasetDefinition>()
|
|
121
202
|
private readonly versionsByDataset = new Map<string, DatasetVersion[]>()
|
|
122
203
|
private readonly rowsByVersionId = new Map<string, readonly DatasetRow[]>()
|
|
123
204
|
private readonly latestVersionIdByDataset = new Map<string, string>()
|
|
205
|
+
private readonly commitLocks = new Map<string, Promise<void>>()
|
|
124
206
|
|
|
125
207
|
async createDataset(definition: DatasetDefinition): Promise<DatasetDefinition> {
|
|
126
208
|
assertDatasetId(definition.id)
|
|
@@ -220,6 +302,36 @@ export class InMemoryLakeStorage implements LakeStorage {
|
|
|
220
302
|
})
|
|
221
303
|
}
|
|
222
304
|
|
|
305
|
+
async beginMerge(input: BeginDatasetMergeInput): Promise<LakeMergeSession> {
|
|
306
|
+
const definition = await this.getDataset(input.dataset.id)
|
|
307
|
+
if (!definition) {
|
|
308
|
+
throw new LakeStorageError(`[LakeStorage] Unknown dataset '${input.dataset.id}'`)
|
|
309
|
+
}
|
|
310
|
+
if (getDatasetPrimaryKeyColumns(definition) === null) {
|
|
311
|
+
throw new LakeStorageError(
|
|
312
|
+
`[LakeStorage] Dataset '${definition.id}' must define a primaryKey before it can be merged.`
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const latestVersion = await this.getLatestVersion(definition.id)
|
|
317
|
+
if (
|
|
318
|
+
input.expectedLatestVersionId !== undefined &&
|
|
319
|
+
latestVersion?.versionId !== input.expectedLatestVersionId
|
|
320
|
+
) {
|
|
321
|
+
throw new LakeStorageError(
|
|
322
|
+
`[LakeStorage] Optimistic merge start failed for dataset '${definition.id}': expected latest version '${input.expectedLatestVersionId}', found '${latestVersion?.versionId ?? "none"}'`
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
return new InMemoryLakeMergeSession(
|
|
326
|
+
this,
|
|
327
|
+
{
|
|
328
|
+
...input,
|
|
329
|
+
dataset: definition,
|
|
330
|
+
},
|
|
331
|
+
latestVersion?.versionId ?? null
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
|
|
223
335
|
async getLatestVersion(datasetId: string): Promise<DatasetVersion | null> {
|
|
224
336
|
const latestVersionId = this.latestVersionIdByDataset.get(datasetId)
|
|
225
337
|
if (!latestVersionId) {
|
|
@@ -267,6 +379,90 @@ export class InMemoryLakeStorage implements LakeStorage {
|
|
|
267
379
|
write: BeginDatasetWriteInput
|
|
268
380
|
rows: readonly DatasetRow[]
|
|
269
381
|
commit?: CommitDatasetWriteInput
|
|
382
|
+
}): Promise<DatasetWriteCommitResult> {
|
|
383
|
+
return this.withDatasetCommitLock(options.write.dataset.id, () =>
|
|
384
|
+
this.commitWriteUnlocked(options)
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async commitMerge(options: {
|
|
389
|
+
merge: BeginDatasetMergeInput
|
|
390
|
+
baseVersionId: string | null
|
|
391
|
+
changes: readonly MergeChange<DatasetRow, DatasetRow>[]
|
|
392
|
+
commit?: CommitDatasetMergeInput
|
|
393
|
+
}): Promise<DatasetMergeCommitResult> {
|
|
394
|
+
return this.withDatasetCommitLock(options.merge.dataset.id, async () => {
|
|
395
|
+
const definition = this.datasets.get(options.merge.dataset.id)
|
|
396
|
+
if (!definition) {
|
|
397
|
+
throw new LakeStorageError(`[LakeStorage] Unknown dataset '${options.merge.dataset.id}'`)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const latestVersion = await this.getLatestVersion(options.merge.dataset.id)
|
|
401
|
+
const actualVersionId = latestVersion?.versionId ?? null
|
|
402
|
+
if (actualVersionId !== options.baseVersionId) {
|
|
403
|
+
throw new LakeStorageError(
|
|
404
|
+
`[LakeStorage] Optimistic merge commit failed for dataset '${options.merge.dataset.id}': expected latest version '${options.baseVersionId ?? "none"}', found '${actualVersionId ?? "none"}'`
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const previousRows = this.rowsByVersionId.get(latestVersion?.versionId ?? "") ?? []
|
|
409
|
+
const previousByKey = this.rowsByPrimaryKey(previousRows, definition)
|
|
410
|
+
const finalChanges = new Map<string, MergeChange<DatasetRow, DatasetRow>>()
|
|
411
|
+
for (const change of options.changes) {
|
|
412
|
+
const value = change.kind === "upsert" ? change.row : change.key
|
|
413
|
+
finalChanges.set(encodeDatasetPrimaryKey(definition, value), change)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const nextByKey = new Map(previousByKey)
|
|
417
|
+
for (const [primaryKey, change] of finalChanges) {
|
|
418
|
+
if (change.kind === "upsert") {
|
|
419
|
+
nextByKey.set(primaryKey, cloneRow(change.row))
|
|
420
|
+
} else {
|
|
421
|
+
nextByKey.delete(primaryKey)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (this.sameKeyedRowContent(previousByKey, nextByKey, definition.schema)) {
|
|
426
|
+
return {
|
|
427
|
+
outcome: "unchanged",
|
|
428
|
+
version: latestVersion ? cloneDatasetVersion(latestVersion) : null,
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const visibleRows = [...nextByKey.values()]
|
|
433
|
+
const versionId = `ver_${randomUUID()}`
|
|
434
|
+
const version: DatasetVersion = {
|
|
435
|
+
datasetId: options.merge.dataset.id,
|
|
436
|
+
versionId,
|
|
437
|
+
parentVersionId: latestVersion?.versionId,
|
|
438
|
+
mode: "merge",
|
|
439
|
+
createdAt: new Date(),
|
|
440
|
+
schema: definition.schema,
|
|
441
|
+
producer: options.merge.producer ? structuredClone(options.merge.producer) : undefined,
|
|
442
|
+
inputs: options.merge.inputs ? structuredClone(options.merge.inputs) : undefined,
|
|
443
|
+
rowCount: visibleRows.length,
|
|
444
|
+
sizeBytes: new TextEncoder().encode(
|
|
445
|
+
visibleRows.map((row) => JSON.stringify(row)).join("\n")
|
|
446
|
+
).byteLength,
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const versions = this.versionsByDataset.get(options.merge.dataset.id) ?? []
|
|
450
|
+
versions.push(version)
|
|
451
|
+
this.versionsByDataset.set(options.merge.dataset.id, versions)
|
|
452
|
+
this.rowsByVersionId.set(
|
|
453
|
+
versionId,
|
|
454
|
+
visibleRows.map((row) => cloneRow(row))
|
|
455
|
+
)
|
|
456
|
+
this.latestVersionIdByDataset.set(options.merge.dataset.id, versionId)
|
|
457
|
+
|
|
458
|
+
return { outcome: "created", version: cloneDatasetVersion(version) }
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
private async commitWriteUnlocked(options: {
|
|
463
|
+
write: BeginDatasetWriteInput
|
|
464
|
+
rows: readonly DatasetRow[]
|
|
465
|
+
commit?: CommitDatasetWriteInput
|
|
270
466
|
}): Promise<DatasetWriteCommitResult> {
|
|
271
467
|
const definition = this.datasets.get(options.write.dataset.id)
|
|
272
468
|
if (!definition) {
|
|
@@ -285,6 +481,8 @@ export class InMemoryLakeStorage implements LakeStorage {
|
|
|
285
481
|
}
|
|
286
482
|
}
|
|
287
483
|
|
|
484
|
+
this.assertKeyedWriteIsUnique(mode, options.rows, latestVersion, definition)
|
|
485
|
+
|
|
288
486
|
// Content-identical snapshots and empty appends reuse the latest version
|
|
289
487
|
// instead of creating a new one.
|
|
290
488
|
if (
|
|
@@ -345,4 +543,88 @@ export class InMemoryLakeStorage implements LakeStorage {
|
|
|
345
543
|
previousRows.map((row) => rowContentKey(row, schema))
|
|
346
544
|
)
|
|
347
545
|
}
|
|
546
|
+
|
|
547
|
+
private assertKeyedWriteIsUnique(
|
|
548
|
+
mode: DatasetWriteMode,
|
|
549
|
+
rows: readonly DatasetRow[],
|
|
550
|
+
latestVersion: DatasetVersion | null,
|
|
551
|
+
definition: DatasetDefinition
|
|
552
|
+
): void {
|
|
553
|
+
if (getDatasetPrimaryKeyColumns(definition) === null) {
|
|
554
|
+
return
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const stagedByKey = this.rowsByPrimaryKey(rows, definition)
|
|
558
|
+
if (mode !== "append" || latestVersion === null) {
|
|
559
|
+
return
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const previousRows = this.rowsByVersionId.get(latestVersion.versionId) ?? []
|
|
563
|
+
const previousByKey = this.rowsByPrimaryKey(previousRows, definition)
|
|
564
|
+
for (const primaryKey of stagedByKey.keys()) {
|
|
565
|
+
if (previousByKey.has(primaryKey)) {
|
|
566
|
+
throw new LakeStorageError(
|
|
567
|
+
`[LakeStorage] Dataset '${definition.id}' append contains duplicate primary key ${primaryKey}.`
|
|
568
|
+
)
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private rowsByPrimaryKey(
|
|
574
|
+
rows: readonly DatasetRow[],
|
|
575
|
+
definition: DatasetDefinition
|
|
576
|
+
): Map<string, DatasetRow> {
|
|
577
|
+
const byKey = new Map<string, DatasetRow>()
|
|
578
|
+
for (const row of rows) {
|
|
579
|
+
const primaryKey = encodeDatasetPrimaryKey(definition, row)
|
|
580
|
+
if (byKey.has(primaryKey)) {
|
|
581
|
+
throw new LakeStorageError(
|
|
582
|
+
`[LakeStorage] Dataset '${definition.id}' contains duplicate primary key ${primaryKey}.`
|
|
583
|
+
)
|
|
584
|
+
}
|
|
585
|
+
byKey.set(primaryKey, row)
|
|
586
|
+
}
|
|
587
|
+
return byKey
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
private sameKeyedRowContent(
|
|
591
|
+
left: ReadonlyMap<string, DatasetRow>,
|
|
592
|
+
right: ReadonlyMap<string, DatasetRow>,
|
|
593
|
+
schema: DatasetSchema
|
|
594
|
+
): boolean {
|
|
595
|
+
if (left.size !== right.size) {
|
|
596
|
+
return false
|
|
597
|
+
}
|
|
598
|
+
for (const [primaryKey, leftRow] of left) {
|
|
599
|
+
const rightRow = right.get(primaryKey)
|
|
600
|
+
if (
|
|
601
|
+
rightRow === undefined ||
|
|
602
|
+
rowContentKey(leftRow, schema) !== rowContentKey(rightRow, schema)
|
|
603
|
+
) {
|
|
604
|
+
return false
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return true
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private async withDatasetCommitLock<T>(datasetId: string, run: () => Promise<T>): Promise<T> {
|
|
611
|
+
const previous = this.commitLocks.get(datasetId) ?? Promise.resolve()
|
|
612
|
+
const ready = previous.catch(() => {})
|
|
613
|
+
let release!: () => void
|
|
614
|
+
const next = new Promise<void>((resolve) => {
|
|
615
|
+
release = resolve
|
|
616
|
+
})
|
|
617
|
+
const current = ready.then(() => next)
|
|
618
|
+
this.commitLocks.set(datasetId, current)
|
|
619
|
+
|
|
620
|
+
await ready
|
|
621
|
+
try {
|
|
622
|
+
return await run()
|
|
623
|
+
} finally {
|
|
624
|
+
release()
|
|
625
|
+
if (this.commitLocks.get(datasetId) === current) {
|
|
626
|
+
this.commitLocks.delete(datasetId)
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
348
630
|
}
|
|
@@ -2,7 +2,9 @@ export type {
|
|
|
2
2
|
DatasetColumnDefinition,
|
|
3
3
|
DatasetColumnType,
|
|
4
4
|
DatasetDefinition,
|
|
5
|
+
DatasetPrimaryKey,
|
|
5
6
|
DatasetSchema,
|
|
7
|
+
MergeChange,
|
|
6
8
|
} from "../datasets"
|
|
7
9
|
export type { JsonValue } from "../json"
|
|
8
10
|
export type {
|
|
@@ -17,6 +19,18 @@ export {
|
|
|
17
19
|
} from "./definition-updates"
|
|
18
20
|
export { LakeStorageError } from "./errors"
|
|
19
21
|
export { InMemoryLakeStorage } from "./in-memory"
|
|
22
|
+
export type {
|
|
23
|
+
BeginDatasetMergeInput,
|
|
24
|
+
CommitDatasetMergeInput,
|
|
25
|
+
DatasetMergeCommitResult,
|
|
26
|
+
LakeMergeSession,
|
|
27
|
+
} from "./merge"
|
|
28
|
+
export {
|
|
29
|
+
cloneDatasetMergeChange,
|
|
30
|
+
encodeDatasetPrimaryKey,
|
|
31
|
+
getDatasetMergeChangeValidationError,
|
|
32
|
+
getDatasetPrimaryKeyColumns,
|
|
33
|
+
} from "./merge-validation"
|
|
20
34
|
export type {
|
|
21
35
|
ExecuteSqlTransformInput,
|
|
22
36
|
LakeSqlExecutor,
|