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
|
@@ -27,12 +27,15 @@ import { maskPiiValue, maskWideEventForConsole, piiFieldNamesFromManifest } from
|
|
|
27
27
|
import { ConsoleRunsQueryError, RUNS_QUERY_PII_GAP, RUNS_QUERY_TIMEOUT_MS } from "./runs-query.ts";
|
|
28
28
|
import { DuckQueryTimeoutError } from "../../runs/duckdb.ts";
|
|
29
29
|
import { ClockResourceNotFoundError, ScheduleNotOverridableError } from "./clock.ts";
|
|
30
|
+
import { isoAt } from "./iso-at.ts";
|
|
30
31
|
import { createFileDiff, emitStructuralDiff } from "./structural.ts";
|
|
31
32
|
import type { ConsoleState } from "./state.ts";
|
|
32
33
|
import { consoleFailureMessage } from "./i18n.ts";
|
|
33
34
|
import { CONSOLE_PASSWORD_POLICY } from "../password-policy.ts";
|
|
34
35
|
import { PUBLIC_CONSOLE_FLOWS } from "./public-flows.ts";
|
|
35
36
|
import { resolveInvokeAs } from "./invoke-user-flow.ts";
|
|
37
|
+
import { resolveRlsIdentity } from "../../elements/store.ts";
|
|
38
|
+
import type { RlsIdentity } from "../../drivers/pg-rls.ts";
|
|
36
39
|
import { isKnownConsoleSqlGate, StoreFileNotFoundError, tenancyDeclared } from "./store.ts";
|
|
37
40
|
import {
|
|
38
41
|
PG_STAT_STATEMENTS_NOT_CREATED,
|
|
@@ -152,7 +155,7 @@ const TracesReplayOut = z.object({
|
|
|
152
155
|
ok: z.literal(true),
|
|
153
156
|
rootId: z.string(),
|
|
154
157
|
dryRun: z.boolean(),
|
|
155
|
-
at: z.
|
|
158
|
+
at: z.string(),
|
|
156
159
|
flow: z.string(),
|
|
157
160
|
});
|
|
158
161
|
|
|
@@ -260,7 +263,7 @@ const SignalsReplayOut = z.object({
|
|
|
260
263
|
messageId: z.string().optional(),
|
|
261
264
|
}),
|
|
262
265
|
),
|
|
263
|
-
at: z.
|
|
266
|
+
at: z.string(),
|
|
264
267
|
});
|
|
265
268
|
|
|
266
269
|
const SignalsDiscardIn = z.object({
|
|
@@ -273,7 +276,7 @@ const SignalsDiscardIn = z.object({
|
|
|
273
276
|
const SignalsDiscardOut = z.object({
|
|
274
277
|
ok: z.literal(true),
|
|
275
278
|
discarded: z.number(),
|
|
276
|
-
at: z.
|
|
279
|
+
at: z.string(),
|
|
277
280
|
});
|
|
278
281
|
|
|
279
282
|
const ActionPingIn = z.object({
|
|
@@ -283,7 +286,7 @@ const ActionPingIn = z.object({
|
|
|
283
286
|
const ActionPingOut = z.object({
|
|
284
287
|
ok: z.literal(true),
|
|
285
288
|
note: z.string().optional(),
|
|
286
|
-
at: z.
|
|
289
|
+
at: z.string(),
|
|
287
290
|
});
|
|
288
291
|
|
|
289
292
|
const StructuralIn = z.object({
|
|
@@ -354,6 +357,13 @@ const InvokeOut = z.object({
|
|
|
354
357
|
durationMs: z.number().optional(),
|
|
355
358
|
peakTier: z.enum(["none", "reads", "writes", "emits", "external", "capabilities"]),
|
|
356
359
|
auditedAt: z.number(),
|
|
360
|
+
rls: z
|
|
361
|
+
.object({
|
|
362
|
+
gate: z.string().nullable(),
|
|
363
|
+
userId: z.string(),
|
|
364
|
+
applied: z.boolean(),
|
|
365
|
+
})
|
|
366
|
+
.optional(),
|
|
357
367
|
});
|
|
358
368
|
|
|
359
369
|
const SetupClosed = z.object({ reason: z.string() });
|
|
@@ -504,7 +514,7 @@ const ChannelRevealOut = z.object({
|
|
|
504
514
|
ok: z.literal(true),
|
|
505
515
|
id: z.string(),
|
|
506
516
|
to: z.string(),
|
|
507
|
-
at: z.
|
|
517
|
+
at: z.string(),
|
|
508
518
|
});
|
|
509
519
|
|
|
510
520
|
const ChannelSendTestIn = z.object({
|
|
@@ -521,7 +531,7 @@ const ChannelSendTestOut = z.object({
|
|
|
521
531
|
messageId: z.string(),
|
|
522
532
|
status: z.string(),
|
|
523
533
|
chain: z.string(),
|
|
524
|
-
at: z.
|
|
534
|
+
at: z.string(),
|
|
525
535
|
});
|
|
526
536
|
|
|
527
537
|
const VaultNotFound = z.object({
|
|
@@ -634,7 +644,7 @@ const ClockRunNowOut = z.object({
|
|
|
634
644
|
ok: z.literal(true),
|
|
635
645
|
name: z.string(),
|
|
636
646
|
ran: z.boolean(),
|
|
637
|
-
at: z.
|
|
647
|
+
at: z.string(),
|
|
638
648
|
});
|
|
639
649
|
|
|
640
650
|
const ClockPauseIn = z.object({ name: z.string().min(1) });
|
|
@@ -642,7 +652,7 @@ const ClockPauseOut = z.object({
|
|
|
642
652
|
ok: z.literal(true),
|
|
643
653
|
name: z.string(),
|
|
644
654
|
status: z.string(),
|
|
645
|
-
at: z.
|
|
655
|
+
at: z.string(),
|
|
646
656
|
});
|
|
647
657
|
|
|
648
658
|
const ClockEditIn = z.object({
|
|
@@ -656,7 +666,7 @@ const ClockEditOut = z.object({
|
|
|
656
666
|
name: z.string(),
|
|
657
667
|
effectiveCron: z.string().optional(),
|
|
658
668
|
effectiveEvery: z.string().optional(),
|
|
659
|
-
at: z.
|
|
669
|
+
at: z.string(),
|
|
660
670
|
});
|
|
661
671
|
|
|
662
672
|
const ClockWakeEarlyIn = z.object({ runId: z.string().min(1) });
|
|
@@ -665,7 +675,7 @@ const ClockWakeEarlyOut = z.object({
|
|
|
665
675
|
runId: z.string(),
|
|
666
676
|
wakeAt: z.number(),
|
|
667
677
|
resumed: z.boolean(),
|
|
668
|
-
at: z.
|
|
678
|
+
at: z.string(),
|
|
669
679
|
});
|
|
670
680
|
|
|
671
681
|
const VaultResolutionStepOut = z.object({
|
|
@@ -746,7 +756,7 @@ const VaultWriteOut = z.object({
|
|
|
746
756
|
ok: z.literal(true),
|
|
747
757
|
name: z.string(),
|
|
748
758
|
fingerprint: z.string().nullable(),
|
|
749
|
-
at: z.
|
|
759
|
+
at: z.string(),
|
|
750
760
|
});
|
|
751
761
|
|
|
752
762
|
const VaultAuditRowOut = z.object({
|
|
@@ -780,7 +790,7 @@ const VaultRotateMasterOut = z.object({
|
|
|
780
790
|
kekVersion: z.number(),
|
|
781
791
|
remaining: z.number(),
|
|
782
792
|
masterKey: z.string().nullable(),
|
|
783
|
-
at: z.
|
|
793
|
+
at: z.string(),
|
|
784
794
|
});
|
|
785
795
|
|
|
786
796
|
const AiMetricOut = z.object({
|
|
@@ -834,6 +844,7 @@ const AiListOut = z.object({
|
|
|
834
844
|
ok: z.number(),
|
|
835
845
|
provider_error: z.number(),
|
|
836
846
|
schema_invalid: z.number(),
|
|
847
|
+
budget_exceeded: z.number(),
|
|
837
848
|
}),
|
|
838
849
|
}),
|
|
839
850
|
),
|
|
@@ -1421,6 +1432,7 @@ const StoreListOut = z.object({
|
|
|
1421
1432
|
piiColumns: z.array(z.string()),
|
|
1422
1433
|
columnDescriptions: z.record(z.string(), z.string()),
|
|
1423
1434
|
rls: z.boolean().optional(),
|
|
1435
|
+
rlsPolicyCount: z.number().int().nonnegative().optional(),
|
|
1424
1436
|
}),
|
|
1425
1437
|
),
|
|
1426
1438
|
replicaLagMs: z.number().nullable(),
|
|
@@ -1444,6 +1456,17 @@ const StoreListOut = z.object({
|
|
|
1444
1456
|
),
|
|
1445
1457
|
});
|
|
1446
1458
|
|
|
1459
|
+
const StoreRlsAs = {
|
|
1460
|
+
asGate: z.string().min(1).optional(),
|
|
1461
|
+
asUserId: z.string().min(1).optional(),
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1464
|
+
const StoreRlsOut = z.object({
|
|
1465
|
+
gate: z.string().nullable(),
|
|
1466
|
+
userId: z.string(),
|
|
1467
|
+
applied: z.boolean(),
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1447
1470
|
const StoreQueryIn = z.object({
|
|
1448
1471
|
ref: z.string().min(1),
|
|
1449
1472
|
child: z.string().optional(),
|
|
@@ -1454,6 +1477,7 @@ const StoreQueryIn = z.object({
|
|
|
1454
1477
|
q: z.string().optional(),
|
|
1455
1478
|
topK: z.number().min(1).max(100).optional(),
|
|
1456
1479
|
revealPii: z.boolean().optional(),
|
|
1480
|
+
...StoreRlsAs,
|
|
1457
1481
|
});
|
|
1458
1482
|
|
|
1459
1483
|
const StoreQueryOut = z.object({
|
|
@@ -1482,6 +1506,7 @@ const StoreQueryOut = z.object({
|
|
|
1482
1506
|
.optional(),
|
|
1483
1507
|
masked: z.boolean(),
|
|
1484
1508
|
routedRole: z.enum(["primary", "replica"]).optional(),
|
|
1509
|
+
rls: StoreRlsOut.optional(),
|
|
1485
1510
|
});
|
|
1486
1511
|
|
|
1487
1512
|
const StoreRevealIn = z.object({
|
|
@@ -1495,7 +1520,7 @@ const StoreRevealIn = z.object({
|
|
|
1495
1520
|
const StoreRevealOut = z.object({
|
|
1496
1521
|
ok: z.literal(true),
|
|
1497
1522
|
value: z.unknown(),
|
|
1498
|
-
at: z.
|
|
1523
|
+
at: z.string(),
|
|
1499
1524
|
});
|
|
1500
1525
|
|
|
1501
1526
|
const StoreFileGetIn = z.object({
|
|
@@ -1526,6 +1551,7 @@ const StoreEditIn = z.object({
|
|
|
1526
1551
|
reason: z.string().optional(),
|
|
1527
1552
|
/** When false/omitted, returns willNotFire without applying. */
|
|
1528
1553
|
commit: z.boolean().optional(),
|
|
1554
|
+
...StoreRlsAs,
|
|
1529
1555
|
});
|
|
1530
1556
|
|
|
1531
1557
|
const StoreEditOut = z.object({
|
|
@@ -1539,7 +1565,8 @@ const StoreEditOut = z.object({
|
|
|
1539
1565
|
resource: z.string(),
|
|
1540
1566
|
}),
|
|
1541
1567
|
),
|
|
1542
|
-
at: z.
|
|
1568
|
+
at: z.string(),
|
|
1569
|
+
rls: StoreRlsOut.optional(),
|
|
1543
1570
|
});
|
|
1544
1571
|
|
|
1545
1572
|
const StoreDeleteIn = z.object({
|
|
@@ -1555,7 +1582,7 @@ const StoreDeleteIn = z.object({
|
|
|
1555
1582
|
const StoreDeleteOut = z.object({
|
|
1556
1583
|
ok: z.literal(true),
|
|
1557
1584
|
deleted: z.number(),
|
|
1558
|
-
at: z.
|
|
1585
|
+
at: z.string(),
|
|
1559
1586
|
});
|
|
1560
1587
|
|
|
1561
1588
|
const StorePurgeIn = z.object({
|
|
@@ -1567,7 +1594,7 @@ const StorePurgeIn = z.object({
|
|
|
1567
1594
|
const StorePurgeOut = z.object({
|
|
1568
1595
|
ok: z.literal(true),
|
|
1569
1596
|
keys: z.array(z.string()),
|
|
1570
|
-
at: z.
|
|
1597
|
+
at: z.string(),
|
|
1571
1598
|
});
|
|
1572
1599
|
|
|
1573
1600
|
const StoreSqlIn = z.object({
|
|
@@ -1577,6 +1604,7 @@ const StoreSqlIn = z.object({
|
|
|
1577
1604
|
allowWrite: z.boolean().optional(),
|
|
1578
1605
|
revealPii: z.boolean().optional(),
|
|
1579
1606
|
asGate: z.string().min(1).optional(),
|
|
1607
|
+
asUserId: z.string().min(1).optional(),
|
|
1580
1608
|
});
|
|
1581
1609
|
|
|
1582
1610
|
const StoreSqlOut = z.object({
|
|
@@ -1584,7 +1612,9 @@ const StoreSqlOut = z.object({
|
|
|
1584
1612
|
masked: z.boolean(),
|
|
1585
1613
|
routedRole: z.enum(["primary", "replica"]),
|
|
1586
1614
|
asGate: z.string().nullable(),
|
|
1615
|
+
asUserId: z.string().nullable(),
|
|
1587
1616
|
gateApplied: z.boolean(),
|
|
1617
|
+
rls: StoreRlsOut.optional(),
|
|
1588
1618
|
});
|
|
1589
1619
|
|
|
1590
1620
|
const StoreSqlStatsIn = z.object({
|
|
@@ -1748,7 +1778,7 @@ const StorePreviewOut = z.object({
|
|
|
1748
1778
|
resource: z.string(),
|
|
1749
1779
|
}),
|
|
1750
1780
|
),
|
|
1751
|
-
at: z.
|
|
1781
|
+
at: z.string(),
|
|
1752
1782
|
});
|
|
1753
1783
|
|
|
1754
1784
|
/**
|
|
@@ -2361,7 +2391,7 @@ function createTracesReplay(state: ConsoleState) {
|
|
|
2361
2391
|
ok: true as const,
|
|
2362
2392
|
rootId: input.rootId,
|
|
2363
2393
|
dryRun,
|
|
2364
|
-
at: Date.now(),
|
|
2394
|
+
at: isoAt(Date.now()),
|
|
2365
2395
|
flow: root.flow,
|
|
2366
2396
|
};
|
|
2367
2397
|
},
|
|
@@ -2442,7 +2472,7 @@ function createSignalsDiscard(state: ConsoleState) {
|
|
|
2442
2472
|
return {
|
|
2443
2473
|
ok: true as const,
|
|
2444
2474
|
discarded: result.discarded,
|
|
2445
|
-
at: state.now(),
|
|
2475
|
+
at: isoAt(state.now()),
|
|
2446
2476
|
};
|
|
2447
2477
|
},
|
|
2448
2478
|
});
|
|
@@ -2516,7 +2546,7 @@ async function runSignalReplay(
|
|
|
2516
2546
|
dryRun: result.dryRun,
|
|
2517
2547
|
results: [...result.results],
|
|
2518
2548
|
wouldHaveFired: [...result.wouldHaveFired],
|
|
2519
|
-
at: state.now(),
|
|
2549
|
+
at: isoAt(state.now()),
|
|
2520
2550
|
};
|
|
2521
2551
|
}
|
|
2522
2552
|
|
|
@@ -2561,7 +2591,7 @@ function createActionPing(state: ConsoleState) {
|
|
|
2561
2591
|
operatorId: fx.operator.id,
|
|
2562
2592
|
note: input.note,
|
|
2563
2593
|
});
|
|
2564
|
-
return { ok: true as const, note: input.note, at: state.now() };
|
|
2594
|
+
return { ok: true as const, note: input.note, at: isoAt(state.now()) };
|
|
2565
2595
|
},
|
|
2566
2596
|
});
|
|
2567
2597
|
}
|
|
@@ -2663,6 +2693,7 @@ function createFlowsInvoke(state: ConsoleState) {
|
|
|
2663
2693
|
...(assumed.bypassGates ? { bypassGates: true } : {}),
|
|
2664
2694
|
...(input.reason !== undefined ? { reason: input.reason } : {}),
|
|
2665
2695
|
...(input.revealPii === true ? { revealPii: true } : {}),
|
|
2696
|
+
...(assumed.rls ? { rls: assumed.rls } : {}),
|
|
2666
2697
|
});
|
|
2667
2698
|
|
|
2668
2699
|
const reveal = input.revealPii === true;
|
|
@@ -2715,6 +2746,11 @@ function createFlowsInvoke(state: ConsoleState) {
|
|
|
2715
2746
|
...(host.durationMs !== undefined ? { durationMs: host.durationMs } : {}),
|
|
2716
2747
|
peakTier,
|
|
2717
2748
|
auditedAt: state.now(),
|
|
2749
|
+
rls: {
|
|
2750
|
+
gate: assumed.rls?.gate ?? null,
|
|
2751
|
+
userId: assumed.rls?.userId ?? "",
|
|
2752
|
+
applied: assumed.rls !== null,
|
|
2753
|
+
},
|
|
2718
2754
|
};
|
|
2719
2755
|
},
|
|
2720
2756
|
});
|
|
@@ -2805,6 +2841,32 @@ function createStoreList(state: ConsoleState) {
|
|
|
2805
2841
|
});
|
|
2806
2842
|
}
|
|
2807
2843
|
|
|
2844
|
+
function consoleStoreRls(
|
|
2845
|
+
state: ConsoleState,
|
|
2846
|
+
input: { readonly asGate?: string; readonly asUserId?: string },
|
|
2847
|
+
):
|
|
2848
|
+
| { readonly ok: true; readonly rls: RlsIdentity | null }
|
|
2849
|
+
| { readonly ok: false; readonly reason: string } {
|
|
2850
|
+
if (input.asGate !== undefined && !isKnownConsoleSqlGate(state.manifest, input.asGate)) {
|
|
2851
|
+
return { ok: false, reason: `unknown gate: ${input.asGate}` };
|
|
2852
|
+
}
|
|
2853
|
+
if (input.asUserId !== undefined) {
|
|
2854
|
+
const identity = state.identities.find((row) => row.id === input.asUserId);
|
|
2855
|
+
if (!identity || identity.status === "disabled") {
|
|
2856
|
+
return { ok: false, reason: `unknown identity: ${input.asUserId}` };
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
return {
|
|
2860
|
+
ok: true,
|
|
2861
|
+
rls: resolveRlsIdentity({
|
|
2862
|
+
asGate: input.asGate,
|
|
2863
|
+
asUserId: input.asUserId,
|
|
2864
|
+
identities: state.identities,
|
|
2865
|
+
manifest: state.manifest,
|
|
2866
|
+
}),
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2808
2870
|
function createStoreQuery(state: ConsoleState) {
|
|
2809
2871
|
return flow("console.store.query", {
|
|
2810
2872
|
plane: "operator",
|
|
@@ -2823,6 +2885,8 @@ function createStoreQuery(state: ConsoleState) {
|
|
|
2823
2885
|
tenant: input.tenant,
|
|
2824
2886
|
});
|
|
2825
2887
|
}
|
|
2888
|
+
const assumed = consoleStoreRls(state, input);
|
|
2889
|
+
if (!assumed.ok) return fail("StoreNotFound", { ref: assumed.reason });
|
|
2826
2890
|
return state.queryStore({
|
|
2827
2891
|
ref: input.ref as ResourceRef,
|
|
2828
2892
|
child: input.child,
|
|
@@ -2833,6 +2897,9 @@ function createStoreQuery(state: ConsoleState) {
|
|
|
2833
2897
|
q: input.q,
|
|
2834
2898
|
topK: input.topK,
|
|
2835
2899
|
revealPii: input.revealPii === true,
|
|
2900
|
+
...(input.asGate !== undefined ? { asGate: input.asGate } : {}),
|
|
2901
|
+
...(input.asUserId !== undefined ? { asUserId: input.asUserId } : {}),
|
|
2902
|
+
...(assumed.rls ? { rls: assumed.rls } : {}),
|
|
2836
2903
|
});
|
|
2837
2904
|
},
|
|
2838
2905
|
});
|
|
@@ -2868,7 +2935,7 @@ function createStoreReveal(state: ConsoleState) {
|
|
|
2868
2935
|
return {
|
|
2869
2936
|
ok: true as const,
|
|
2870
2937
|
value: row[input.column],
|
|
2871
|
-
at: state.now(),
|
|
2938
|
+
at: isoAt(state.now()),
|
|
2872
2939
|
};
|
|
2873
2940
|
},
|
|
2874
2941
|
});
|
|
@@ -2921,6 +2988,14 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2921
2988
|
const tenantFail = requireTenantIfDeclared(state, input.tenant);
|
|
2922
2989
|
if (tenantFail) return tenantFail;
|
|
2923
2990
|
|
|
2991
|
+
const assumed = consoleStoreRls(state, input);
|
|
2992
|
+
if (!assumed.ok) return fail("StoreNotFound", { ref: assumed.reason });
|
|
2993
|
+
const rlsFields = {
|
|
2994
|
+
...(input.asGate !== undefined ? { asGate: input.asGate } : {}),
|
|
2995
|
+
...(input.asUserId !== undefined ? { asUserId: input.asUserId } : {}),
|
|
2996
|
+
...(assumed.rls ? { rls: assumed.rls } : {}),
|
|
2997
|
+
};
|
|
2998
|
+
|
|
2924
2999
|
if (!input.commit) {
|
|
2925
3000
|
// Return will-not-fire payload without applying — informational confirm.
|
|
2926
3001
|
const preview = await state.editStore(
|
|
@@ -2931,6 +3006,7 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2931
3006
|
id: input.id,
|
|
2932
3007
|
key: input.key,
|
|
2933
3008
|
patch: input.patch,
|
|
3009
|
+
...rlsFields,
|
|
2934
3010
|
},
|
|
2935
3011
|
{ dryRun: true },
|
|
2936
3012
|
);
|
|
@@ -2940,7 +3016,8 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2940
3016
|
applied: false,
|
|
2941
3017
|
willNotFire: preview.willNotFire,
|
|
2942
3018
|
wouldHaveFired: [...preview.wouldHaveFired],
|
|
2943
|
-
at: state.now(),
|
|
3019
|
+
at: isoAt(state.now()),
|
|
3020
|
+
...(preview.rls ? { rls: preview.rls } : {}),
|
|
2944
3021
|
};
|
|
2945
3022
|
}
|
|
2946
3023
|
|
|
@@ -2961,6 +3038,7 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2961
3038
|
id: input.id,
|
|
2962
3039
|
key: input.key,
|
|
2963
3040
|
patch: input.patch,
|
|
3041
|
+
...rlsFields,
|
|
2964
3042
|
},
|
|
2965
3043
|
{ dryRun: false },
|
|
2966
3044
|
);
|
|
@@ -2977,7 +3055,8 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2977
3055
|
applied: result.applied,
|
|
2978
3056
|
willNotFire: result.willNotFire,
|
|
2979
3057
|
wouldHaveFired: [...result.wouldHaveFired],
|
|
2980
|
-
at: state.now(),
|
|
3058
|
+
at: isoAt(state.now()),
|
|
3059
|
+
...(result.rls ? { rls: result.rls } : {}),
|
|
2981
3060
|
};
|
|
2982
3061
|
},
|
|
2983
3062
|
});
|
|
@@ -3017,7 +3096,7 @@ function createStoreDelete(state: ConsoleState) {
|
|
|
3017
3096
|
return {
|
|
3018
3097
|
ok: true as const,
|
|
3019
3098
|
deleted: result.deleted,
|
|
3020
|
-
at: state.now(),
|
|
3099
|
+
at: isoAt(state.now()),
|
|
3021
3100
|
};
|
|
3022
3101
|
},
|
|
3023
3102
|
});
|
|
@@ -3049,7 +3128,7 @@ function createStorePurgeCache(state: ConsoleState) {
|
|
|
3049
3128
|
return {
|
|
3050
3129
|
ok: true as const,
|
|
3051
3130
|
keys: [...result.keys],
|
|
3052
|
-
at: state.now(),
|
|
3131
|
+
at: isoAt(state.now()),
|
|
3053
3132
|
};
|
|
3054
3133
|
},
|
|
3055
3134
|
});
|
|
@@ -3073,9 +3152,8 @@ function createStoreSql(state: ConsoleState) {
|
|
|
3073
3152
|
tenant: input.tenant,
|
|
3074
3153
|
});
|
|
3075
3154
|
}
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
}
|
|
3155
|
+
const assumed = consoleStoreRls(state, input);
|
|
3156
|
+
if (!assumed.ok) return fail("StoreNotFound", { ref: assumed.reason });
|
|
3079
3157
|
if (input.asGate !== undefined) {
|
|
3080
3158
|
fx.log.info("console.store.sql.asGate", {
|
|
3081
3159
|
operatorId: fx.operator.id,
|
|
@@ -3089,6 +3167,8 @@ function createStoreSql(state: ConsoleState) {
|
|
|
3089
3167
|
revealPii: input.revealPii === true,
|
|
3090
3168
|
tenant: input.tenant,
|
|
3091
3169
|
...(input.asGate !== undefined ? { asGate: input.asGate } : {}),
|
|
3170
|
+
...(input.asUserId !== undefined ? { asUserId: input.asUserId } : {}),
|
|
3171
|
+
...(assumed.rls ? { rls: assumed.rls } : {}),
|
|
3092
3172
|
});
|
|
3093
3173
|
fx.log.info("console.store.sql", {
|
|
3094
3174
|
operatorId: fx.operator.id,
|
|
@@ -3096,6 +3176,7 @@ function createStoreSql(state: ConsoleState) {
|
|
|
3096
3176
|
allowWrite: input.allowWrite === true,
|
|
3097
3177
|
revealPii: input.revealPii === true,
|
|
3098
3178
|
asGate: input.asGate ?? null,
|
|
3179
|
+
asUserId: input.asUserId ?? null,
|
|
3099
3180
|
rowCount: result.rows.length,
|
|
3100
3181
|
});
|
|
3101
3182
|
return result;
|
|
@@ -3311,7 +3392,7 @@ function createStorePreview(state: ConsoleState) {
|
|
|
3311
3392
|
dryRun: true as const,
|
|
3312
3393
|
willNotFire: preview.willNotFire,
|
|
3313
3394
|
wouldHaveFired: [...preview.wouldHaveFired],
|
|
3314
|
-
at: state.now(),
|
|
3395
|
+
at: isoAt(state.now()),
|
|
3315
3396
|
};
|
|
3316
3397
|
} catch (err) {
|
|
3317
3398
|
if (err instanceof DryRunWriteIsolationError) {
|
|
@@ -3367,7 +3448,7 @@ function createVaultCreate(state: ConsoleState) {
|
|
|
3367
3448
|
ok: true as const,
|
|
3368
3449
|
name: result.name,
|
|
3369
3450
|
fingerprint: result.fingerprint,
|
|
3370
|
-
at: state.now(),
|
|
3451
|
+
at: isoAt(state.now()),
|
|
3371
3452
|
};
|
|
3372
3453
|
} catch (err) {
|
|
3373
3454
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -3407,7 +3488,7 @@ function createVaultSet(state: ConsoleState) {
|
|
|
3407
3488
|
ok: true as const,
|
|
3408
3489
|
name: result.name,
|
|
3409
3490
|
fingerprint: result.fingerprint,
|
|
3410
|
-
at: state.now(),
|
|
3491
|
+
at: isoAt(state.now()),
|
|
3411
3492
|
};
|
|
3412
3493
|
} catch (err) {
|
|
3413
3494
|
return fail("VaultNotFound", {
|
|
@@ -3445,7 +3526,7 @@ function createVaultRotate(state: ConsoleState) {
|
|
|
3445
3526
|
ok: true as const,
|
|
3446
3527
|
name: result.name,
|
|
3447
3528
|
fingerprint: result.fingerprint,
|
|
3448
|
-
at: state.now(),
|
|
3529
|
+
at: isoAt(state.now()),
|
|
3449
3530
|
};
|
|
3450
3531
|
} catch (err) {
|
|
3451
3532
|
return fail("VaultNotFound", {
|
|
@@ -3491,7 +3572,7 @@ function createVaultRotateMaster(state: ConsoleState) {
|
|
|
3491
3572
|
kekVersion: result.kekVersion,
|
|
3492
3573
|
remaining: result.remaining,
|
|
3493
3574
|
masterKey: result.masterKey,
|
|
3494
|
-
at: state.now(),
|
|
3575
|
+
at: isoAt(state.now()),
|
|
3495
3576
|
};
|
|
3496
3577
|
} catch (err) {
|
|
3497
3578
|
return mapVaultOperatorError(err);
|
|
@@ -4009,7 +4090,7 @@ function createClockRunNow(state: ConsoleState) {
|
|
|
4009
4090
|
ok: true as const,
|
|
4010
4091
|
name: input.name,
|
|
4011
4092
|
ran: result.ran,
|
|
4012
|
-
at: state.now(),
|
|
4093
|
+
at: isoAt(state.now()),
|
|
4013
4094
|
};
|
|
4014
4095
|
} catch (err) {
|
|
4015
4096
|
if (err instanceof ClockResourceNotFoundError) {
|
|
@@ -4039,7 +4120,7 @@ function createClockPause(state: ConsoleState) {
|
|
|
4039
4120
|
ok: true as const,
|
|
4040
4121
|
name: result.name,
|
|
4041
4122
|
status: result.status,
|
|
4042
|
-
at: state.now(),
|
|
4123
|
+
at: isoAt(state.now()),
|
|
4043
4124
|
};
|
|
4044
4125
|
} catch (err) {
|
|
4045
4126
|
if (err instanceof ClockResourceNotFoundError) {
|
|
@@ -4074,7 +4155,7 @@ function createClockEditSchedule(state: ConsoleState) {
|
|
|
4074
4155
|
name: result.name,
|
|
4075
4156
|
effectiveCron: result.effectiveCron,
|
|
4076
4157
|
effectiveEvery: result.effectiveEvery,
|
|
4077
|
-
at: state.now(),
|
|
4158
|
+
at: isoAt(state.now()),
|
|
4078
4159
|
};
|
|
4079
4160
|
} catch (err) {
|
|
4080
4161
|
if (err instanceof ScheduleNotOverridableError) {
|
|
@@ -4109,7 +4190,7 @@ function createClockWakeEarly(state: ConsoleState) {
|
|
|
4109
4190
|
runId: result.runId,
|
|
4110
4191
|
wakeAt: result.wakeAt,
|
|
4111
4192
|
resumed: result.resumed,
|
|
4112
|
-
at: state.now(),
|
|
4193
|
+
at: isoAt(state.now()),
|
|
4113
4194
|
};
|
|
4114
4195
|
} catch (err) {
|
|
4115
4196
|
if (err instanceof ClockResourceNotFoundError) {
|
|
@@ -4186,7 +4267,7 @@ function createChannelReveal(state: ConsoleState) {
|
|
|
4186
4267
|
ok: true as const,
|
|
4187
4268
|
id: revealed.id,
|
|
4188
4269
|
to: revealed.to,
|
|
4189
|
-
at: state.now(),
|
|
4270
|
+
at: isoAt(state.now()),
|
|
4190
4271
|
};
|
|
4191
4272
|
},
|
|
4192
4273
|
});
|
|
@@ -4233,7 +4314,7 @@ function createChannelSendTest(state: ConsoleState) {
|
|
|
4233
4314
|
});
|
|
4234
4315
|
return {
|
|
4235
4316
|
...result,
|
|
4236
|
-
at: state.now(),
|
|
4317
|
+
at: isoAt(state.now()),
|
|
4237
4318
|
};
|
|
4238
4319
|
} catch (err) {
|
|
4239
4320
|
return fail("ChannelNotFound", {
|
|
@@ -181,7 +181,9 @@ describe("resolveInvokeAs", () => {
|
|
|
181
181
|
const resolved = resolveInvokeAs({ asGate: "member" }, IDENTITIES, MANIFEST);
|
|
182
182
|
expect(resolved.ok).toBe(true);
|
|
183
183
|
if (!resolved.ok) return;
|
|
184
|
-
expect(resolved.asUserId).toBe("
|
|
184
|
+
expect(resolved.asUserId).toBe("");
|
|
185
|
+
expect(resolved.principal.userId).toBe("");
|
|
186
|
+
expect(resolved.rls).toEqual({ gate: "member", userId: "", scopes: ["member"] });
|
|
185
187
|
expect([...resolved.principal.scopes]).toEqual(["member"]);
|
|
186
188
|
expect(resolved.principal.verified).toBe(true);
|
|
187
189
|
});
|
|
@@ -14,6 +14,8 @@ import type { AnyFlowDef } from "../../kernel/flow.ts";
|
|
|
14
14
|
import { isJsonResult } from "../../kernel/fx.ts";
|
|
15
15
|
import { isFlowFailure } from "../../kernel/hooks.ts";
|
|
16
16
|
import type { Trigger } from "../../kernel/triggers.ts";
|
|
17
|
+
import type { RlsIdentity } from "../../drivers/pg-rls.ts";
|
|
18
|
+
import { resolveRlsIdentity } from "../../elements/store.ts";
|
|
17
19
|
import type { Manifest } from "../../manifest/types.ts";
|
|
18
20
|
import type { ConsoleIdentity } from "./state.ts";
|
|
19
21
|
|
|
@@ -32,6 +34,8 @@ export interface InvokeUserFlowInput {
|
|
|
32
34
|
* Envelope remask is skipped separately when this is true.
|
|
33
35
|
*/
|
|
34
36
|
readonly revealPii?: boolean;
|
|
37
|
+
/** Same bag as SQL console / browse — stamped onto host `fx.store`. */
|
|
38
|
+
readonly rls?: RlsIdentity;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
/** Resolved Call API invoke-as principal. */
|
|
@@ -42,6 +46,7 @@ export type ResolvedInvokeAs =
|
|
|
42
46
|
readonly asUserId: string;
|
|
43
47
|
readonly asGate: string | null;
|
|
44
48
|
readonly bypassGates: boolean;
|
|
49
|
+
readonly rls: RlsIdentity | null;
|
|
45
50
|
}
|
|
46
51
|
| { readonly ok: false; readonly reason: string };
|
|
47
52
|
|
|
@@ -75,6 +80,12 @@ export function resolveInvokeAs(
|
|
|
75
80
|
asUserId: identity.id,
|
|
76
81
|
asGate: asGate ?? null,
|
|
77
82
|
bypassGates: false,
|
|
83
|
+
rls: resolveRlsIdentity({
|
|
84
|
+
asUserId: identity.id,
|
|
85
|
+
asGate: asGate ?? null,
|
|
86
|
+
identities,
|
|
87
|
+
manifest,
|
|
88
|
+
}),
|
|
78
89
|
};
|
|
79
90
|
}
|
|
80
91
|
|
|
@@ -89,6 +100,7 @@ export function resolveInvokeAs(
|
|
|
89
100
|
asUserId: "console:operator",
|
|
90
101
|
asGate: null,
|
|
91
102
|
bypassGates: true,
|
|
103
|
+
rls: null,
|
|
92
104
|
};
|
|
93
105
|
}
|
|
94
106
|
|
|
@@ -103,6 +115,7 @@ export function resolveInvokeAs(
|
|
|
103
115
|
asUserId: "public",
|
|
104
116
|
asGate: "public",
|
|
105
117
|
bypassGates: false,
|
|
118
|
+
rls: resolveRlsIdentity({ asGate: "public", manifest }),
|
|
106
119
|
};
|
|
107
120
|
}
|
|
108
121
|
|
|
@@ -114,13 +127,14 @@ export function resolveInvokeAs(
|
|
|
114
127
|
return {
|
|
115
128
|
ok: true,
|
|
116
129
|
principal: userPrincipal({
|
|
117
|
-
userId:
|
|
130
|
+
userId: "",
|
|
118
131
|
scopes,
|
|
119
132
|
verified: true,
|
|
120
133
|
}),
|
|
121
|
-
asUserId:
|
|
134
|
+
asUserId: "",
|
|
122
135
|
asGate,
|
|
123
136
|
bypassGates: false,
|
|
137
|
+
rls: resolveRlsIdentity({ asGate, manifest }),
|
|
124
138
|
};
|
|
125
139
|
}
|
|
126
140
|
|
|
@@ -353,6 +367,7 @@ export function bindHostInvokeUserFlow(app: InvokeHostApp): ConsoleInvokeUserFlo
|
|
|
353
367
|
runId,
|
|
354
368
|
...(input.bypassGates === true ? { bypassGates: true } : {}),
|
|
355
369
|
...(input.revealPii === true ? { revealPii: true } : {}),
|
|
370
|
+
...(input.rls ? { rls: input.rls } : {}),
|
|
356
371
|
principal: {
|
|
357
372
|
plane: "user",
|
|
358
373
|
userId: input.principal.userId.length > 0 ? input.principal.userId : null,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ISO-8601 UTC instant from a Console clock reading (epoch ms).
|
|
3
|
+
*
|
|
4
|
+
* Mutation receipts (`clock.run-now`, store edit, vault write, …) return
|
|
5
|
+
* this instead of a raw millisecond number so Call API JSON is readable.
|
|
6
|
+
*
|
|
7
|
+
* @param ms - Epoch milliseconds from `state.now()` / `Date.now()`
|
|
8
|
+
*/
|
|
9
|
+
export function isoAt(ms: number): string {
|
|
10
|
+
return new Date(ms).toISOString();
|
|
11
|
+
}
|
|
@@ -7,14 +7,16 @@ export const CONSOLE_CSP: string = [
|
|
|
7
7
|
"default-src 'self'",
|
|
8
8
|
"script-src 'self'",
|
|
9
9
|
"style-src 'self' 'unsafe-inline'",
|
|
10
|
-
"img-src 'self' data:",
|
|
10
|
+
"img-src 'self' data: blob:",
|
|
11
|
+
"media-src 'self' blob:",
|
|
11
12
|
"font-src 'self'",
|
|
12
13
|
"connect-src 'self' ws: wss:",
|
|
13
14
|
"object-src 'none'",
|
|
14
15
|
"base-uri 'self'",
|
|
15
16
|
"form-action 'self'",
|
|
16
17
|
"frame-ancestors 'none'",
|
|
17
|
-
|
|
18
|
+
// Files preview mints blob: URLs for PDF iframes, images, and A/V.
|
|
19
|
+
"frame-src 'self' blob:",
|
|
18
20
|
].join("; ");
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -27,13 +29,14 @@ export const CONSOLE_VITE_DEV_CSP: string = [
|
|
|
27
29
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
|
|
28
30
|
"style-src 'self' 'unsafe-inline'",
|
|
29
31
|
"img-src 'self' data: blob:",
|
|
32
|
+
"media-src 'self' blob:",
|
|
30
33
|
"font-src 'self'",
|
|
31
34
|
"connect-src 'self' ws: wss: http://127.0.0.1:* ws://127.0.0.1:*",
|
|
32
35
|
"object-src 'none'",
|
|
33
36
|
"base-uri 'self'",
|
|
34
37
|
"form-action 'self'",
|
|
35
38
|
"frame-ancestors 'none'",
|
|
36
|
-
"frame-src 'self'",
|
|
39
|
+
"frame-src 'self' blob:",
|
|
37
40
|
].join("; ");
|
|
38
41
|
|
|
39
42
|
/** CSP for sandboxed plugin panel iframes (no operator session reach). */
|