okengine 0.3.5 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +6 -0
- package/manifest.v1.schema.json +43 -1
- package/package.json +27 -12
- package/site/content/docs/ai/skills.mdx +11 -7
- package/site/content/docs/console/vault.mdx +4 -0
- package/site/content/docs/elements/ai.mdx +2 -0
- package/site/content/docs/elements/channel.mdx +7 -4
- package/site/content/docs/elements/clock.mdx +2 -4
- package/site/content/docs/elements/flow.mdx +19 -10
- package/site/content/docs/elements/gate.mdx +18 -11
- package/site/content/docs/elements/signal.mdx +9 -12
- package/site/content/docs/elements/store.mdx +69 -8
- package/site/content/docs/elements/vault.mdx +11 -12
- package/site/content/docs/get-started/basic-usage.mdx +76 -41
- package/site/content/docs/get-started/installation.mdx +95 -43
- package/site/content/docs/get-started/introduction.mdx +128 -75
- package/site/content/docs/get-started/meta.json +1 -1
- package/site/content/docs/get-started/why.mdx +141 -0
- package/site/content/docs/plugins/ip-allowlist.mdx +1 -2
- package/site/content/docs/plugins/security-headers.mdx +1 -1
- package/site/content/docs/reference/configuration.mdx +2 -2
- package/site/content/docs/reference/environment-variables.mdx +10 -0
- package/site/content/docs/reference/fx.mdx +56 -3
- package/site/content/docs/reference/plugins.mdx +18 -18
- package/src/cli/competitor-mention-removal.test.ts +117 -0
- package/src/cli/dev.ts +20 -0
- package/src/cli/meilisearch-local.test.ts +69 -0
- package/src/cli/meilisearch-local.ts +188 -0
- package/src/compiler/extract.test.ts +63 -0
- package/src/compiler/extract.ts +36 -15
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +5 -1
- package/src/console/server/channels.ts +2 -0
- package/src/console/server/clock.ts +3 -0
- package/src/console/server/flows.ts +13 -0
- package/src/console/server/gates.ts +2 -0
- package/src/console/server/plugins.ts +20 -1
- package/src/console/server/signals.ts +5 -0
- package/src/console/server/store.test.ts +17 -0
- package/src/console/server/store.ts +35 -1
- package/src/console/ui/channels/types.ts +1 -0
- package/src/console/ui/clock/types.ts +1 -0
- package/src/console/ui/display.test.ts +14 -0
- package/src/console/ui/display.ts +9 -0
- package/src/console/ui/dist/assets/index-CjxwRGVv.js +10 -0
- package/src/console/ui/dist/assets/panel-access-BGv45snf.js +64 -0
- package/src/console/ui/dist/assets/{panel-ai-D_m6WQI8.js → panel-ai-B2S7LEii.js} +1 -1
- package/src/console/ui/dist/assets/{panel-architecture-CKnXFyUx.js → panel-architecture-D7UJh91v.js} +1 -1
- package/src/console/ui/dist/assets/panel-channels-9T3ybqRu.js +1 -0
- package/src/console/ui/dist/assets/panel-clock-Cb1UXGRQ.js +1 -0
- package/src/console/ui/dist/assets/{panel-diff-cdonmH8c.js → panel-diff-DmYbKWmN.js} +1 -1
- package/src/console/ui/dist/assets/panel-flows-PiHwT55z.js +48 -0
- package/src/console/ui/dist/assets/panel-gates-BQGYXvjT.js +1 -0
- package/src/console/ui/dist/assets/panel-overview-BBnRO18l.js +1 -0
- package/src/console/ui/dist/assets/panel-plugins-D0PsmVw2.js +1 -0
- package/src/console/ui/dist/assets/panel-runs-CWuRDe0r.js +1 -0
- package/src/console/ui/dist/assets/panel-signals-Bbg4ewpP.js +1 -0
- package/src/console/ui/dist/assets/panel-store-CPCbsDRa.js +1 -0
- package/src/console/ui/dist/assets/panel-traces-DVAzuA_S.js +1 -0
- package/src/console/ui/dist/assets/panel-vault-D1_MvOmo.js +1 -0
- package/src/console/ui/dist/assets/{rolldown-runtime-CNC7AqOf.js → rolldown-runtime-B0Z9INg1.js} +1 -1
- package/src/console/ui/dist/index.html +2 -2
- package/src/console/ui/gates/types.ts +1 -0
- package/src/console/ui/plugins/fixture.ts +7 -0
- package/src/console/ui/plugins/types.ts +3 -0
- package/src/console/ui/shell/client.ts +3 -0
- package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +7 -2
- package/src/console/ui/shell/panels/clock/ClockPanel.tsx +9 -2
- package/src/console/ui/shell/panels/gates/GatesPanel.tsx +12 -5
- package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +18 -4
- package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +13 -2
- package/src/console/ui/shell/panels/store/StorePanel.tsx +11 -4
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +9 -3
- package/src/console/ui/signals/types.ts +1 -0
- package/src/console/ui/store/fixture.ts +5 -0
- package/src/console/ui/store/types.ts +2 -0
- package/src/docker/compose.ts +5 -0
- package/src/docker/docker.test.ts +41 -0
- package/src/docker/recipes/index.ts +10 -2
- package/src/docker/recipes/meilisearch.ts +31 -0
- package/src/drivers/conformance.test.ts +26 -0
- package/src/drivers/conformance.ts +40 -3
- package/src/drivers/drizzle-dialect.test.ts +4 -0
- package/src/drivers/drizzle-dialect.ts +8 -4
- package/src/drivers/index.ts +18 -2
- package/src/drivers/libsql.ts +179 -0
- package/src/drivers/meilisearch.integration.test.ts +77 -0
- package/src/drivers/meilisearch.test.ts +181 -0
- package/src/drivers/meilisearch.ts +208 -0
- package/src/drivers/memory.ts +4 -4
- package/src/drivers/pglite.ts +79 -0
- package/src/drivers/pgvector.ts +60 -25
- package/src/drivers/types.ts +106 -16
- package/src/drivers/vault-driver-removal.test.ts +6 -0
- package/src/drivers/vault-types.ts +4 -4
- package/src/elements/ai/runtime.ts +6 -0
- package/src/elements/ai.test.ts +22 -0
- package/src/elements/channel/declare.ts +5 -0
- package/src/elements/clock/declare.ts +5 -0
- package/src/elements/clock/durable.ts +7 -1
- package/src/elements/gate/declare.ts +28 -5
- package/src/elements/gate.ts +1 -0
- package/src/elements/signal/declare.ts +5 -0
- package/src/elements/store/declare.ts +10 -2
- package/src/elements/store/index-boot.test.ts +299 -0
- package/src/elements/store/runtime.ts +110 -17
- package/src/elements/store/schema-decl.ts +7 -0
- package/src/elements/store.ts +2 -0
- package/src/elements/vault.test.ts +27 -4
- package/src/elements/vault.ts +1 -1
- package/src/index.ts +4 -0
- package/src/kernel/abort-scope.ts +116 -0
- package/src/kernel/app.ts +12 -2
- package/src/kernel/boot-bind/store.test.ts +68 -1
- package/src/kernel/boot-bind/store.ts +92 -2
- package/src/kernel/concurrency.test.ts +294 -0
- package/src/kernel/concurrency.ts +220 -0
- package/src/kernel/flow.ts +9 -0
- package/src/kernel/fx.test.ts +23 -2
- package/src/kernel/fx.ts +80 -4
- package/src/kernel/index.ts +23 -0
- package/src/kernel/journal.ts +9 -0
- package/src/kernel/plugin/capabilities.test.ts +18 -0
- package/src/kernel/plugin.ts +11 -3
- package/src/kernel/redacted.ts +74 -0
- package/src/kernel/registry.ts +29 -6
- package/src/kernel/router.ts +3 -3
- package/src/manifest/types.ts +21 -0
- package/src/release/measure.ts +4 -0
- package/src/test/provisions.integration.test.ts +1 -1
- package/site/content/docs/get-started/comparison.mdx +0 -65
- package/src/console/ui/dist/assets/index-BWo8R7NR.js +0 -10
- package/src/console/ui/dist/assets/panel-access-C0J2D-a2.js +0 -64
- package/src/console/ui/dist/assets/panel-channels-BOmQ-onL.js +0 -1
- package/src/console/ui/dist/assets/panel-clock-giAq0Ccv.js +0 -1
- package/src/console/ui/dist/assets/panel-flows-DlCU5zjA.js +0 -45
- package/src/console/ui/dist/assets/panel-gates-XclZxWD5.js +0 -1
- package/src/console/ui/dist/assets/panel-overview-BznEOTnb.js +0 -1
- package/src/console/ui/dist/assets/panel-plugins-CcGM1g64.js +0 -1
- package/src/console/ui/dist/assets/panel-runs-CGWNHLR4.js +0 -1
- package/src/console/ui/dist/assets/panel-signals-CNywkdak.js +0 -1
- package/src/console/ui/dist/assets/panel-store-KmTbFHMH.js +0 -1
- package/src/console/ui/dist/assets/panel-traces-DBLx2ilD.js +0 -1
- package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +0 -1
- package/src/drivers/vault-infisical.ts +0 -57
package/src/elements/vault.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Vault element — protected knowledge.
|
|
3
3
|
*
|
|
4
4
|
* Physics: secrets · config · environment.
|
|
5
|
-
* Drivers: `env` · `openbao` · `
|
|
5
|
+
* Drivers: `env` · `openbao` · `managed`.
|
|
6
6
|
*
|
|
7
7
|
* A declaration is a contract, never a value. Boot validates every contract
|
|
8
8
|
* and lists all gaps at once. Logs/traces receive fingerprints and redaction
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient AbortSignal scope for structured concurrency.
|
|
3
|
+
*
|
|
4
|
+
* Same ALS pattern as dry-run: `fx.all` / `fx.race` enter a child signal so
|
|
5
|
+
* cooperative branches (and future driver plumbing) can observe cancellation
|
|
6
|
+
* without every call site passing a signal argument.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
+
|
|
11
|
+
/** Never-aborted signal used outside an `all` / `race` branch. */
|
|
12
|
+
const NEVER_ABORTED = new AbortController().signal;
|
|
13
|
+
|
|
14
|
+
const storage = new AsyncLocalStorage<AbortSignal>();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* AbortSignal for the current async chain, or a never-aborted signal when
|
|
18
|
+
* no structured-concurrency scope is active.
|
|
19
|
+
*/
|
|
20
|
+
export function currentAbortSignal(): AbortSignal {
|
|
21
|
+
return storage.getStore() ?? NEVER_ABORTED;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Run `fn` with `signal` as the ambient abort signal.
|
|
26
|
+
*
|
|
27
|
+
* @param signal - Branch / scope signal
|
|
28
|
+
* @param fn - Work that may read {@link currentAbortSignal}
|
|
29
|
+
*/
|
|
30
|
+
export async function withAbortSignal<T>(
|
|
31
|
+
signal: AbortSignal,
|
|
32
|
+
fn: () => T | Promise<T>,
|
|
33
|
+
): Promise<T> {
|
|
34
|
+
return storage.run(signal, fn);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* When `parent` aborts, abort `child` with the same reason.
|
|
39
|
+
*
|
|
40
|
+
* @param parent - Outer signal
|
|
41
|
+
* @param child - Controller to abort
|
|
42
|
+
* @returns Unsubscribe
|
|
43
|
+
*/
|
|
44
|
+
export function linkAbort(parent: AbortSignal, child: AbortController): () => void {
|
|
45
|
+
if (parent.aborted) {
|
|
46
|
+
child.abort(parent.reason);
|
|
47
|
+
return () => undefined;
|
|
48
|
+
}
|
|
49
|
+
const onAbort = (): void => {
|
|
50
|
+
child.abort(parent.reason);
|
|
51
|
+
};
|
|
52
|
+
parent.addEventListener("abort", onAbort);
|
|
53
|
+
return () => parent.removeEventListener("abort", onAbort);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* True when `err` is an abort rejection (`AbortError` name).
|
|
58
|
+
*
|
|
59
|
+
* @param err - Unknown
|
|
60
|
+
*/
|
|
61
|
+
export function isAbortError(err: unknown): boolean {
|
|
62
|
+
return err instanceof Error && err.name === "AbortError";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create an `AbortError` matching Web / fetch abort rejections.
|
|
67
|
+
*
|
|
68
|
+
* @param reason - Optional abort reason
|
|
69
|
+
*/
|
|
70
|
+
export function abortError(reason?: unknown): Error {
|
|
71
|
+
if (typeof DOMException === "function") {
|
|
72
|
+
const message =
|
|
73
|
+
reason instanceof Error
|
|
74
|
+
? reason.message
|
|
75
|
+
: reason !== undefined
|
|
76
|
+
? String(reason)
|
|
77
|
+
: "This operation was aborted";
|
|
78
|
+
return new DOMException(message, "AbortError");
|
|
79
|
+
}
|
|
80
|
+
const err = new Error(
|
|
81
|
+
reason instanceof Error
|
|
82
|
+
? reason.message
|
|
83
|
+
: reason !== undefined
|
|
84
|
+
? String(reason)
|
|
85
|
+
: "This operation was aborted",
|
|
86
|
+
);
|
|
87
|
+
err.name = "AbortError";
|
|
88
|
+
return err;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Sleep that rejects promptly when `signal` aborts.
|
|
93
|
+
*
|
|
94
|
+
* Not durable — retry backoff must not journal via `fx.clock.sleep`.
|
|
95
|
+
*
|
|
96
|
+
* @param ms - Milliseconds
|
|
97
|
+
* @param signal - Optional abort signal
|
|
98
|
+
*/
|
|
99
|
+
export function abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {
|
|
100
|
+
if (ms <= 0) return Promise.resolve();
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
if (signal?.aborted) {
|
|
103
|
+
reject(abortError(signal.reason));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const timer = setTimeout(() => {
|
|
107
|
+
signal?.removeEventListener("abort", onAbort);
|
|
108
|
+
resolve();
|
|
109
|
+
}, ms);
|
|
110
|
+
const onAbort = (): void => {
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
reject(abortError(signal?.reason));
|
|
113
|
+
};
|
|
114
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
115
|
+
});
|
|
116
|
+
}
|
package/src/kernel/app.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from "./auth-resolve.ts";
|
|
34
34
|
import { runDurable } from "../elements/clock/durable.ts";
|
|
35
35
|
import { isFlow, type AnyFlowDef } from "./flow.ts";
|
|
36
|
+
import { fxRetry } from "./concurrency.ts";
|
|
36
37
|
import {
|
|
37
38
|
createFxContext,
|
|
38
39
|
resolveName,
|
|
@@ -680,13 +681,22 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
680
681
|
hooks,
|
|
681
682
|
async () => {
|
|
682
683
|
try {
|
|
684
|
+
const invoke = async (input: unknown) => {
|
|
685
|
+
const run = () => {
|
|
686
|
+
// Flow-level retry re-enters `do` on the same journal session —
|
|
687
|
+
// rewind so completed steps/effects replay instead of re-executing.
|
|
688
|
+
journalSession?.rewind();
|
|
689
|
+
return flowDef.do(input as never, fx);
|
|
690
|
+
};
|
|
691
|
+
return flowDef.retry ? fxRetry(run, flowDef.retry) : run();
|
|
692
|
+
};
|
|
683
693
|
if (!alreadyValidated) {
|
|
684
694
|
const parsed = await validate(flowDef.in, ctx.input);
|
|
685
695
|
if (!parsed.ok) return parsed.failure;
|
|
686
696
|
ctx.input = parsed.value;
|
|
687
|
-
return await
|
|
697
|
+
return await invoke(parsed.value);
|
|
688
698
|
}
|
|
689
|
-
return await
|
|
699
|
+
return await invoke(ctx.input);
|
|
690
700
|
} catch (err) {
|
|
691
701
|
// A durable sleep that has not yet elapsed suspends the run — this
|
|
692
702
|
// is a park, not a pipeline failure, so it must not throw upward.
|
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
indexDriverFor,
|
|
8
|
+
resolveFilesDriverId,
|
|
9
|
+
resolveIndexDriverId,
|
|
10
|
+
resolveKvDriverId,
|
|
11
|
+
resolveSqlDriverId,
|
|
12
|
+
} from "./store.ts";
|
|
7
13
|
|
|
8
14
|
describe("bindStore driver resolution", () => {
|
|
9
15
|
const prev = {
|
|
@@ -11,6 +17,7 @@ describe("bindStore driver resolution", () => {
|
|
|
11
17
|
sql: process.env.OKE_SQL_DRIVER,
|
|
12
18
|
kv: process.env.OKE_KV_DRIVER,
|
|
13
19
|
files: process.env.OKE_FILES_DRIVER,
|
|
20
|
+
index: process.env.OKE_INDEX_DRIVER,
|
|
14
21
|
};
|
|
15
22
|
|
|
16
23
|
afterEach(() => {
|
|
@@ -22,6 +29,8 @@ describe("bindStore driver resolution", () => {
|
|
|
22
29
|
else process.env.OKE_KV_DRIVER = prev.kv;
|
|
23
30
|
if (prev.files === undefined) delete process.env.OKE_FILES_DRIVER;
|
|
24
31
|
else process.env.OKE_FILES_DRIVER = prev.files;
|
|
32
|
+
if (prev.index === undefined) delete process.env.OKE_INDEX_DRIVER;
|
|
33
|
+
else process.env.OKE_INDEX_DRIVER = prev.index;
|
|
25
34
|
});
|
|
26
35
|
|
|
27
36
|
test("local env keeps sqlite / memory from config", () => {
|
|
@@ -67,3 +76,61 @@ describe("bindStore driver resolution", () => {
|
|
|
67
76
|
expect(resolveFilesDriverId({}, "docker", true)).toBe("s3");
|
|
68
77
|
});
|
|
69
78
|
});
|
|
79
|
+
|
|
80
|
+
describe("bindStore index driver resolution", () => {
|
|
81
|
+
const prevIndex = process.env.OKE_INDEX_DRIVER;
|
|
82
|
+
|
|
83
|
+
afterEach(() => {
|
|
84
|
+
if (prevIndex === undefined) delete process.env.OKE_INDEX_DRIVER;
|
|
85
|
+
else process.env.OKE_INDEX_DRIVER = prevIndex;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("defaults to memory when no index driver is configured", () => {
|
|
89
|
+
expect(resolveIndexDriverId({}, "local", false)).toBe("memory");
|
|
90
|
+
expect(resolveIndexDriverId({}, "docker", true)).toBe("memory");
|
|
91
|
+
expect(indexDriverFor("memory").id).toBe("memory");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("config drivers.store.index is honoured per env", () => {
|
|
95
|
+
const options = {
|
|
96
|
+
config: {
|
|
97
|
+
drivers: {
|
|
98
|
+
store: {
|
|
99
|
+
index: { local: "memory", docker: "pgvector", prod: "pgvector" },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
expect(resolveIndexDriverId(options, "local", false)).toBe("memory");
|
|
105
|
+
expect(resolveIndexDriverId(options, "docker", true)).toBe("pgvector");
|
|
106
|
+
expect(resolveIndexDriverId(options, "prod", false)).toBe("pgvector");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("libsql resolves from config", () => {
|
|
110
|
+
const options = {
|
|
111
|
+
config: { drivers: { store: { index: { local: "libsql" } } } },
|
|
112
|
+
};
|
|
113
|
+
expect(resolveIndexDriverId(options, "local", false)).toBe("libsql");
|
|
114
|
+
expect(indexDriverFor("libsql").id).toBe("libsql");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("meilisearch resolves from config as a fourth id", () => {
|
|
118
|
+
const options = {
|
|
119
|
+
config: { drivers: { store: { index: { local: "meilisearch", docker: "meilisearch" } } } },
|
|
120
|
+
};
|
|
121
|
+
expect(resolveIndexDriverId(options, "local", false)).toBe("meilisearch");
|
|
122
|
+
expect(resolveIndexDriverId(options, "docker", true)).toBe("meilisearch");
|
|
123
|
+
expect(indexDriverFor("meilisearch").id).toBe("meilisearch");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("docker mode honours OKE_INDEX_DRIVER override", () => {
|
|
127
|
+
process.env.OKE_INDEX_DRIVER = "pgvector";
|
|
128
|
+
expect(resolveIndexDriverId({}, "docker", true)).toBe("pgvector");
|
|
129
|
+
expect(resolveIndexDriverId({}, "local", false)).toBe("memory");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("indexDriverFor returns the configured driver and throws on unknown ids", () => {
|
|
133
|
+
expect(indexDriverFor("pgvector").id).toBe("pgvector");
|
|
134
|
+
expect(() => indexDriverFor("chroma")).toThrow(/unknown index driver "chroma"/);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -4,12 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import { resolveDomainDdlMode, resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
6
6
|
import { fsDriver } from "../../drivers/fs.ts";
|
|
7
|
+
import { libsqlDriver, libsqlIndexDriver } from "../../drivers/libsql.ts";
|
|
8
|
+
import { meilisearchDriver } from "../../drivers/meilisearch.ts";
|
|
7
9
|
import { memoryDrivers } from "../../drivers/memory.ts";
|
|
10
|
+
import { pgliteDriver } from "../../drivers/pglite.ts";
|
|
11
|
+
import { pgvectorDriver } from "../../drivers/pgvector.ts";
|
|
8
12
|
import { postgresDriver } from "../../drivers/postgres.ts";
|
|
9
13
|
import { redisDriver } from "../../drivers/redis.ts";
|
|
10
14
|
import { s3Driver } from "../../drivers/s3.ts";
|
|
11
15
|
import { sqliteDriver } from "../../drivers/sqlite.ts";
|
|
12
|
-
import type { FilesDriver, KvDriver, SqlDriver } from "../../drivers/types.ts";
|
|
16
|
+
import type { FilesDriver, IndexDriver, KvDriver, SqlDriver } from "../../drivers/types.ts";
|
|
13
17
|
import { createStoreRuntime, type StoreRuntime } from "../../elements/store.ts";
|
|
14
18
|
import type { StoreDecl } from "../../elements/store/declare.ts";
|
|
15
19
|
import type { BootOptions } from "../boot.ts"; // type-only — no cycle at runtime
|
|
@@ -34,6 +38,7 @@ export function bindStore(
|
|
|
34
38
|
const sqlId = resolveSqlDriverId(options, env, docker);
|
|
35
39
|
const kvId = resolveKvDriverId(options, env, docker);
|
|
36
40
|
const filesId = resolveFilesDriverId(options, env, docker);
|
|
41
|
+
const indexId = resolveIndexDriverId(options, env, docker);
|
|
37
42
|
const sqlUrl = sqlUrlFor(sqlId, docker);
|
|
38
43
|
const kvUrl = kvUrlFor(kvId, docker);
|
|
39
44
|
const filesRoot = filesRootFor(filesId);
|
|
@@ -41,6 +46,7 @@ export function bindStore(
|
|
|
41
46
|
const sqlBindings: Record<string, { name: string; primary: { url: string } }> = {};
|
|
42
47
|
const kvBindings: Record<string, { url?: string }> = {};
|
|
43
48
|
const filesBindings: Record<string, { root?: string }> = {};
|
|
49
|
+
const indexBindings: Record<string, { url?: string; apiKey?: string }> = {};
|
|
44
50
|
|
|
45
51
|
for (const decl of options.stores ?? []) {
|
|
46
52
|
if (isSqlDecl(decl)) {
|
|
@@ -52,6 +58,17 @@ export function bindStore(
|
|
|
52
58
|
kvBindings[decl.name] = kvUrl !== undefined ? { url: kvUrl } : {};
|
|
53
59
|
} else if (isFilesDecl(decl)) {
|
|
54
60
|
filesBindings[decl.name] = filesRoot !== undefined ? { root: filesRoot } : {};
|
|
61
|
+
} else if (isIndexDecl(decl)) {
|
|
62
|
+
// SQL-backed index drivers share the sql facet's URL — the runtime opens
|
|
63
|
+
// one connection and hands it to both (never a second, redundant one).
|
|
64
|
+
// Meilisearch is a standalone HTTP service: its own URL + key, never sqlUrl.
|
|
65
|
+
if (indexId === "memory") {
|
|
66
|
+
indexBindings[decl.name] = {};
|
|
67
|
+
} else if (indexId === "meilisearch") {
|
|
68
|
+
indexBindings[decl.name] = { url: indexUrlFor(docker), apiKey: indexApiKeyFor() };
|
|
69
|
+
} else {
|
|
70
|
+
indexBindings[decl.name] = { url: sqlUrl };
|
|
71
|
+
}
|
|
55
72
|
}
|
|
56
73
|
}
|
|
57
74
|
|
|
@@ -63,11 +80,12 @@ export function bindStore(
|
|
|
63
80
|
sql: sqlDriverFor(sqlId),
|
|
64
81
|
kv: kvDriverFor(kvId),
|
|
65
82
|
files: filesDriverFor(filesId),
|
|
66
|
-
index:
|
|
83
|
+
index: indexDriverFor(indexId),
|
|
67
84
|
},
|
|
68
85
|
sql: sqlBindings,
|
|
69
86
|
kv: kvBindings,
|
|
70
87
|
files: filesBindings,
|
|
88
|
+
index: indexBindings,
|
|
71
89
|
now,
|
|
72
90
|
domainDdl,
|
|
73
91
|
});
|
|
@@ -132,12 +150,37 @@ export function resolveFilesDriverId(
|
|
|
132
150
|
return docker ? "s3" : "memory";
|
|
133
151
|
}
|
|
134
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Index driver — same resolution chain as sql/kv/files. Defaults to `memory`;
|
|
155
|
+
* a configured `pgvector` / `libsql` is honoured at real boot (and fails loud
|
|
156
|
+
* if its SQL engine or peer is missing — never silently back to memory).
|
|
157
|
+
*
|
|
158
|
+
* @param options - Boot options
|
|
159
|
+
* @param env - Active env
|
|
160
|
+
* @param docker - Docker mode
|
|
161
|
+
*/
|
|
162
|
+
export function resolveIndexDriverId(
|
|
163
|
+
options: BootOptions,
|
|
164
|
+
env: ConfigEnv,
|
|
165
|
+
docker: boolean,
|
|
166
|
+
): string {
|
|
167
|
+
const fromEnv = process.env.OKE_INDEX_DRIVER?.trim();
|
|
168
|
+
if (docker && fromEnv) return fromEnv;
|
|
169
|
+
const resolved = resolveDriverId(options.config?.drivers?.store?.index, env);
|
|
170
|
+
if (resolved) return resolved;
|
|
171
|
+
return "memory";
|
|
172
|
+
}
|
|
173
|
+
|
|
135
174
|
function sqlDriverFor(id: string): SqlDriver {
|
|
136
175
|
switch (id) {
|
|
137
176
|
case "postgres":
|
|
138
177
|
return postgresDriver;
|
|
139
178
|
case "sqlite":
|
|
140
179
|
return sqliteDriver;
|
|
180
|
+
case "libsql":
|
|
181
|
+
return libsqlDriver;
|
|
182
|
+
case "pglite":
|
|
183
|
+
return pgliteDriver;
|
|
141
184
|
case "memory":
|
|
142
185
|
return memoryDrivers.sql;
|
|
143
186
|
default:
|
|
@@ -169,6 +212,25 @@ function filesDriverFor(id: string): FilesDriver {
|
|
|
169
212
|
}
|
|
170
213
|
}
|
|
171
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Single id → index driver switch — shared by `bindStore` and the Console's
|
|
217
|
+
* Manifest runtime so resolution can never drift into two maintained copies.
|
|
218
|
+
*/
|
|
219
|
+
export function indexDriverFor(id: string): IndexDriver {
|
|
220
|
+
switch (id) {
|
|
221
|
+
case "memory":
|
|
222
|
+
return memoryDrivers.index;
|
|
223
|
+
case "pgvector":
|
|
224
|
+
return pgvectorDriver;
|
|
225
|
+
case "libsql":
|
|
226
|
+
return libsqlIndexDriver;
|
|
227
|
+
case "meilisearch":
|
|
228
|
+
return meilisearchDriver;
|
|
229
|
+
default:
|
|
230
|
+
throw new Error(`oke boot: unknown index driver "${id}"`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
172
234
|
function sqlUrlFor(sqlId: string, docker: boolean): string {
|
|
173
235
|
if (sqlId === "postgres") {
|
|
174
236
|
const url = process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL ?? undefined;
|
|
@@ -184,6 +246,12 @@ function sqlUrlFor(sqlId: string, docker: boolean): string {
|
|
|
184
246
|
if (sqlId === "sqlite") {
|
|
185
247
|
return process.env.OKE_SQLITE_URL ?? ".oke/app.sqlite";
|
|
186
248
|
}
|
|
249
|
+
if (sqlId === "libsql") {
|
|
250
|
+
return process.env.OKE_LIBSQL_URL ?? ".oke/app.libsql";
|
|
251
|
+
}
|
|
252
|
+
if (sqlId === "pglite") {
|
|
253
|
+
return process.env.OKE_PGLITE_URL ?? ".oke/pgdata";
|
|
254
|
+
}
|
|
187
255
|
return ":memory:";
|
|
188
256
|
}
|
|
189
257
|
|
|
@@ -205,6 +273,24 @@ function filesRootFor(filesId: string): string | undefined {
|
|
|
205
273
|
return process.env.S3_BUCKET ?? process.env.OKE_STORE_FILES_DB ?? undefined;
|
|
206
274
|
}
|
|
207
275
|
|
|
276
|
+
/** Meilisearch base URL — standalone HTTP service, fail loud when missing. */
|
|
277
|
+
function indexUrlFor(docker: boolean): string {
|
|
278
|
+
const url = process.env.OKE_STORE_INDEX_URL ?? undefined;
|
|
279
|
+
if (!url) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
docker
|
|
282
|
+
? "oke boot: meilisearch index needs OKE_STORE_INDEX_URL (did `oke dev -d` write docker/.env.docker?)"
|
|
283
|
+
: "oke boot: meilisearch index needs OKE_STORE_INDEX_URL",
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
return url;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Meilisearch API / master key. */
|
|
290
|
+
function indexApiKeyFor(): string | undefined {
|
|
291
|
+
return process.env.OKE_STORE_INDEX_KEY ?? process.env.MEILI_MASTER_KEY ?? undefined;
|
|
292
|
+
}
|
|
293
|
+
|
|
208
294
|
function isSqlDecl(decl: StoreDecl): decl is Extract<StoreDecl, { facet: "sql" }> {
|
|
209
295
|
return decl.facet === "sql";
|
|
210
296
|
}
|
|
@@ -216,3 +302,7 @@ function isKvDecl(decl: StoreDecl): decl is Extract<StoreDecl, { facet: "kv" }>
|
|
|
216
302
|
function isFilesDecl(decl: StoreDecl): decl is Extract<StoreDecl, { facet: "files" }> {
|
|
217
303
|
return decl.facet === "files";
|
|
218
304
|
}
|
|
305
|
+
|
|
306
|
+
function isIndexDecl(decl: StoreDecl): decl is Extract<StoreDecl, { facet: "index" }> {
|
|
307
|
+
return decl.facet === "index";
|
|
308
|
+
}
|