okengine 0.13.0 → 0.15.2
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/manifest.v1.schema.json +7 -1
- package/package.json +4 -5
- package/site/content/docs/ai/mcp.mdx +27 -2
- package/site/content/docs/elements/ai.mdx +59 -11
- package/site/content/docs/elements/channel.mdx +1 -0
- package/site/content/docs/elements/clock.mdx +30 -12
- package/site/content/docs/elements/flow.mdx +9 -3
- package/site/content/docs/elements/gate.mdx +25 -22
- package/site/content/docs/elements/signal.mdx +71 -25
- package/site/content/docs/elements/store.mdx +87 -28
- package/site/content/docs/elements/vault.mdx +1 -0
- package/site/content/docs/get-started/basic-usage.mdx +22 -13
- package/site/content/docs/get-started/index.mdx +5 -0
- package/site/content/docs/get-started/installation.mdx +2 -2
- package/site/content/docs/get-started/introduction.mdx +11 -3
- package/site/content/docs/get-started/meta.json +1 -1
- package/site/content/docs/get-started/project-structure.mdx +932 -0
- package/site/content/docs/reference/cli.md +13 -10
- package/site/content/docs/reference/client.mdx +25 -21
- package/site/content/docs/reference/fx.mdx +27 -22
- package/site/content/docs/reference/security.md +1 -1
- package/src/auth/bindings.ts +14 -5
- package/src/auth/cross-plane.ts +10 -3
- package/src/cli/ai-setup/ai-setup.test.ts +62 -0
- package/src/cli/ai-setup/apply.ts +32 -1
- package/src/cli/ai-setup/recommend.test.ts +25 -0
- package/src/cli/ai-setup/recommend.ts +8 -3
- package/src/cli/attach-host-console.test.ts +3 -2
- package/src/cli/attach-host-console.ts +3 -0
- package/src/cli/build.test.ts +4 -2
- package/src/cli/db-seed.ts +48 -15
- package/src/cli/db.test.ts +104 -0
- package/src/cli/db.ts +122 -10
- package/src/cli/dev-controls.test.ts +20 -0
- package/src/cli/dev-controls.ts +13 -0
- package/src/cli/dev.test.ts +15 -4
- package/src/cli/dev.ts +102 -29
- package/src/cli/ensure-drizzle-config.ts +2 -1
- package/src/cli/tui/DevLive.tsx +12 -2
- package/src/cli/tui/keys.test.ts +2 -1
- package/src/cli/tui/keys.ts +3 -2
- package/src/compiler/aot.test.ts +1 -1
- package/src/compiler/effects-infer.ts +58 -3
- package/src/compiler/extract.test.ts +458 -29
- package/src/compiler/extract.ts +387 -69
- package/src/compiler/flow-path.test.ts +96 -0
- package/src/compiler/flow-path.ts +173 -0
- package/src/compiler/generate-adopt.test.ts +112 -3
- package/src/compiler/generate-adopt.ts +280 -26
- package/src/compiler/response.ts +45 -1
- package/src/compiler/schema-from-ast.ts +609 -0
- package/src/console/server/ai.ts +5 -2
- package/src/console/server/bind.ts +2 -2
- package/src/console/server/console.test.ts +3 -0
- package/src/console/server/flows.ts +121 -40
- package/src/console/server/invoke-user-flow.test.ts +3 -1
- package/src/console/server/invoke-user-flow.ts +17 -2
- package/src/console/server/iso-at.test.ts +9 -0
- package/src/console/server/iso-at.ts +11 -0
- package/src/console/server/security-headers.ts +6 -3
- package/src/console/server/serve.ts +17 -2
- package/src/console/server/spa-proxy.test.ts +1 -0
- package/src/console/server/sql-catalog.ts +147 -7
- package/src/console/server/sql-rls.test.ts +16 -0
- package/src/console/server/state.ts +8 -0
- package/src/console/server/store.test.ts +7 -4
- package/src/console/server/store.ts +142 -58
- package/src/console/ui-next/dist/assets/agent-disclosure-C0X1fbWF.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-F1FI122b.js +1 -0
- package/src/console/ui-next/dist/assets/{call-pii-button-bqkxMrJH.js → call-pii-button-DEDCl_j3.js} +1 -1
- package/src/console/ui-next/dist/assets/collapsible-LPqGvfoz.js +1 -0
- package/src/console/ui-next/dist/assets/{confirm-sheet-DDCRmG62.js → confirm-sheet-3ptDzXbz.js} +1 -1
- package/src/console/ui-next/dist/assets/{duration-tone-oiRxPVsZ.js → duration-tone-sC3lGABz.js} +1 -1
- package/src/console/ui-next/dist/assets/{explorer-empty-HjTnVQoR.js → explorer-empty-BvYrygyO.js} +1 -1
- package/src/console/ui-next/dist/assets/flows-page-Dluo1Bd7.js +1 -0
- package/src/console/ui-next/dist/assets/{highlighted-json-CvDPvveV.js → highlighted-json-CS_O8L-r.js} +1 -1
- package/src/console/ui-next/dist/assets/http-method--sWDdXSB.js +1 -0
- package/src/console/ui-next/dist/assets/index-Ca3HZMVq.js +66 -0
- package/src/console/ui-next/dist/assets/index-UtTDRQpS.css +2 -0
- package/src/console/ui-next/dist/assets/{link-DF7SZ9Ek.js → link-COeyggt-.js} +1 -1
- package/src/console/ui-next/dist/assets/observability-page-HK9-BO8z.js +4 -0
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +1 -0
- package/src/console/ui-next/dist/assets/replica-lag-DBIFFf7d.js +18 -0
- package/src/console/ui-next/dist/assets/sheet-form-Dnwa5oOR.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-CoqwEIi0.js +1 -0
- package/src/console/ui-next/dist/assets/skeleton-BHcfDYcb.js +1 -0
- package/src/console/ui-next/dist/assets/store-page-BSohH3wM.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CFIGRnnA.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BgLl34w7.js +54 -0
- package/src/console/ui-next/dist/assets/units-page-B0cFE76A.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-Cl79j_ku.js → use-vault-list-BLbZhzyF.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-B1SbYe10.js +2 -0
- package/src/console/ui-next/dist/index.html +6 -6
- package/src/console/ui-next/seed-invoke-host.ts +2 -0
- package/src/console/ui-next/src/client.ts +35 -7
- package/src/console/ui-next/src/components/motion/table/index.tsx +16 -0
- package/src/console/ui-next/src/components/motion/table/types.ts +4 -0
- package/src/console/ui-next/src/components/ui/kbd.tsx +2 -2
- package/src/console/ui-next/src/features/flows/graph/build-flow-graph.test.ts +18 -0
- package/src/console/ui-next/src/features/flows/graph/build-flow-graph.ts +14 -1
- package/src/console/ui-next/src/features/flows/graph/neighborhood.test.ts +17 -0
- package/src/console/ui-next/src/features/flows/graph/neighborhood.ts +16 -3
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +3 -1
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/http-method.ts +19 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +9 -3
- package/src/console/ui-next/src/features/flows/traces/trace-detail.test.ts +29 -2
- package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +10 -3
- package/src/console/ui-next/src/features/observability/lib/ask-count.test.ts +25 -0
- package/src/console/ui-next/src/features/observability/lib/ask-count.ts +4 -1
- package/src/console/ui-next/src/features/store/detail/browse-section.tsx +45 -1
- package/src/console/ui-next/src/features/store/detail/resource-panel.tsx +78 -16
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +155 -14
- package/src/console/ui-next/src/features/store/explorer/store-tree.tsx +33 -133
- package/src/console/ui-next/src/features/store/files/file-preview.tsx +4 -1
- package/src/console/ui-next/src/features/store/grid/rls-policy-sheet.tsx +326 -165
- package/src/console/ui-next/src/features/store/grid/sql-insert-sheet.tsx +6 -0
- package/src/console/ui-next/src/features/store/grid/store-data-grid.tsx +50 -3
- package/src/console/ui-next/src/features/store/lib/files-meta.test.ts +3 -0
- package/src/console/ui-next/src/features/store/lib/files-meta.ts +12 -0
- package/src/console/ui-next/src/features/store/lib/query-defaults.test.ts +25 -0
- package/src/console/ui-next/src/features/store/lib/query-defaults.ts +85 -3
- package/src/console/ui-next/src/features/store/lib/query-gate.ts +30 -4
- package/src/console/ui-next/src/features/store/lib/rls-policy.test.ts +139 -0
- package/src/console/ui-next/src/features/store/lib/rls-policy.ts +223 -21
- package/src/console/ui-next/src/features/store/lib/schema-graph.ts +4 -0
- package/src/console/ui-next/src/features/store/lib/sql-catalog.test.ts +24 -0
- package/src/console/ui-next/src/features/store/lib/sql-catalog.ts +19 -0
- package/src/console/ui-next/src/features/store/lib/store-tree.test.ts +6 -0
- package/src/console/ui-next/src/features/store/lib/store-tree.ts +13 -0
- package/src/console/ui-next/src/features/store/query/query-console.tsx +48 -14
- package/src/console/ui-next/src/features/store/query/query-gate-menu.tsx +19 -20
- package/src/console/ui-next/src/features/store/query/query-gate-parts.tsx +2 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +110 -83
- package/src/console/ui-next/src/features/store/schema/schema-table-node.tsx +17 -0
- package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +112 -72
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +12 -4
- package/src/console/ui-next/src/features/units/lib/contract-input.test.ts +206 -1
- package/src/console/ui-next/src/features/units/lib/contract-input.ts +55 -0
- package/src/console/ui-next/src/features/vault/lib/types.ts +1 -1
- package/src/docker/compose-health.test.ts +27 -0
- package/src/docker/compose-health.ts +19 -3
- package/src/docker/docker.test.ts +4 -1
- package/src/docker/dockerfile.ts +1 -1
- package/src/docker/recipes/pgdog.ts +2 -0
- package/src/drivers/ai-anthropic.ts +5 -0
- package/src/drivers/ai-ollama.ts +49 -30
- package/src/drivers/ai-openai-compatible.ts +57 -46
- package/src/drivers/ai-providers.test.ts +3 -0
- package/src/drivers/bun-native-completeness.test.ts +7 -9
- package/src/drivers/clock-postgres.ts +13 -9
- package/src/drivers/instances-postgres.ts +4 -6
- package/src/drivers/journal-postgres.ts +13 -9
- package/src/drivers/pg-rls.test.ts +87 -0
- package/src/drivers/pg-rls.ts +233 -7
- package/src/drivers/pglite.ts +26 -3
- package/src/drivers/postgres.test.ts +23 -0
- package/src/drivers/postgres.ts +133 -9
- package/src/drivers/redis.ts +11 -4
- package/src/drivers/signal-redis.ts +24 -14
- package/src/drivers/signal-types.ts +2 -1
- package/src/drivers/types.ts +10 -0
- package/src/elements/ai/declare.ts +109 -0
- package/src/elements/ai/errors.test.ts +5 -1
- package/src/elements/ai/errors.ts +30 -2
- package/src/elements/ai/eval.ts +4 -6
- package/src/elements/ai/mcp-client.test.ts +206 -0
- package/src/elements/ai/mcp-client.ts +362 -0
- package/src/elements/ai/mcp-http.ts +159 -0
- package/src/elements/ai/mcp-mock.ts +134 -0
- package/src/elements/ai/mcp-protocol.ts +234 -0
- package/src/elements/ai/mcp-stdio.test.ts +50 -0
- package/src/elements/ai/mcp-stdio.ts +212 -0
- package/src/elements/ai/mcp-transport.ts +70 -0
- package/src/elements/ai/runtime.ts +159 -29
- package/src/elements/ai.test.ts +139 -0
- package/src/elements/ai.ts +16 -0
- package/src/elements/clock/declare.ts +26 -1
- package/src/elements/clock/health.test.ts +43 -0
- package/src/elements/clock/runtime.ts +55 -2
- package/src/elements/clock/schedule.ts +71 -142
- package/src/elements/clock.test.ts +9 -40
- package/src/elements/clock.ts +6 -1
- package/src/elements/gate/boot.ts +5 -5
- package/src/elements/gate/declare.ts +36 -4
- package/src/elements/gate/flatten.ts +1 -1
- package/src/elements/gate/runtime.ts +1 -1
- package/src/elements/index.ts +2 -0
- package/src/elements/signal/declare.ts +2 -1
- package/src/elements/signal/runtime.ts +16 -1
- package/src/elements/signal.ts +1 -0
- package/src/elements/store/cache.test.ts +2 -0
- package/src/elements/store/cache.ts +3 -3
- package/src/elements/store/declare.ts +9 -6
- package/src/elements/store/emit-drizzle.ts +44 -8
- package/src/elements/store/resource.test.ts +1 -1
- package/src/elements/store/rls-identity.test.ts +95 -0
- package/src/elements/store/rls-identity.ts +116 -0
- package/src/elements/store/runtime.ts +4 -0
- package/src/elements/store/schema-decl.test.ts +37 -0
- package/src/elements/store/schema-decl.ts +161 -0
- package/src/elements/store/seed.ts +1 -1
- package/src/elements/store/sql-condition.test.ts +12 -0
- package/src/elements/store/sql-condition.ts +26 -2
- package/src/elements/store/sql-rls-isolation.test.ts +165 -0
- package/src/elements/store/sql-rls-stamp.test.ts +117 -0
- package/src/elements/store/sql-session.ts +81 -3
- package/src/elements/store/upsert-app.test.ts +1 -1
- package/src/elements/store.ts +14 -0
- package/src/elements/vault/builtin-adapter.ts +17 -0
- package/src/full.ts +2 -0
- package/src/http.ts +20 -3
- package/src/index.ts +14 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +1 -1
- package/src/kernel/adopt-routes.ts +30 -2
- package/src/kernel/app.ts +227 -77
- package/src/kernel/auto-cache.test.ts +8 -8
- package/src/kernel/auto-registry.test.ts +54 -9
- package/src/kernel/boot-bind/ai.ts +24 -0
- package/src/kernel/boot-bind/clock.ts +2 -0
- package/src/kernel/boot.test.ts +4 -4
- package/src/kernel/boot.ts +5 -3
- package/src/kernel/effects-stamping.test.ts +3 -3
- package/src/kernel/element-registries.ts +15 -5
- package/src/kernel/errors.ts +24 -0
- package/src/kernel/flow-units.ts +64 -0
- package/src/kernel/flow.ts +29 -17
- package/src/kernel/fx-dead-letters.test.ts +77 -0
- package/src/kernel/fx.test.ts +22 -0
- package/src/kernel/fx.ts +135 -6
- package/src/kernel/horizontal-child.ts +4 -4
- package/src/kernel/http-path-pending.ts +20 -0
- package/src/kernel/http-resource.ts +4 -0
- package/src/kernel/http-stream.test.ts +174 -0
- package/src/kernel/index.ts +2 -0
- package/src/kernel/pipeline.test.ts +2 -2
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/plugin-needs.test.ts +1 -1
- package/src/kernel/ready.test.ts +2 -2
- package/src/kernel/resource-mount.test.ts +14 -0
- package/src/kernel/run-duration.test.ts +2 -2
- package/src/kernel/stamp-http.test.ts +79 -0
- package/src/kernel/stamp-http.ts +75 -0
- package/src/kernel/triggers.ts +52 -27
- package/src/manifest/mcp-ref.ts +88 -0
- package/src/manifest/types.ts +41 -2
- package/src/manifest/validate.test.ts +20 -0
- package/src/mcp/docs-server.ts +1 -1
- package/src/mcp/server.ts +1 -1
- package/src/plugins/compression.test.ts +21 -0
- package/src/plugins/compression.ts +1 -0
- package/src/release/measure.ts +2 -2
- package/src/runtime/bun.ts +41 -4
- package/src/runtime/json-code-block.test.ts +2 -2
- package/src/runtime/serve.test.ts +4 -4
- package/src/term.test.ts +52 -4
- package/src/term.ts +125 -17
- package/src/test/reset-element-registries.ts +10 -3
- package/src/cli/ask-seed.test.ts +0 -96
- package/src/cli/ask-seed.ts +0 -82
- package/src/console/ui-next/dist/assets/cache-glyph-CLPBqZeb.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DYb0xU8C.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-Dg8CTE29.js +0 -1
- package/src/console/ui-next/dist/assets/http-method-BJ92Z_ke.js +0 -1
- package/src/console/ui-next/dist/assets/index-Bp-R7jtM.js +0 -66
- package/src/console/ui-next/dist/assets/index-D4Ldtj79.css +0 -2
- package/src/console/ui-next/dist/assets/observability-page-DAnpEaq1.js +0 -4
- package/src/console/ui-next/dist/assets/query-gate-parts-1m8m1iNp.js +0 -2
- package/src/console/ui-next/dist/assets/react-B1ML8gxg.js +0 -1
- package/src/console/ui-next/dist/assets/replica-lag-C8_BRt2x.js +0 -18
- package/src/console/ui-next/dist/assets/sheet-form-D-ata7jy.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DO4IsVqv.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-CL_X0GCj.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-v3LXdYpr.js +0 -45
- package/src/console/ui-next/dist/assets/trace-detail-sheet-D16lWQMt.js +0 -2
- package/src/console/ui-next/dist/assets/units-page-BtQ0bqMe.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-Ca-MvcmJ.js +0 -2
|
@@ -39,10 +39,20 @@ export type AppFlowRoute<
|
|
|
39
39
|
readonly path?: undefined;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Unit → flow → contract. Leaf is the HTTP / call-only union — do not
|
|
44
|
+
* index with `AppFlowRoute<any, any, any, any, any>` (`any extends string`
|
|
45
|
+
* makes `method`/`path` required and rejects cron / signal flows).
|
|
46
|
+
*/
|
|
43
47
|
export type AppRouteMap = {
|
|
44
48
|
readonly [unit: string]: {
|
|
45
|
-
readonly [flow: string]:
|
|
49
|
+
readonly [flow: string]: {
|
|
50
|
+
readonly in?: unknown;
|
|
51
|
+
readonly out?: unknown;
|
|
52
|
+
readonly errors?: unknown;
|
|
53
|
+
readonly method?: string;
|
|
54
|
+
readonly path?: string;
|
|
55
|
+
};
|
|
46
56
|
};
|
|
47
57
|
};
|
|
48
58
|
|
|
@@ -170,6 +180,7 @@ export function accumulateAdoptArgs(args: readonly unknown[], into: RuntimeRoute
|
|
|
170
180
|
const unitBag = into[unit] ?? (into[unit] = {});
|
|
171
181
|
for (const [flowName, flowDef] of Object.entries(value as Record<string, unknown>)) {
|
|
172
182
|
if (!isFlow(flowDef)) continue;
|
|
183
|
+
stampAdoptedFlow(flowDef, unit, flowName);
|
|
173
184
|
found.push(flowDef);
|
|
174
185
|
unitBag[flowName] = runtimeRouteFromFlow(flowDef);
|
|
175
186
|
}
|
|
@@ -178,3 +189,20 @@ export function accumulateAdoptArgs(args: readonly unknown[], into: RuntimeRoute
|
|
|
178
189
|
|
|
179
190
|
return found;
|
|
180
191
|
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Stamp `unit.export` on nameless flows — same rule as {@link unit}.
|
|
195
|
+
*
|
|
196
|
+
* @param flowDef - Flow to stamp
|
|
197
|
+
* @param unit - Client unit (folder / adopt key)
|
|
198
|
+
* @param exportName - Namespace export
|
|
199
|
+
*/
|
|
200
|
+
function stampAdoptedFlow(flowDef: AnyFlowDef, unit: string, exportName: string): void {
|
|
201
|
+
const f = flowDef as { name: string; unit: string | undefined };
|
|
202
|
+
if (!f.name || f.name.startsWith("flow_")) {
|
|
203
|
+
f.name = `${unit}.${exportName}`;
|
|
204
|
+
}
|
|
205
|
+
if (!f.unit) {
|
|
206
|
+
f.unit = unit;
|
|
207
|
+
}
|
|
208
|
+
}
|
package/src/kernel/app.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
accumulateAdoptArgs,
|
|
15
15
|
type AppRouteMap,
|
|
16
16
|
type RoutesFromAdoptArgs,
|
|
17
|
+
type RoutesFromNamespace,
|
|
17
18
|
type RuntimeRouteMap,
|
|
18
19
|
} from "./adopt-routes.ts";
|
|
19
20
|
// `./boot.ts` pulls in every element + driver module (vault, store, signal,
|
|
@@ -37,10 +38,12 @@ import { runWithLocale } from "../i18n/locale-context.ts";
|
|
|
37
38
|
import { runDurable } from "../elements/clock/durable.ts";
|
|
38
39
|
import { isFlow, type AnyFlowDef } from "./flow.ts";
|
|
39
40
|
import { failureFromUnknown, runCompensationPhase } from "./compensate.ts";
|
|
41
|
+
import { withAbortSignal } from "./abort-scope.ts";
|
|
40
42
|
import { fxRetry } from "./concurrency.ts";
|
|
41
43
|
import {
|
|
42
44
|
createFxContext,
|
|
43
45
|
freezePrincipal,
|
|
46
|
+
isJsonStreamResult,
|
|
44
47
|
resolveName,
|
|
45
48
|
type CreateFxOptions,
|
|
46
49
|
type Fx,
|
|
@@ -57,7 +60,8 @@ import {
|
|
|
57
60
|
} from "../runtime/dev-request-log.ts";
|
|
58
61
|
import { asBrowserJsonCodeBlock, httpNavGroups } from "../runtime/json-code-block.ts";
|
|
59
62
|
import { resolveDurationMs } from "./elapsed.ts";
|
|
60
|
-
import { fail } from "./errors.ts";
|
|
63
|
+
import { fail, throwOke } from "./errors.ts";
|
|
64
|
+
import { consumeRegisteredFlowUnits, type FlowUnitBag } from "./flow-units.ts";
|
|
61
65
|
import {
|
|
62
66
|
isFlowFailure,
|
|
63
67
|
mergeHooks,
|
|
@@ -85,9 +89,12 @@ import { listBindings, resetBindings, type Binding } from "./on.ts";
|
|
|
85
89
|
import {
|
|
86
90
|
aiAgentRegistry,
|
|
87
91
|
aiEmbedRegistry,
|
|
92
|
+
aiMcpServerRegistry,
|
|
88
93
|
aiModelRegistry,
|
|
89
94
|
aiPromptRegistry,
|
|
90
95
|
channelTemplateRegistry,
|
|
96
|
+
clockRegistry,
|
|
97
|
+
gateRegistry,
|
|
91
98
|
requiredEnvRegistry,
|
|
92
99
|
secretRegistry,
|
|
93
100
|
signalRegistry,
|
|
@@ -96,6 +103,7 @@ import {
|
|
|
96
103
|
import {
|
|
97
104
|
applyPrincipal,
|
|
98
105
|
createElementPipelineHooks,
|
|
106
|
+
gateNamesOf,
|
|
99
107
|
type PrincipalBag,
|
|
100
108
|
type ResolvedPrincipal,
|
|
101
109
|
} from "./pipeline.ts";
|
|
@@ -115,6 +123,7 @@ import {
|
|
|
115
123
|
type RouterPreset,
|
|
116
124
|
type SmartRouter,
|
|
117
125
|
} from "./router.ts";
|
|
126
|
+
import { isPendingHttpPath } from "./http-path-pending.ts";
|
|
118
127
|
import type {
|
|
119
128
|
CdcTrigger,
|
|
120
129
|
EveryTrigger,
|
|
@@ -296,6 +305,21 @@ export interface UnitHooks<D extends Record<string, unknown> = {}> {
|
|
|
296
305
|
plug<P extends PluginDef>(pluginDef: P): UnitHooks<AccumulateDecorations<D, P>>;
|
|
297
306
|
}
|
|
298
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Module-augmentation slot filled by `src/flows/generated.ts`.
|
|
310
|
+
* Kernel tests do not import an app generated file, so this stays `{}`.
|
|
311
|
+
*/
|
|
312
|
+
export interface RegisteredFlowUnits {}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* `$routes` derived from {@link RegisteredFlowUnits} after `import generated`.
|
|
316
|
+
*
|
|
317
|
+
* @typeParam U - Augmented unit map
|
|
318
|
+
*/
|
|
319
|
+
export type RoutesFromRegisteredUnits<U = RegisteredFlowUnits> = {
|
|
320
|
+
[K in keyof U]: U[K] extends Record<string, unknown> ? RoutesFromNamespace<U[K]> : never;
|
|
321
|
+
};
|
|
322
|
+
|
|
299
323
|
/**
|
|
300
324
|
* Application instance — adopts flows, routes HTTP, runs the pipeline.
|
|
301
325
|
*
|
|
@@ -432,6 +456,8 @@ export interface OkeApp<D extends Record<string, unknown> = {}, R extends AppRou
|
|
|
432
456
|
* Takes effect only with {@link trustedInvoke}.
|
|
433
457
|
*/
|
|
434
458
|
readonly revealPii?: boolean;
|
|
459
|
+
/** Forced RLS bag (Console / Call API). Operator omit = no stamp. */
|
|
460
|
+
readonly rls?: import("../drivers/pg-rls.ts").RlsIdentity;
|
|
435
461
|
/** Parent WideEvent id when this execution was caused by another. */
|
|
436
462
|
readonly parentId?: string;
|
|
437
463
|
/** Explicit run / WideEvent id (defaults to a new UUID). */
|
|
@@ -531,18 +557,21 @@ function mergeAiOptions(
|
|
|
531
557
|
readonly prompts: NonNullable<BootOptions["ai"]>["prompts"];
|
|
532
558
|
readonly embeds: NonNullable<BootOptions["ai"]>["embeds"];
|
|
533
559
|
readonly agents: NonNullable<BootOptions["ai"]>["agents"];
|
|
560
|
+
readonly mcpServers: NonNullable<BootOptions["ai"]>["mcpServers"];
|
|
534
561
|
},
|
|
535
562
|
): BootOptions["ai"] | undefined {
|
|
536
563
|
const models = mergeUnique(explicit?.models, fromRegistry.models ?? []);
|
|
537
564
|
const prompts = mergeUnique(explicit?.prompts, fromRegistry.prompts ?? []);
|
|
538
565
|
const embeds = mergeUnique(explicit?.embeds, fromRegistry.embeds ?? []);
|
|
539
566
|
const agents = mergeUnique(explicit?.agents, fromRegistry.agents ?? []);
|
|
567
|
+
const mcpServers = mergeUnique(explicit?.mcpServers, fromRegistry.mcpServers ?? []);
|
|
540
568
|
if (
|
|
541
569
|
explicit === undefined &&
|
|
542
570
|
models.length === 0 &&
|
|
543
571
|
prompts.length === 0 &&
|
|
544
572
|
embeds.length === 0 &&
|
|
545
|
-
agents.length === 0
|
|
573
|
+
agents.length === 0 &&
|
|
574
|
+
mcpServers.length === 0
|
|
546
575
|
) {
|
|
547
576
|
return undefined;
|
|
548
577
|
}
|
|
@@ -552,14 +581,61 @@ function mergeAiOptions(
|
|
|
552
581
|
...(prompts.length > 0 ? { prompts } : {}),
|
|
553
582
|
...(embeds.length > 0 ? { embeds } : {}),
|
|
554
583
|
...(agents.length > 0 ? { agents } : {}),
|
|
584
|
+
...(mcpServers.length > 0 ? { mcpServers } : {}),
|
|
555
585
|
};
|
|
556
586
|
}
|
|
557
587
|
|
|
588
|
+
/**
|
|
589
|
+
* Refuse an unresolved path sentinel or a nameless HTTP flow.
|
|
590
|
+
*
|
|
591
|
+
* @param binding - HTTP binding
|
|
592
|
+
*/
|
|
593
|
+
function assertHttpBindingReady(binding: Binding): void {
|
|
594
|
+
const trigger = binding.trigger;
|
|
595
|
+
if (trigger.kind !== "http") return;
|
|
596
|
+
if (isPendingHttpPath(trigger.path)) {
|
|
597
|
+
throwOke("HTTP_PATH_UNRESOLVED", {
|
|
598
|
+
flow: binding.flow.name || "(unnamed)",
|
|
599
|
+
method: trigger.method,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
if (!binding.flow.name || binding.flow.name.startsWith("flow_")) {
|
|
603
|
+
throwOke("HTTP_FLOW_UNNAMED", {
|
|
604
|
+
method: trigger.method,
|
|
605
|
+
path: trigger.path,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Fold `generated.ts` units into `$routes` and `flowsByName`.
|
|
612
|
+
*
|
|
613
|
+
* @param units - Drained {@link registerFlowUnits} bag
|
|
614
|
+
* @param routes - Runtime `$routes`
|
|
615
|
+
* @param registerFlow - App flow index
|
|
616
|
+
*/
|
|
617
|
+
function drainGeneratedUnits(
|
|
618
|
+
units: Record<string, FlowUnitBag>,
|
|
619
|
+
routes: RuntimeRouteMap,
|
|
620
|
+
registerFlow: (flowDef: AnyFlowDef) => void,
|
|
621
|
+
): void {
|
|
622
|
+
if (Object.keys(units).length === 0) return;
|
|
623
|
+
const flows = accumulateAdoptArgs([units], routes);
|
|
624
|
+
for (const flowDef of flows) {
|
|
625
|
+
registerFlow(flowDef);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
558
629
|
/**
|
|
559
630
|
* Create an application. Adopts bindings registered via {@link on}.
|
|
631
|
+
* Drains {@link registerFlowUnits} into `$routes` unless `registry: "ignore"`.
|
|
560
632
|
*
|
|
561
633
|
* @param options - App name and router preset
|
|
562
634
|
*/
|
|
635
|
+
export function oke(
|
|
636
|
+
options: OkeOptions & { readonly registry: "ignore" },
|
|
637
|
+
): OkeApp<Record<string, never>, Record<string, never>>;
|
|
638
|
+
export function oke(options: OkeOptions): OkeApp<{}, RoutesFromRegisteredUnits>;
|
|
563
639
|
export function oke(options: OkeOptions): OkeApp {
|
|
564
640
|
const aot = options.aot !== false;
|
|
565
641
|
const registry = options.registry ?? "consume";
|
|
@@ -569,11 +645,12 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
569
645
|
: [...listBindings(), ...(options.bindings ?? [])];
|
|
570
646
|
if (registry === "consume") resetBindings();
|
|
571
647
|
|
|
572
|
-
// Same registry mode drains store
|
|
573
|
-
// channel.<medium>().template(), and
|
|
574
|
-
// module-evaluation registries
|
|
575
|
-
// (`listBindings`/`resetBindings` above).
|
|
576
|
-
// `
|
|
648
|
+
// Same registry mode drains store.*, vault.secret, signal(), clock(),
|
|
649
|
+
// gate.policy/scope/rate, channel.<medium>().template(), and
|
|
650
|
+
// ai.model/prompt/embed/agent/mcpServer — module-evaluation registries
|
|
651
|
+
// that mirror `on`'s trigger drain (`listBindings`/`resetBindings` above).
|
|
652
|
+
// Explicit `options.stores` / `secrets` / `signals` / `clocks` /
|
|
653
|
+
// `gate.policies` / `channel.templates` / `ai` are additive, never
|
|
577
654
|
// silently ignored — deduped by reference so an explicitly-passed decl
|
|
578
655
|
// that is also in the registry is not doubled.
|
|
579
656
|
const registrySnapshot =
|
|
@@ -583,37 +660,48 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
583
660
|
secrets: [],
|
|
584
661
|
requiredEnv: [],
|
|
585
662
|
signals: [],
|
|
663
|
+
clocks: [],
|
|
664
|
+
gates: [],
|
|
586
665
|
channelTemplates: [],
|
|
587
666
|
aiModels: [],
|
|
588
667
|
aiPrompts: [],
|
|
589
668
|
aiEmbeds: [],
|
|
590
669
|
aiAgents: [],
|
|
670
|
+
aiMcpServers: [],
|
|
591
671
|
}
|
|
592
672
|
: {
|
|
593
673
|
stores: storeRegistry.slice(),
|
|
594
674
|
secrets: secretRegistry.slice(),
|
|
595
675
|
requiredEnv: requiredEnvRegistry.slice(),
|
|
596
676
|
signals: signalRegistry.slice(),
|
|
677
|
+
clocks: clockRegistry.slice(),
|
|
678
|
+
gates: gateRegistry.slice(),
|
|
597
679
|
channelTemplates: channelTemplateRegistry.slice(),
|
|
598
680
|
aiModels: aiModelRegistry.slice(),
|
|
599
681
|
aiPrompts: aiPromptRegistry.slice(),
|
|
600
682
|
aiEmbeds: aiEmbedRegistry.slice(),
|
|
601
683
|
aiAgents: aiAgentRegistry.slice(),
|
|
684
|
+
aiMcpServers: aiMcpServerRegistry.slice(),
|
|
602
685
|
};
|
|
603
686
|
if (registry === "consume") {
|
|
604
687
|
storeRegistry.length = 0;
|
|
605
688
|
secretRegistry.length = 0;
|
|
606
689
|
requiredEnvRegistry.length = 0;
|
|
607
690
|
signalRegistry.length = 0;
|
|
691
|
+
clockRegistry.length = 0;
|
|
692
|
+
gateRegistry.length = 0;
|
|
608
693
|
channelTemplateRegistry.length = 0;
|
|
609
694
|
aiModelRegistry.length = 0;
|
|
610
695
|
aiPromptRegistry.length = 0;
|
|
611
696
|
aiEmbedRegistry.length = 0;
|
|
612
697
|
aiAgentRegistry.length = 0;
|
|
698
|
+
aiMcpServerRegistry.length = 0;
|
|
613
699
|
}
|
|
614
700
|
const effectiveStores = mergeUnique(options.stores, registrySnapshot.stores);
|
|
615
701
|
const effectiveSecrets = mergeUnique(options.secrets, registrySnapshot.secrets);
|
|
616
702
|
const effectiveSignals = mergeUnique(options.signals, registrySnapshot.signals);
|
|
703
|
+
const effectiveClocks = mergeUnique(options.clocks, registrySnapshot.clocks);
|
|
704
|
+
const effectivePolicies = mergeUnique(options.gate?.policies, registrySnapshot.gates);
|
|
617
705
|
/**
|
|
618
706
|
* Fold registered `vault.env.required` names into the vault boot options so
|
|
619
707
|
* boot reports missing env vars in the same gap list as missing secrets.
|
|
@@ -643,20 +731,28 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
643
731
|
prompts: registrySnapshot.aiPrompts,
|
|
644
732
|
embeds: registrySnapshot.aiEmbeds,
|
|
645
733
|
agents: registrySnapshot.aiAgents,
|
|
734
|
+
mcpServers: registrySnapshot.aiMcpServers,
|
|
646
735
|
});
|
|
647
736
|
|
|
648
737
|
// Resolve Gate bag early so auth HTTP Bindings join `adopted` + the router
|
|
649
738
|
// before posture audit (same ensureBoot → doBoot path — never a side channel).
|
|
739
|
+
const mergedGate: GateOptions | undefined =
|
|
740
|
+
effectivePolicies.length > 0 ? { ...options.gate, policies: effectivePolicies } : options.gate;
|
|
650
741
|
const gateConfig: ResolvedGateConfig = resolveGateConfig({
|
|
651
|
-
gate:
|
|
742
|
+
gate: mergedGate,
|
|
652
743
|
env: options.env,
|
|
653
744
|
});
|
|
654
745
|
|
|
655
|
-
/** Retained for test harness / boot merges (includes auto-drained
|
|
656
|
-
const $options: OkeOptions =
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
746
|
+
/** Retained for test harness / boot merges (includes auto-drained decls). */
|
|
747
|
+
const $options: OkeOptions = {
|
|
748
|
+
...options,
|
|
749
|
+
...(effectiveAi !== undefined ? { ai: effectiveAi } : {}),
|
|
750
|
+
...(effectiveStores.length > 0 ? { stores: effectiveStores } : {}),
|
|
751
|
+
...(effectiveSecrets.length > 0 ? { secrets: effectiveSecrets } : {}),
|
|
752
|
+
...(effectiveSignals.length > 0 ? { signals: effectiveSignals } : {}),
|
|
753
|
+
...(effectiveClocks.length > 0 ? { clocks: effectiveClocks } : {}),
|
|
754
|
+
...(mergedGate !== undefined ? { gate: mergedGate } : {}),
|
|
755
|
+
};
|
|
660
756
|
|
|
661
757
|
const appHooks: HookMap = {};
|
|
662
758
|
const unitHooks = new Map<string, HookMap>();
|
|
@@ -690,8 +786,19 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
690
786
|
}
|
|
691
787
|
|
|
692
788
|
const smart = createRouter<Binding>(options.router ?? "default");
|
|
789
|
+
const seenHttpRoutes = new Set<string>();
|
|
693
790
|
for (const b of adopted) {
|
|
694
791
|
if (b.trigger.kind === "http") {
|
|
792
|
+
assertHttpBindingReady(b);
|
|
793
|
+
const key = `${b.trigger.method} ${b.trigger.path}`;
|
|
794
|
+
if (seenHttpRoutes.has(key)) {
|
|
795
|
+
throwOke("HTTP_ROUTE_DUPLICATE", {
|
|
796
|
+
method: b.trigger.method,
|
|
797
|
+
path: b.trigger.path,
|
|
798
|
+
flow: b.flow.name || "(unnamed)",
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
seenHttpRoutes.add(key);
|
|
695
802
|
smart.add(b.trigger.method, b.trigger.path, b);
|
|
696
803
|
compiled.set(b, compileHttpBinding(b, aot));
|
|
697
804
|
}
|
|
@@ -704,6 +811,16 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
704
811
|
adopted.push(b);
|
|
705
812
|
registerFlow(b.flow);
|
|
706
813
|
if (b.trigger.kind === "http") {
|
|
814
|
+
assertHttpBindingReady(b);
|
|
815
|
+
const key = `${b.trigger.method} ${b.trigger.path}`;
|
|
816
|
+
if (seenHttpRoutes.has(key)) {
|
|
817
|
+
throwOke("HTTP_ROUTE_DUPLICATE", {
|
|
818
|
+
method: b.trigger.method,
|
|
819
|
+
path: b.trigger.path,
|
|
820
|
+
flow: b.flow.name || "(unnamed)",
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
seenHttpRoutes.add(key);
|
|
707
824
|
smart.add(b.trigger.method, b.trigger.path, b);
|
|
708
825
|
compiled.set(b, compileHttpBinding(b, aot));
|
|
709
826
|
}
|
|
@@ -777,6 +894,11 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
777
894
|
registerFlow(b.flow);
|
|
778
895
|
}
|
|
779
896
|
|
|
897
|
+
if (registry !== "ignore") {
|
|
898
|
+
const generatedUnits = consumeRegisteredFlowUnits();
|
|
899
|
+
drainGeneratedUnits(generatedUnits, routes, registerFlow);
|
|
900
|
+
}
|
|
901
|
+
|
|
780
902
|
// --- boot (vault → store → signal → clock → channel → AI → runs → caps) ---
|
|
781
903
|
let bootResult: BootResult | undefined;
|
|
782
904
|
let bootPromise: Promise<BootResult> | undefined;
|
|
@@ -952,7 +1074,7 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
952
1074
|
vault: withRequiredEnv(overrides?.vault ?? options.vault),
|
|
953
1075
|
gates: [...baseGates, ...authGates],
|
|
954
1076
|
signals: overrides?.signals ?? effectiveSignals,
|
|
955
|
-
clocks: overrides?.clocks ??
|
|
1077
|
+
clocks: overrides?.clocks ?? effectiveClocks,
|
|
956
1078
|
stores: overrides?.stores ?? effectiveStores,
|
|
957
1079
|
channel: overrides?.channel ?? effectiveChannel,
|
|
958
1080
|
ai: overrides?.ai ?? effectiveAi,
|
|
@@ -1008,7 +1130,7 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1008
1130
|
|
|
1009
1131
|
const baseSecrets = overrides?.secrets ?? effectiveSecrets;
|
|
1010
1132
|
const baseSignals = overrides?.signals ?? effectiveSignals;
|
|
1011
|
-
const baseClocks = overrides?.clocks ??
|
|
1133
|
+
const baseClocks = overrides?.clocks ?? effectiveClocks;
|
|
1012
1134
|
const baseChannel = overrides?.channel ?? effectiveChannel;
|
|
1013
1135
|
const mergedCatalog = mergeTemplateCatalogs(baseChannel?.catalog, ...pluginChannelCatalogs);
|
|
1014
1136
|
|
|
@@ -1127,6 +1249,8 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1127
1249
|
readonly bypassGates?: boolean;
|
|
1128
1250
|
/** Console Call API — cleartext store PII. Requires {@link trustedInvoke}. */
|
|
1129
1251
|
readonly revealPii?: boolean;
|
|
1252
|
+
/** Forced RLS bag (Console / Call API). Operator omit = no stamp. */
|
|
1253
|
+
readonly rls?: import("../drivers/pg-rls.ts").RlsIdentity;
|
|
1130
1254
|
/** Frozen origin identity for {@link Fx.principal} across `fx.call`. */
|
|
1131
1255
|
readonly originPrincipal?: FxPrincipal;
|
|
1132
1256
|
/** Explicit locale override for {@link Fx.t} / channel sends. */
|
|
@@ -1149,16 +1273,19 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1149
1273
|
defaultLocale,
|
|
1150
1274
|
);
|
|
1151
1275
|
|
|
1152
|
-
return runWithLocale({ locale: resolvedLocale, defaultLocale }, () =>
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1276
|
+
return runWithLocale({ locale: resolvedLocale, defaultLocale }, () => {
|
|
1277
|
+
const run = () =>
|
|
1278
|
+
executeInLocale({
|
|
1279
|
+
flowDef,
|
|
1280
|
+
input,
|
|
1281
|
+
trigger,
|
|
1282
|
+
extras,
|
|
1283
|
+
resolvedLocale,
|
|
1284
|
+
defaultLocale,
|
|
1285
|
+
});
|
|
1286
|
+
const signal = extras?.request?.signal;
|
|
1287
|
+
return signal ? withAbortSignal(signal, run) : run();
|
|
1288
|
+
});
|
|
1162
1289
|
}
|
|
1163
1290
|
|
|
1164
1291
|
async function executeInLocale(args: {
|
|
@@ -1175,6 +1302,7 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1175
1302
|
readonly trustedInvoke?: boolean;
|
|
1176
1303
|
readonly bypassGates?: boolean;
|
|
1177
1304
|
readonly revealPii?: boolean;
|
|
1305
|
+
readonly rls?: import("../drivers/pg-rls.ts").RlsIdentity;
|
|
1178
1306
|
readonly originPrincipal?: FxPrincipal;
|
|
1179
1307
|
readonly locale?: string;
|
|
1180
1308
|
readonly parentId?: string;
|
|
@@ -1325,6 +1453,9 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1325
1453
|
...(principals ? { auth: principals.auth as FxAuth, operator: principals.operator } : {}),
|
|
1326
1454
|
...(extras?.originPrincipal ? { principal: extras.originPrincipal } : {}),
|
|
1327
1455
|
...(extras?.trustedInvoke === true && extras.revealPii === true ? { revealPii: true } : {}),
|
|
1456
|
+
rlsGateNames: gateNamesOf(trigger),
|
|
1457
|
+
rlsBypass: extras?.bypassGates === true || flowDef.plane === "operator",
|
|
1458
|
+
...(extras?.rls ? { rls: extras.rls } : {}),
|
|
1328
1459
|
...(capability ? { capability } : {}),
|
|
1329
1460
|
...(booted
|
|
1330
1461
|
? {
|
|
@@ -1451,7 +1582,7 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1451
1582
|
durable: flowDef.durable,
|
|
1452
1583
|
effects: putEffects,
|
|
1453
1584
|
});
|
|
1454
|
-
if (storeAfter && output !== undefined) {
|
|
1585
|
+
if (storeAfter && output !== undefined && !isJsonStreamResult(output)) {
|
|
1455
1586
|
const ttlMs =
|
|
1456
1587
|
typeof flowDef.cache === "string" ? cache.parseTtlMs(flowDef.cache) : undefined;
|
|
1457
1588
|
storeRt.putTier1(
|
|
@@ -1499,60 +1630,79 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1499
1630
|
|
|
1500
1631
|
const endedAt = now();
|
|
1501
1632
|
const durationMs = resolveDurationMs(endedAt - startedAt, performance.now() - startedHr);
|
|
1633
|
+
const streamOut = isJsonStreamResult(result.output) ? result.output : undefined;
|
|
1634
|
+
|
|
1635
|
+
const finalizeRun = async (): Promise<void> => {
|
|
1636
|
+
// Stream rows land in Traces only after close. Measure wall time then
|
|
1637
|
+
// so duration / waterfall cover the open stream, not just TTFB.
|
|
1638
|
+
const recordEndedAt = streamOut ? now() : endedAt;
|
|
1639
|
+
const recordDurationMs = streamOut
|
|
1640
|
+
? resolveDurationMs(recordEndedAt - startedAt, performance.now() - startedHr)
|
|
1641
|
+
: durationMs;
|
|
1642
|
+
if (journalSession) {
|
|
1643
|
+
inflightRuns.delete(journalSession.runId);
|
|
1644
|
+
const sleeping = ctx.state.sleeping as
|
|
1645
|
+
| { readonly wakeAt: number; readonly label: string; readonly runId: string }
|
|
1646
|
+
| undefined;
|
|
1647
|
+
// Lease-capable stores make the shared row the wake schedule; the
|
|
1648
|
+
// in-process map is only for custom stores without the lease surface.
|
|
1649
|
+
if (sleeping && !hasJournalLease(activeJournal().store)) {
|
|
1650
|
+
sleepingRuns.set(sleeping.runId, {
|
|
1651
|
+
flow: flowDef,
|
|
1652
|
+
input: ctx.input,
|
|
1653
|
+
wakeAt: sleeping.wakeAt,
|
|
1654
|
+
});
|
|
1655
|
+
} else if (!sleeping && isTerminalFailure(result)) {
|
|
1656
|
+
const terminalErr = result.failure ?? result.ctx.error;
|
|
1657
|
+
await runCompensationPhase({
|
|
1658
|
+
flow: flowDef,
|
|
1659
|
+
input: ctx.input,
|
|
1660
|
+
session: journalSession,
|
|
1661
|
+
fx,
|
|
1662
|
+
error: terminalErr,
|
|
1663
|
+
});
|
|
1664
|
+
} else if (!sleeping) {
|
|
1665
|
+
await journalSession.commit("completed", {
|
|
1666
|
+
output: streamOut ? { streamed: true } : result.output,
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1502
1670
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1671
|
+
const runsRuntime =
|
|
1672
|
+
booted?.runs ?? (isRunsRuntimeLike(options.runs) ? options.runs : undefined);
|
|
1673
|
+
if (runsRuntime) {
|
|
1674
|
+
const archiveCleartext = archiveFromInput(ctx.input, options.archiveInputFields);
|
|
1675
|
+
const replayInput = redactArchivedFields(ctx.input, options.archiveInputFields);
|
|
1676
|
+
const recordFailure =
|
|
1677
|
+
result.failure ??
|
|
1678
|
+
(isTerminalFailure(result) ? failureFromUnknown(result.ctx.error) : undefined);
|
|
1679
|
+
await runsRuntime.record(
|
|
1680
|
+
{
|
|
1681
|
+
flow: flowDef,
|
|
1682
|
+
trigger,
|
|
1683
|
+
fx,
|
|
1684
|
+
ledger,
|
|
1685
|
+
telemetry,
|
|
1686
|
+
startedAt,
|
|
1687
|
+
endedAt: recordEndedAt,
|
|
1688
|
+
durationMs: recordDurationMs,
|
|
1689
|
+
failure: recordFailure,
|
|
1690
|
+
id: runId,
|
|
1691
|
+
input: replayInput,
|
|
1692
|
+
...(result.output !== undefined && !recordFailure
|
|
1693
|
+
? { output: streamOut ? { streamed: true } : result.output }
|
|
1694
|
+
: {}),
|
|
1695
|
+
...(parentId !== undefined ? { parentId } : {}),
|
|
1696
|
+
},
|
|
1697
|
+
archiveCleartext,
|
|
1698
|
+
);
|
|
1527
1699
|
}
|
|
1528
|
-
}
|
|
1700
|
+
};
|
|
1529
1701
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
const replayInput = redactArchivedFields(ctx.input, options.archiveInputFields);
|
|
1535
|
-
const recordFailure =
|
|
1536
|
-
result.failure ??
|
|
1537
|
-
(isTerminalFailure(result) ? failureFromUnknown(result.ctx.error) : undefined);
|
|
1538
|
-
await runsRuntime.record(
|
|
1539
|
-
{
|
|
1540
|
-
flow: flowDef,
|
|
1541
|
-
trigger,
|
|
1542
|
-
fx,
|
|
1543
|
-
ledger,
|
|
1544
|
-
telemetry,
|
|
1545
|
-
startedAt,
|
|
1546
|
-
endedAt,
|
|
1547
|
-
durationMs,
|
|
1548
|
-
failure: recordFailure,
|
|
1549
|
-
id: runId,
|
|
1550
|
-
input: replayInput,
|
|
1551
|
-
...(result.output !== undefined && !recordFailure ? { output: result.output } : {}),
|
|
1552
|
-
...(parentId !== undefined ? { parentId } : {}),
|
|
1553
|
-
},
|
|
1554
|
-
archiveCleartext,
|
|
1555
|
-
);
|
|
1702
|
+
if (streamOut && !isTerminalFailure(result)) {
|
|
1703
|
+
streamOut.finalize = finalizeRun;
|
|
1704
|
+
} else {
|
|
1705
|
+
await finalizeRun();
|
|
1556
1706
|
}
|
|
1557
1707
|
|
|
1558
1708
|
return {
|
|
@@ -44,7 +44,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
44
44
|
const db = store.sql("app", { schema: { notes } });
|
|
45
45
|
let lists = 0;
|
|
46
46
|
const list = on(
|
|
47
|
-
http.get("/notes").
|
|
47
|
+
http.get("/notes").public(),
|
|
48
48
|
flow("notes.list", {
|
|
49
49
|
out: z.array(NoteOut),
|
|
50
50
|
effects: { reads: ["sql:notes"] },
|
|
@@ -80,7 +80,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
80
80
|
resetFlowSeq();
|
|
81
81
|
const db = store.sql("app", { schema: { notes } });
|
|
82
82
|
const list = on(
|
|
83
|
-
http.get("/notes").
|
|
83
|
+
http.get("/notes").public(),
|
|
84
84
|
flow("notes.list", {
|
|
85
85
|
out: z.array(NoteOut),
|
|
86
86
|
effects: { reads: ["sql:notes"] },
|
|
@@ -115,7 +115,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
115
115
|
const db = store.sql("app", { schema: { notes } });
|
|
116
116
|
let lists = 0;
|
|
117
117
|
const list = on(
|
|
118
|
-
http.get("/notes").
|
|
118
|
+
http.get("/notes").public(),
|
|
119
119
|
flow("notes.list", {
|
|
120
120
|
cache: false,
|
|
121
121
|
effects: { reads: ["sql:notes"] },
|
|
@@ -146,7 +146,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
146
146
|
const db = store.sql("app", { schema: { notes } });
|
|
147
147
|
let lists = 0;
|
|
148
148
|
const list = on(
|
|
149
|
-
http.get("/notes").
|
|
149
|
+
http.get("/notes").public(),
|
|
150
150
|
flow("notes.list", {
|
|
151
151
|
out: z.array(NoteOut),
|
|
152
152
|
do: async (_input, fx) => {
|
|
@@ -191,7 +191,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
191
191
|
const db = store.sql("app", { schema: { notes } });
|
|
192
192
|
let lists = 0;
|
|
193
193
|
const list = on(
|
|
194
|
-
http.get("/notes").
|
|
194
|
+
http.get("/notes").public(),
|
|
195
195
|
flow("notes.list", {
|
|
196
196
|
effects: { reads: ["sql:notes"] },
|
|
197
197
|
do: () => {
|
|
@@ -201,7 +201,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
201
201
|
}),
|
|
202
202
|
);
|
|
203
203
|
const create = on(
|
|
204
|
-
http.post("/notes").
|
|
204
|
+
http.post("/notes").public(),
|
|
205
205
|
flow("notes.create", {
|
|
206
206
|
in: z.object({ title: z.string() }),
|
|
207
207
|
effects: { writes: ["sql:notes"] },
|
|
@@ -231,7 +231,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
231
231
|
const db = store.sql("app", { schema: { notes } });
|
|
232
232
|
let lists = 0;
|
|
233
233
|
const list = on(
|
|
234
|
-
http.get("/notes").
|
|
234
|
+
http.get("/notes").public(),
|
|
235
235
|
flow("notes.list", {
|
|
236
236
|
out: z.array(NoteOut),
|
|
237
237
|
do: async (_input, fx) => {
|
|
@@ -242,7 +242,7 @@ describe("automatic tier-1 cache from effects", () => {
|
|
|
242
242
|
}),
|
|
243
243
|
);
|
|
244
244
|
const create = on(
|
|
245
|
-
http.post("/notes").
|
|
245
|
+
http.post("/notes").public(),
|
|
246
246
|
flow("notes.create", {
|
|
247
247
|
in: z.object({ title: z.string() }),
|
|
248
248
|
do: async (input, fx) => {
|