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
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "../../../plugins/index.ts";
|
|
22
22
|
import { consoleCalls } from "../../client.ts";
|
|
23
23
|
import { Button, Input } from "../../components/ui.tsx";
|
|
24
|
+
import { displayLabel } from "../../../display.ts";
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Plugins panel — read-only catalogue + supply-chain surface.
|
|
@@ -176,10 +177,23 @@ function PluginDetail(props: {
|
|
|
176
177
|
{p.declares.length === 0 ? (
|
|
177
178
|
<p className="mt-2 text-sm text-[var(--oke-muted)]">None</p>
|
|
178
179
|
) : (
|
|
179
|
-
<ul className="mt-2 list-inside list-disc
|
|
180
|
-
{p.declares.map((d) =>
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
<ul className="mt-2 list-inside list-disc text-sm">
|
|
181
|
+
{p.declares.map((d) => {
|
|
182
|
+
const tableName = d.startsWith("table:") ? d.slice("table:".length) : null;
|
|
183
|
+
const description = tableName ? p.tables[tableName]?.description : undefined;
|
|
184
|
+
return (
|
|
185
|
+
<li key={d}>
|
|
186
|
+
{tableName && description ? (
|
|
187
|
+
<>
|
|
188
|
+
<span>{displayLabel(tableName, description)}</span>
|
|
189
|
+
<code className="ml-2 font-mono text-[var(--oke-muted)]">{d}</code>
|
|
190
|
+
</>
|
|
191
|
+
) : (
|
|
192
|
+
<code className="font-mono">{d}</code>
|
|
193
|
+
)}
|
|
194
|
+
</li>
|
|
195
|
+
);
|
|
196
|
+
})}
|
|
183
197
|
</ul>
|
|
184
198
|
)}
|
|
185
199
|
</section>
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
} from "../../../signals/index.ts";
|
|
32
32
|
import { consoleCalls } from "../../client.ts";
|
|
33
33
|
import { Button } from "../../components/ui.tsx";
|
|
34
|
+
import { displayLabel } from "../../../display.ts";
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Signals panel. List + detail + DLQ state lives in URL search params.
|
|
@@ -248,13 +249,18 @@ export function SignalsPanel() {
|
|
|
248
249
|
onClick={() => setSearch(openSignal(search, s.name))}
|
|
249
250
|
>
|
|
250
251
|
<span className="font-medium">
|
|
251
|
-
{s.name}
|
|
252
|
+
{displayLabel(s.name, s.description)}
|
|
252
253
|
{s.orphaned ? (
|
|
253
254
|
<span role="status" className="ml-2 text-xs text-[var(--oke-muted)]">
|
|
254
255
|
orphaned
|
|
255
256
|
</span>
|
|
256
257
|
) : null}
|
|
257
258
|
</span>
|
|
259
|
+
{s.description ? (
|
|
260
|
+
<span className="font-mono text-xs text-[var(--oke-muted)]">
|
|
261
|
+
{s.name}
|
|
262
|
+
</span>
|
|
263
|
+
) : null}
|
|
258
264
|
<span className="text-xs text-[var(--oke-muted)]">
|
|
259
265
|
{s.delivery === "once" && (
|
|
260
266
|
<>
|
|
@@ -299,7 +305,12 @@ export function SignalsPanel() {
|
|
|
299
305
|
<div className="flex flex-col gap-6">
|
|
300
306
|
<div className="flex items-start justify-between gap-4">
|
|
301
307
|
<div>
|
|
302
|
-
<h2 className="text-lg font-semibold">
|
|
308
|
+
<h2 className="text-lg font-semibold">
|
|
309
|
+
{displayLabel(open.name, open.description)}
|
|
310
|
+
</h2>
|
|
311
|
+
{open.description ? (
|
|
312
|
+
<p className="font-mono text-sm text-[var(--oke-muted)]">{open.name}</p>
|
|
313
|
+
) : null}
|
|
303
314
|
<p
|
|
304
315
|
role="status"
|
|
305
316
|
className="mt-2 max-w-prose text-sm leading-relaxed"
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from "../../../store/index.ts";
|
|
25
25
|
import { consoleCalls } from "../../client.ts";
|
|
26
26
|
import { Button } from "../../components/ui.tsx";
|
|
27
|
+
import { displayLabel } from "../../../display.ts";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Store panel. Tenant lives in the header when tenancy is declared.
|
|
@@ -320,7 +321,10 @@ export function StorePanel() {
|
|
|
320
321
|
)}
|
|
321
322
|
onClick={() => setSearch(openStore(search, s.ref))}
|
|
322
323
|
>
|
|
323
|
-
<span>{s.name}</span>
|
|
324
|
+
<span>{displayLabel(s.name, s.description)}</span>
|
|
325
|
+
{s.description ? (
|
|
326
|
+
<span className="font-mono text-xs text-[var(--oke-muted)]">{s.name}</span>
|
|
327
|
+
) : null}
|
|
324
328
|
<span className="text-xs text-[var(--oke-muted)]">
|
|
325
329
|
{s.children.length} resource(s)
|
|
326
330
|
{s.replicaLagMs != null ? ` · lag ${s.replicaLagMs}ms` : ""}
|
|
@@ -469,8 +473,11 @@ function StoreDetail(props: {
|
|
|
469
473
|
return (
|
|
470
474
|
<div className="flex flex-col gap-4">
|
|
471
475
|
<div className="flex flex-wrap items-baseline gap-2">
|
|
472
|
-
<h2 className="text-base font-medium">{open.name}</h2>
|
|
473
|
-
<span className="text-sm text-[var(--oke-muted)]">
|
|
476
|
+
<h2 className="text-base font-medium">{displayLabel(open.name, open.description)}</h2>
|
|
477
|
+
<span className="text-sm text-[var(--oke-muted)]">
|
|
478
|
+
{open.description ? `${open.name} · ` : ""}
|
|
479
|
+
{open.ref}
|
|
480
|
+
</span>
|
|
474
481
|
{open.contentAddressed ? (
|
|
475
482
|
<span role="status" className="text-xs text-[var(--oke-muted)]">
|
|
476
483
|
content-addressed keys
|
|
@@ -610,7 +617,7 @@ function StoreDetail(props: {
|
|
|
610
617
|
<tr>
|
|
611
618
|
{Object.keys(browse.rows[0] ?? { id: 1 }).map((col) => (
|
|
612
619
|
<th key={col} scope="col" className="border-b px-2 py-1">
|
|
613
|
-
{col}
|
|
620
|
+
{displayLabel(col, child?.columnDescriptions[col])}
|
|
614
621
|
</th>
|
|
615
622
|
))}
|
|
616
623
|
<th scope="col" className="border-b px-2 py-1">
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type VaultListResponse,
|
|
21
21
|
type VaultSearch,
|
|
22
22
|
} from "../../../vault/index.ts";
|
|
23
|
+
import { displayLabel } from "../../../display.ts";
|
|
23
24
|
import { consoleCalls } from "../../client.ts";
|
|
24
25
|
import { Button, Input } from "../../components/ui.tsx";
|
|
25
26
|
|
|
@@ -191,7 +192,10 @@ export function VaultPanel() {
|
|
|
191
192
|
)}
|
|
192
193
|
onClick={() => setSearch(openVault(search, s.name))}
|
|
193
194
|
>
|
|
194
|
-
<span
|
|
195
|
+
<span>{displayLabel(s.name, s.description)}</span>
|
|
196
|
+
{s.description ? (
|
|
197
|
+
<span className="font-mono text-xs text-[var(--oke-muted)]">{s.name}</span>
|
|
198
|
+
) : null}
|
|
195
199
|
<span className="truncate text-xs">
|
|
196
200
|
{s.sensitive ? (s.fingerprint ?? "unset") : (s.cleartext ?? "unset")}
|
|
197
201
|
</span>
|
|
@@ -225,9 +229,11 @@ export function VaultPanel() {
|
|
|
225
229
|
) : (
|
|
226
230
|
<div className="flex max-w-2xl flex-col gap-6">
|
|
227
231
|
<div>
|
|
228
|
-
<h2 className="
|
|
232
|
+
<h2 className="text-lg text-[var(--oke-fg)]">
|
|
233
|
+
{displayLabel(open.name, open.description)}
|
|
234
|
+
</h2>
|
|
229
235
|
{open.description ? (
|
|
230
|
-
<p className="text-sm text-[var(--oke-muted)]">{open.
|
|
236
|
+
<p className="font-mono text-sm text-[var(--oke-muted)]">{open.name}</p>
|
|
231
237
|
) : null}
|
|
232
238
|
{open.rotate ? (
|
|
233
239
|
<p className="text-sm text-[var(--oke-muted)]">Rotate hint: {open.rotate}</p>
|
|
@@ -39,6 +39,7 @@ export interface SignalEndpoint {
|
|
|
39
39
|
/** One signal in the operator list. */
|
|
40
40
|
export interface SignalRecord {
|
|
41
41
|
readonly name: string;
|
|
42
|
+
readonly description?: string;
|
|
42
43
|
readonly delivery: SignalDelivery;
|
|
43
44
|
readonly retries: number;
|
|
44
45
|
readonly deadLetterEnabled: boolean;
|
|
@@ -27,6 +27,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
27
27
|
channels: [],
|
|
28
28
|
},
|
|
29
29
|
piiColumns: ["email"],
|
|
30
|
+
columnDescriptions: {},
|
|
30
31
|
},
|
|
31
32
|
{
|
|
32
33
|
name: "shipments",
|
|
@@ -44,6 +45,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
44
45
|
channels: ["booking-confirmed"],
|
|
45
46
|
},
|
|
46
47
|
piiColumns: [],
|
|
48
|
+
columnDescriptions: {},
|
|
47
49
|
},
|
|
48
50
|
],
|
|
49
51
|
replicaLagMs: 240,
|
|
@@ -76,6 +78,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
76
78
|
channels: [],
|
|
77
79
|
},
|
|
78
80
|
piiColumns: [],
|
|
81
|
+
columnDescriptions: {},
|
|
79
82
|
},
|
|
80
83
|
],
|
|
81
84
|
replicaLagMs: null,
|
|
@@ -104,6 +107,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
104
107
|
channels: [],
|
|
105
108
|
},
|
|
106
109
|
piiColumns: [],
|
|
110
|
+
columnDescriptions: {},
|
|
107
111
|
},
|
|
108
112
|
],
|
|
109
113
|
replicaLagMs: null,
|
|
@@ -138,6 +142,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
138
142
|
channels: [],
|
|
139
143
|
},
|
|
140
144
|
piiColumns: [],
|
|
145
|
+
columnDescriptions: {},
|
|
141
146
|
},
|
|
142
147
|
],
|
|
143
148
|
replicaLagMs: null,
|
|
@@ -28,6 +28,7 @@ export interface StoreChild {
|
|
|
28
28
|
readonly cache: StoreCacheView;
|
|
29
29
|
readonly willNotFire: WillNotFire;
|
|
30
30
|
readonly piiColumns: readonly string[];
|
|
31
|
+
readonly columnDescriptions: Readonly<Record<string, string>>;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/** One store row from `console.store.list`. */
|
|
@@ -35,6 +36,7 @@ export interface StoreRecord {
|
|
|
35
36
|
readonly ref: string;
|
|
36
37
|
readonly facet: StoreFacet;
|
|
37
38
|
readonly name: string;
|
|
39
|
+
readonly description?: string;
|
|
38
40
|
readonly children: readonly StoreChild[];
|
|
39
41
|
readonly replicaLagMs: number | null;
|
|
40
42
|
readonly migrationDrift: {
|
package/src/docker/compose.ts
CHANGED
|
@@ -250,6 +250,11 @@ export function buildStackEnv(
|
|
|
250
250
|
// Token is minted by the bootstrap — never a generated password here.
|
|
251
251
|
env[`${prefix}_URL`] = url;
|
|
252
252
|
env.OKE_VAULT_URL = url;
|
|
253
|
+
} else if (spec.role === "store.index") {
|
|
254
|
+
// Meilisearch: standalone HTTP URL + the generated master key.
|
|
255
|
+
env[`${prefix}_URL`] = url;
|
|
256
|
+
env.OKE_STORE_INDEX_URL = url;
|
|
257
|
+
env.OKE_STORE_INDEX_KEY = spec.credentials.password;
|
|
253
258
|
} else {
|
|
254
259
|
env[`${prefix}_USER`] = spec.credentials.user;
|
|
255
260
|
env[`${prefix}_PASSWORD`] = spec.credentials.password;
|
|
@@ -43,6 +43,29 @@ describe("image recipes", () => {
|
|
|
43
43
|
expect(redis.match("redis:7")).toBe(true);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
+
test("meilisearch matches the official image and emits a http URL", () => {
|
|
47
|
+
expect(recipeFor("getmeili/meilisearch:v1.37").id).toBe("meilisearch");
|
|
48
|
+
const spec: ServiceSpec = {
|
|
49
|
+
role: "store.index",
|
|
50
|
+
serviceName: "store-index",
|
|
51
|
+
image: "getmeili/meilisearch:v1.37",
|
|
52
|
+
port: 7700,
|
|
53
|
+
hostPort: 7700,
|
|
54
|
+
credentials: { user: "oke", password: "meili-master-key", database: "oke" },
|
|
55
|
+
};
|
|
56
|
+
const applied = recipeFor(spec.image).apply(spec);
|
|
57
|
+
expect(applied.environment?.MEILI_MASTER_KEY).toBe("${OKE_STORE_INDEX_KEY}");
|
|
58
|
+
expect(applied.volumes).toContain("store-index-data:/meili_data");
|
|
59
|
+
const url = recipeFor(spec.image).url(spec, {
|
|
60
|
+
host: "127.0.0.1",
|
|
61
|
+
port: 7700,
|
|
62
|
+
user: "oke",
|
|
63
|
+
password: "meili-master-key",
|
|
64
|
+
database: "oke",
|
|
65
|
+
});
|
|
66
|
+
expect(url).toBe("http://127.0.0.1:7700");
|
|
67
|
+
});
|
|
68
|
+
|
|
46
69
|
test("a new image recipe is ≤15 lines", async () => {
|
|
47
70
|
const src = await Bun.file(`${import.meta.dir}/recipes/postgres.ts`).text();
|
|
48
71
|
const exportLines = src
|
|
@@ -197,6 +220,24 @@ describe("deriveInfrastructure", () => {
|
|
|
197
220
|
expect(formatStackEnv(result.stackEnv)).toContain("OKE_STORE_SQL_PASSWORD=");
|
|
198
221
|
});
|
|
199
222
|
|
|
223
|
+
test("store.index meilisearch emits its own URL + master key env", () => {
|
|
224
|
+
const result = deriveInfrastructure({
|
|
225
|
+
images: { "store.index": "getmeili/meilisearch:v1.37" },
|
|
226
|
+
credentials: {
|
|
227
|
+
"store.index": { user: "oke", password: "meili-master-key", database: "oke" },
|
|
228
|
+
},
|
|
229
|
+
app: "skyport",
|
|
230
|
+
});
|
|
231
|
+
const yml = result.files.find((f) => f.path === "compose.store.index.yml")!.content;
|
|
232
|
+
expect(yml).toContain("getmeili/meilisearch:v1.37");
|
|
233
|
+
expect(yml).toContain("${OKE_STORE_INDEX_KEY}");
|
|
234
|
+
expect(yml).toContain("meili_data");
|
|
235
|
+
expect(yml).not.toContain("meili-master-key");
|
|
236
|
+
expect(result.stackEnv.OKE_STORE_INDEX_URL).toBe("http://127.0.0.1:7700");
|
|
237
|
+
expect(result.stackEnv.OKE_STORE_INDEX_KEY).toBe("meili-master-key");
|
|
238
|
+
expect(result.stackEnv.DATABASE_URL).toBeUndefined();
|
|
239
|
+
});
|
|
240
|
+
|
|
200
241
|
test("emits protocol-specific env keys plus optional control notes", () => {
|
|
201
242
|
const result = deriveInfrastructure({
|
|
202
243
|
images: {
|
|
@@ -4,15 +4,23 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ImageRecipe } from "../types.ts";
|
|
6
6
|
import { mailpit } from "./mailpit.ts";
|
|
7
|
+
import { meilisearch } from "./meilisearch.ts";
|
|
7
8
|
import { openbao } from "./openbao.ts";
|
|
8
9
|
import { postgres } from "./postgres.ts";
|
|
9
10
|
import { redis } from "./redis.ts";
|
|
10
11
|
import { rustfs } from "./rustfs.ts";
|
|
11
12
|
|
|
12
13
|
/** Default recipe catalogue. */
|
|
13
|
-
export const builtinRecipes: readonly ImageRecipe[] = [
|
|
14
|
+
export const builtinRecipes: readonly ImageRecipe[] = [
|
|
15
|
+
postgres,
|
|
16
|
+
redis,
|
|
17
|
+
mailpit,
|
|
18
|
+
rustfs,
|
|
19
|
+
openbao,
|
|
20
|
+
meilisearch,
|
|
21
|
+
];
|
|
14
22
|
|
|
15
|
-
export { mailpit, openbao, postgres, redis, rustfs };
|
|
23
|
+
export { mailpit, meilisearch, openbao, postgres, redis, rustfs };
|
|
16
24
|
|
|
17
25
|
/**
|
|
18
26
|
* Resolve the recipe for an image reference.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meilisearch image recipe — full-text search service (`getmeili/meilisearch`).
|
|
3
|
+
*
|
|
4
|
+
* Data lives on a named volume under `/meili_data`; the master key is injected
|
|
5
|
+
* via `${VAR}` (never cleartext in YAML). The official image is Alpine-based
|
|
6
|
+
* and musl-clean — the glibc binary gap only affects raw host installs.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ImageRecipe } from "../types.ts";
|
|
10
|
+
|
|
11
|
+
/** Meilisearch FTS service. API on 7700. */
|
|
12
|
+
export const meilisearch: ImageRecipe = {
|
|
13
|
+
id: "meilisearch",
|
|
14
|
+
port: 7700,
|
|
15
|
+
match: (i) => /meilisearch|getmeili/i.test(i),
|
|
16
|
+
apply: (s) => ({
|
|
17
|
+
environment: {
|
|
18
|
+
MEILI_MASTER_KEY: "${OKE_STORE_INDEX_KEY}",
|
|
19
|
+
MEILI_ENV: "${OKE_MEILI_ENV:-production}",
|
|
20
|
+
MEILI_NO_ANALYTICS: "true",
|
|
21
|
+
},
|
|
22
|
+
volumes: [`${s.serviceName}-data:/meili_data`],
|
|
23
|
+
healthcheck: {
|
|
24
|
+
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:7700/health || exit 1"],
|
|
25
|
+
interval: "5s",
|
|
26
|
+
timeout: "3s",
|
|
27
|
+
retries: 12,
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
url: (_s, c) => `http://${c.host}:${c.port}`,
|
|
31
|
+
};
|
|
@@ -9,9 +9,14 @@ import {
|
|
|
9
9
|
runIndexConformance,
|
|
10
10
|
runKvConformance,
|
|
11
11
|
runSqlConformance,
|
|
12
|
+
runTextIndexConformance,
|
|
12
13
|
} from "./conformance.ts";
|
|
13
14
|
import { fsDriver } from "./fs.ts";
|
|
15
|
+
import { libsqlDriver, libsqlIndexDriver } from "./libsql.ts";
|
|
14
16
|
import { memoryFilesDriver, memoryIndexDriver, memoryKvDriver, memorySqlDriver } from "./memory.ts";
|
|
17
|
+
import { meilisearchDriver } from "./meilisearch.ts";
|
|
18
|
+
import { createMeilisearchFakeFetch } from "./meilisearch.test.ts";
|
|
19
|
+
import { pgliteDriver } from "./pglite.ts";
|
|
15
20
|
import { pgvectorDriver } from "./pgvector.ts";
|
|
16
21
|
import { createPostgresFakeClient, postgresDriver } from "./postgres.ts";
|
|
17
22
|
import { createRedisFakeClient, redisDriver } from "./redis.ts";
|
|
@@ -21,6 +26,9 @@ import { sqliteDriver } from "./sqlite.ts";
|
|
|
21
26
|
describe("sql conformance", () => {
|
|
22
27
|
test("memory", () => runSqlConformance(memorySqlDriver));
|
|
23
28
|
test("sqlite", () => runSqlConformance(sqliteDriver, { url: ":memory:" }));
|
|
29
|
+
test("libsql", () => runSqlConformance(libsqlDriver, { url: ":memory:" }));
|
|
30
|
+
// pglite cold-starts WASM + extension load — slow disks / CI need > default 5s
|
|
31
|
+
test("pglite", () => runSqlConformance(pgliteDriver, { url: "memory://" }), 15_000);
|
|
24
32
|
test("postgres (fake Bun.SQL client)", () =>
|
|
25
33
|
runSqlConformance(postgresDriver, {
|
|
26
34
|
client: createPostgresFakeClient(),
|
|
@@ -46,6 +54,16 @@ describe("files conformance", () => {
|
|
|
46
54
|
describe("index conformance", () => {
|
|
47
55
|
test("memory", () => runIndexConformance(memoryIndexDriver, { dims: 3 }));
|
|
48
56
|
test("pgvector", () => runIndexConformance(pgvectorDriver, { dims: 3 }));
|
|
57
|
+
test("libsql", () => runIndexConformance(libsqlIndexDriver, { dims: 3 }));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("text index conformance", () => {
|
|
61
|
+
test("meilisearch (injected fetch)", () =>
|
|
62
|
+
runTextIndexConformance(meilisearchDriver, {
|
|
63
|
+
url: "http://127.0.0.1:7700",
|
|
64
|
+
apiKey: "master-key",
|
|
65
|
+
fetch: createMeilisearchFakeFetch(),
|
|
66
|
+
}));
|
|
49
67
|
});
|
|
50
68
|
|
|
51
69
|
describe("protocol naming", () => {
|
|
@@ -53,6 +71,8 @@ describe("protocol naming", () => {
|
|
|
53
71
|
const ids = [
|
|
54
72
|
memorySqlDriver.id,
|
|
55
73
|
sqliteDriver.id,
|
|
74
|
+
libsqlDriver.id,
|
|
75
|
+
pgliteDriver.id,
|
|
56
76
|
postgresDriver.id,
|
|
57
77
|
memoryKvDriver.id,
|
|
58
78
|
redisDriver.id,
|
|
@@ -61,10 +81,14 @@ describe("protocol naming", () => {
|
|
|
61
81
|
s3Driver.id,
|
|
62
82
|
memoryIndexDriver.id,
|
|
63
83
|
pgvectorDriver.id,
|
|
84
|
+
libsqlIndexDriver.id,
|
|
85
|
+
meilisearchDriver.id,
|
|
64
86
|
];
|
|
65
87
|
expect(ids).toEqual([
|
|
66
88
|
"memory",
|
|
67
89
|
"sqlite",
|
|
90
|
+
"libsql",
|
|
91
|
+
"pglite",
|
|
68
92
|
"postgres",
|
|
69
93
|
"memory",
|
|
70
94
|
"redis",
|
|
@@ -73,6 +97,8 @@ describe("protocol naming", () => {
|
|
|
73
97
|
"s3",
|
|
74
98
|
"memory",
|
|
75
99
|
"pgvector",
|
|
100
|
+
"libsql",
|
|
101
|
+
"meilisearch",
|
|
76
102
|
]);
|
|
77
103
|
for (const id of ids) {
|
|
78
104
|
expect(id).not.toMatch(/neon|dragonfly|minio|upstash|cloudflare/i);
|
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
import { expect } from "bun:test";
|
|
9
9
|
import { createSqlStoreHandle } from "../elements/store/sql-session.ts";
|
|
10
10
|
import { defineTable } from "../elements/store/table.ts";
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
FilesDriver,
|
|
13
|
+
KvDriver,
|
|
14
|
+
SqlDriver,
|
|
15
|
+
SqlConnectOptions,
|
|
16
|
+
TextIndexDriver,
|
|
17
|
+
VectorIndexDriver,
|
|
18
|
+
} from "./types.ts";
|
|
12
19
|
|
|
13
20
|
/** SQL conformance against one driver. */
|
|
14
21
|
export async function runSqlConformance(
|
|
@@ -118,9 +125,9 @@ export async function runFilesConformance(
|
|
|
118
125
|
}
|
|
119
126
|
}
|
|
120
127
|
|
|
121
|
-
/**
|
|
128
|
+
/** Vector index conformance against one driver. */
|
|
122
129
|
export async function runIndexConformance(
|
|
123
|
-
driver:
|
|
130
|
+
driver: VectorIndexDriver,
|
|
124
131
|
openOpts: {
|
|
125
132
|
name?: string;
|
|
126
133
|
dims?: number;
|
|
@@ -147,3 +154,33 @@ export async function runIndexConformance(
|
|
|
147
154
|
await index.close();
|
|
148
155
|
}
|
|
149
156
|
}
|
|
157
|
+
|
|
158
|
+
/** Full-text index conformance against one driver. */
|
|
159
|
+
export async function runTextIndexConformance(
|
|
160
|
+
driver: TextIndexDriver,
|
|
161
|
+
openOpts: {
|
|
162
|
+
name?: string;
|
|
163
|
+
url?: string;
|
|
164
|
+
apiKey?: string;
|
|
165
|
+
fetch?: typeof fetch;
|
|
166
|
+
} = {},
|
|
167
|
+
): Promise<void> {
|
|
168
|
+
const index = await driver.open({
|
|
169
|
+
name: openOpts.name ?? "conf-text",
|
|
170
|
+
dims: 0,
|
|
171
|
+
url: openOpts.url,
|
|
172
|
+
apiKey: openOpts.apiKey,
|
|
173
|
+
fetch: openOpts.fetch,
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
await index.upsert("d1", { id: "d1", title: "hello world" });
|
|
177
|
+
await index.upsert("d2", { id: "d2", title: "goodbye world" });
|
|
178
|
+
const found = await index.search("hello", { topK: 1 });
|
|
179
|
+
expect(found.hits.length).toBeGreaterThan(0);
|
|
180
|
+
expect(found.hits[0]?.id).toBe("d1");
|
|
181
|
+
expect(await index.delete("d1")).toBe(true);
|
|
182
|
+
expect(index.driverId).toBe(driver.id);
|
|
183
|
+
} finally {
|
|
184
|
+
await index.close();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -10,11 +10,15 @@ describe("SQL_DRIVER_TO_DRIZZLE_DIALECT", () => {
|
|
|
10
10
|
expect(SQL_DRIVER_TO_DRIZZLE_DIALECT).toEqual({
|
|
11
11
|
sqlite: "sqlite",
|
|
12
12
|
postgres: "postgresql",
|
|
13
|
+
libsql: "sqlite",
|
|
14
|
+
pglite: "postgresql",
|
|
13
15
|
});
|
|
14
16
|
});
|
|
15
17
|
|
|
16
18
|
test("drizzleDialectFromSqlDriver resolves", () => {
|
|
17
19
|
expect(drizzleDialectFromSqlDriver("sqlite")).toBe("sqlite");
|
|
18
20
|
expect(drizzleDialectFromSqlDriver("postgres")).toBe("postgresql");
|
|
21
|
+
expect(drizzleDialectFromSqlDriver("libsql")).toBe("sqlite");
|
|
22
|
+
expect(drizzleDialectFromSqlDriver("pglite")).toBe("postgresql");
|
|
19
23
|
});
|
|
20
24
|
});
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* drizzle-kit `1.0.0-rc.4` dialects (from its schema validator):
|
|
5
5
|
* `postgresql` · `mysql` · `sqlite` · `turso` · `singlestore` · `mssql` ·
|
|
6
6
|
* `cockroach` · `duckdb`. OKE owns kit-facing SQL drivers `sqlite` /
|
|
7
|
-
* `postgres` only — map those, never infer from
|
|
7
|
+
* `postgres` / `libsql` / `pglite` only — map those, never infer from
|
|
8
|
+
* connection URLs. `libsql` speaks the sqlite wire dialect; `pglite` speaks
|
|
9
|
+
* postgresql (same dialect as `postgres`, different transport).
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
import type { StoreDriverId } from "./types.ts";
|
|
@@ -18,20 +20,22 @@ export type OkeDrizzleKitDialect = "sqlite" | "postgresql";
|
|
|
18
20
|
* dialect months later.
|
|
19
21
|
*/
|
|
20
22
|
export const SQL_DRIVER_TO_DRIZZLE_DIALECT: Record<
|
|
21
|
-
Extract<StoreDriverId, "sqlite" | "postgres">,
|
|
23
|
+
Extract<StoreDriverId, "sqlite" | "postgres" | "libsql" | "pglite">,
|
|
22
24
|
OkeDrizzleKitDialect
|
|
23
25
|
> = {
|
|
24
26
|
sqlite: "sqlite",
|
|
25
27
|
postgres: "postgresql",
|
|
28
|
+
libsql: "sqlite",
|
|
29
|
+
pglite: "postgresql",
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* Resolve the drizzle-kit dialect for an OKE SQL driver id.
|
|
30
34
|
*
|
|
31
|
-
* @param driverId - Protocol driver id (`sqlite` | `postgres`)
|
|
35
|
+
* @param driverId - Protocol driver id (`sqlite` | `postgres` | `libsql` | `pglite`)
|
|
32
36
|
*/
|
|
33
37
|
export function drizzleDialectFromSqlDriver(
|
|
34
|
-
driverId: Extract<StoreDriverId, "sqlite" | "postgres">,
|
|
38
|
+
driverId: Extract<StoreDriverId, "sqlite" | "postgres" | "libsql" | "pglite">,
|
|
35
39
|
): OkeDrizzleKitDialect {
|
|
36
40
|
return SQL_DRIVER_TO_DRIZZLE_DIALECT[driverId];
|
|
37
41
|
}
|
package/src/drivers/index.ts
CHANGED
|
@@ -23,12 +23,18 @@ export type {
|
|
|
23
23
|
FilesDriver,
|
|
24
24
|
IndexHit,
|
|
25
25
|
IndexStore,
|
|
26
|
+
VectorIndexStore,
|
|
27
|
+
TextIndexStore,
|
|
28
|
+
TextIndexSearchOptions,
|
|
29
|
+
TextIndexSearchResult,
|
|
26
30
|
IndexOpenOptions,
|
|
27
31
|
IndexDriver,
|
|
32
|
+
VectorIndexDriver,
|
|
33
|
+
TextIndexDriver,
|
|
28
34
|
StoreDriver,
|
|
29
35
|
ClassificationMap,
|
|
30
36
|
} from "./types.ts";
|
|
31
|
-
export { classificationKey } from "./types.ts";
|
|
37
|
+
export { classificationKey, indexDriverNeedsSql } from "./types.ts";
|
|
32
38
|
|
|
33
39
|
export type {
|
|
34
40
|
SignalDriverId,
|
|
@@ -77,6 +83,17 @@ export { s3Driver, openS3Bucket, createS3FakeClient } from "./s3.ts";
|
|
|
77
83
|
|
|
78
84
|
export { pgvectorDriver, openPgvectorIndex } from "./pgvector.ts";
|
|
79
85
|
|
|
86
|
+
export { libsqlDriver, connectLibsql, libsqlIndexDriver, openLibsqlIndex } from "./libsql.ts";
|
|
87
|
+
|
|
88
|
+
export {
|
|
89
|
+
meilisearchDriver,
|
|
90
|
+
openMeilisearchIndex,
|
|
91
|
+
MeilisearchUnavailableError,
|
|
92
|
+
type MeilisearchIndexOptions,
|
|
93
|
+
} from "./meilisearch.ts";
|
|
94
|
+
|
|
95
|
+
export { pgliteDriver, connectPglite } from "./pglite.ts";
|
|
96
|
+
|
|
80
97
|
export { memorySignalDriver, openMemorySignal } from "./signal-memory.ts";
|
|
81
98
|
|
|
82
99
|
export {
|
|
@@ -103,7 +120,6 @@ export type { VaultDriverId, VaultOpenOptions, VaultBag, VaultDriver } from "./v
|
|
|
103
120
|
export { memoryVaultDriver } from "./vault-memory.ts";
|
|
104
121
|
export { envVaultDriver } from "./vault-env.ts";
|
|
105
122
|
export { openbaoVaultDriver, OpenBaoUnavailableError } from "./vault-openbao.ts";
|
|
106
|
-
export { infisicalVaultDriver } from "./vault-infisical.ts";
|
|
107
123
|
export { managedVaultDriver } from "./vault-managed.ts";
|
|
108
124
|
|
|
109
125
|
export type {
|