okengine 0.14.1 → 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/package.json +3 -4
- package/site/content/docs/elements/ai.mdx +2 -1
- package/site/content/docs/elements/channel.mdx +1 -0
- package/site/content/docs/elements/clock.mdx +3 -0
- package/site/content/docs/elements/flow.mdx +3 -0
- package/site/content/docs/elements/gate.mdx +25 -22
- package/site/content/docs/elements/signal.mdx +4 -4
- package/site/content/docs/elements/store.mdx +86 -27
- 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/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/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/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/extract.test.ts +409 -33
- package/src/compiler/extract.ts +318 -67
- 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/schema-from-ast.ts +609 -0
- package/src/console/server/bind.ts +2 -2
- package/src/console/server/console.test.ts +3 -0
- package/src/console/server/flows.ts +120 -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/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-BanhLsEY.js → cache-glyph-F1FI122b.js} +1 -1
- 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-BEZDzyYh.js → observability-page-HK9-BO8z.js} +2 -2
- 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/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/traces/http-method.ts +19 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail.test.ts +19 -1
- package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +10 -3
- 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/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 +3 -0
- package/src/docker/recipes/pgdog.ts +2 -0
- 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/types.ts +10 -0
- package/src/elements/clock/declare.ts +26 -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/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/http.ts +20 -3
- package/src/index.ts +10 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +1 -1
- package/src/kernel/adopt-routes.ts +30 -2
- package/src/kernel/app.ts +131 -14
- package/src/kernel/auto-cache.test.ts +8 -8
- package/src/kernel/auto-registry.test.ts +49 -9
- package/src/kernel/boot.test.ts +4 -4
- package/src/kernel/boot.ts +2 -2
- package/src/kernel/effects-stamping.test.ts +3 -3
- package/src/kernel/element-registries.ts +12 -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.ts +23 -0
- 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 +4 -4
- 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/types.ts +13 -0
- package/src/release/measure.ts +2 -2
- 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 +8 -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/collapsible-DYb0xU8C.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-DxDsOd4f.js +0 -1
- package/src/console/ui-next/dist/assets/http-method-CJCBYL2j.js +0 -1
- package/src/console/ui-next/dist/assets/index-Ce6WKWKM.js +0 -66
- package/src/console/ui-next/dist/assets/index-D4Ldtj79.css +0 -2
- 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-DFLFfUUX.js +0 -2
- package/src/console/ui-next/dist/assets/units-page-C0gW6Kdo.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-DuKzqwzW.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({
|
|
@@ -1422,6 +1432,7 @@ const StoreListOut = z.object({
|
|
|
1422
1432
|
piiColumns: z.array(z.string()),
|
|
1423
1433
|
columnDescriptions: z.record(z.string(), z.string()),
|
|
1424
1434
|
rls: z.boolean().optional(),
|
|
1435
|
+
rlsPolicyCount: z.number().int().nonnegative().optional(),
|
|
1425
1436
|
}),
|
|
1426
1437
|
),
|
|
1427
1438
|
replicaLagMs: z.number().nullable(),
|
|
@@ -1445,6 +1456,17 @@ const StoreListOut = z.object({
|
|
|
1445
1456
|
),
|
|
1446
1457
|
});
|
|
1447
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
|
+
|
|
1448
1470
|
const StoreQueryIn = z.object({
|
|
1449
1471
|
ref: z.string().min(1),
|
|
1450
1472
|
child: z.string().optional(),
|
|
@@ -1455,6 +1477,7 @@ const StoreQueryIn = z.object({
|
|
|
1455
1477
|
q: z.string().optional(),
|
|
1456
1478
|
topK: z.number().min(1).max(100).optional(),
|
|
1457
1479
|
revealPii: z.boolean().optional(),
|
|
1480
|
+
...StoreRlsAs,
|
|
1458
1481
|
});
|
|
1459
1482
|
|
|
1460
1483
|
const StoreQueryOut = z.object({
|
|
@@ -1483,6 +1506,7 @@ const StoreQueryOut = z.object({
|
|
|
1483
1506
|
.optional(),
|
|
1484
1507
|
masked: z.boolean(),
|
|
1485
1508
|
routedRole: z.enum(["primary", "replica"]).optional(),
|
|
1509
|
+
rls: StoreRlsOut.optional(),
|
|
1486
1510
|
});
|
|
1487
1511
|
|
|
1488
1512
|
const StoreRevealIn = z.object({
|
|
@@ -1496,7 +1520,7 @@ const StoreRevealIn = z.object({
|
|
|
1496
1520
|
const StoreRevealOut = z.object({
|
|
1497
1521
|
ok: z.literal(true),
|
|
1498
1522
|
value: z.unknown(),
|
|
1499
|
-
at: z.
|
|
1523
|
+
at: z.string(),
|
|
1500
1524
|
});
|
|
1501
1525
|
|
|
1502
1526
|
const StoreFileGetIn = z.object({
|
|
@@ -1527,6 +1551,7 @@ const StoreEditIn = z.object({
|
|
|
1527
1551
|
reason: z.string().optional(),
|
|
1528
1552
|
/** When false/omitted, returns willNotFire without applying. */
|
|
1529
1553
|
commit: z.boolean().optional(),
|
|
1554
|
+
...StoreRlsAs,
|
|
1530
1555
|
});
|
|
1531
1556
|
|
|
1532
1557
|
const StoreEditOut = z.object({
|
|
@@ -1540,7 +1565,8 @@ const StoreEditOut = z.object({
|
|
|
1540
1565
|
resource: z.string(),
|
|
1541
1566
|
}),
|
|
1542
1567
|
),
|
|
1543
|
-
at: z.
|
|
1568
|
+
at: z.string(),
|
|
1569
|
+
rls: StoreRlsOut.optional(),
|
|
1544
1570
|
});
|
|
1545
1571
|
|
|
1546
1572
|
const StoreDeleteIn = z.object({
|
|
@@ -1556,7 +1582,7 @@ const StoreDeleteIn = z.object({
|
|
|
1556
1582
|
const StoreDeleteOut = z.object({
|
|
1557
1583
|
ok: z.literal(true),
|
|
1558
1584
|
deleted: z.number(),
|
|
1559
|
-
at: z.
|
|
1585
|
+
at: z.string(),
|
|
1560
1586
|
});
|
|
1561
1587
|
|
|
1562
1588
|
const StorePurgeIn = z.object({
|
|
@@ -1568,7 +1594,7 @@ const StorePurgeIn = z.object({
|
|
|
1568
1594
|
const StorePurgeOut = z.object({
|
|
1569
1595
|
ok: z.literal(true),
|
|
1570
1596
|
keys: z.array(z.string()),
|
|
1571
|
-
at: z.
|
|
1597
|
+
at: z.string(),
|
|
1572
1598
|
});
|
|
1573
1599
|
|
|
1574
1600
|
const StoreSqlIn = z.object({
|
|
@@ -1578,6 +1604,7 @@ const StoreSqlIn = z.object({
|
|
|
1578
1604
|
allowWrite: z.boolean().optional(),
|
|
1579
1605
|
revealPii: z.boolean().optional(),
|
|
1580
1606
|
asGate: z.string().min(1).optional(),
|
|
1607
|
+
asUserId: z.string().min(1).optional(),
|
|
1581
1608
|
});
|
|
1582
1609
|
|
|
1583
1610
|
const StoreSqlOut = z.object({
|
|
@@ -1585,7 +1612,9 @@ const StoreSqlOut = z.object({
|
|
|
1585
1612
|
masked: z.boolean(),
|
|
1586
1613
|
routedRole: z.enum(["primary", "replica"]),
|
|
1587
1614
|
asGate: z.string().nullable(),
|
|
1615
|
+
asUserId: z.string().nullable(),
|
|
1588
1616
|
gateApplied: z.boolean(),
|
|
1617
|
+
rls: StoreRlsOut.optional(),
|
|
1589
1618
|
});
|
|
1590
1619
|
|
|
1591
1620
|
const StoreSqlStatsIn = z.object({
|
|
@@ -1749,7 +1778,7 @@ const StorePreviewOut = z.object({
|
|
|
1749
1778
|
resource: z.string(),
|
|
1750
1779
|
}),
|
|
1751
1780
|
),
|
|
1752
|
-
at: z.
|
|
1781
|
+
at: z.string(),
|
|
1753
1782
|
});
|
|
1754
1783
|
|
|
1755
1784
|
/**
|
|
@@ -2362,7 +2391,7 @@ function createTracesReplay(state: ConsoleState) {
|
|
|
2362
2391
|
ok: true as const,
|
|
2363
2392
|
rootId: input.rootId,
|
|
2364
2393
|
dryRun,
|
|
2365
|
-
at: Date.now(),
|
|
2394
|
+
at: isoAt(Date.now()),
|
|
2366
2395
|
flow: root.flow,
|
|
2367
2396
|
};
|
|
2368
2397
|
},
|
|
@@ -2443,7 +2472,7 @@ function createSignalsDiscard(state: ConsoleState) {
|
|
|
2443
2472
|
return {
|
|
2444
2473
|
ok: true as const,
|
|
2445
2474
|
discarded: result.discarded,
|
|
2446
|
-
at: state.now(),
|
|
2475
|
+
at: isoAt(state.now()),
|
|
2447
2476
|
};
|
|
2448
2477
|
},
|
|
2449
2478
|
});
|
|
@@ -2517,7 +2546,7 @@ async function runSignalReplay(
|
|
|
2517
2546
|
dryRun: result.dryRun,
|
|
2518
2547
|
results: [...result.results],
|
|
2519
2548
|
wouldHaveFired: [...result.wouldHaveFired],
|
|
2520
|
-
at: state.now(),
|
|
2549
|
+
at: isoAt(state.now()),
|
|
2521
2550
|
};
|
|
2522
2551
|
}
|
|
2523
2552
|
|
|
@@ -2562,7 +2591,7 @@ function createActionPing(state: ConsoleState) {
|
|
|
2562
2591
|
operatorId: fx.operator.id,
|
|
2563
2592
|
note: input.note,
|
|
2564
2593
|
});
|
|
2565
|
-
return { ok: true as const, note: input.note, at: state.now() };
|
|
2594
|
+
return { ok: true as const, note: input.note, at: isoAt(state.now()) };
|
|
2566
2595
|
},
|
|
2567
2596
|
});
|
|
2568
2597
|
}
|
|
@@ -2664,6 +2693,7 @@ function createFlowsInvoke(state: ConsoleState) {
|
|
|
2664
2693
|
...(assumed.bypassGates ? { bypassGates: true } : {}),
|
|
2665
2694
|
...(input.reason !== undefined ? { reason: input.reason } : {}),
|
|
2666
2695
|
...(input.revealPii === true ? { revealPii: true } : {}),
|
|
2696
|
+
...(assumed.rls ? { rls: assumed.rls } : {}),
|
|
2667
2697
|
});
|
|
2668
2698
|
|
|
2669
2699
|
const reveal = input.revealPii === true;
|
|
@@ -2716,6 +2746,11 @@ function createFlowsInvoke(state: ConsoleState) {
|
|
|
2716
2746
|
...(host.durationMs !== undefined ? { durationMs: host.durationMs } : {}),
|
|
2717
2747
|
peakTier,
|
|
2718
2748
|
auditedAt: state.now(),
|
|
2749
|
+
rls: {
|
|
2750
|
+
gate: assumed.rls?.gate ?? null,
|
|
2751
|
+
userId: assumed.rls?.userId ?? "",
|
|
2752
|
+
applied: assumed.rls !== null,
|
|
2753
|
+
},
|
|
2719
2754
|
};
|
|
2720
2755
|
},
|
|
2721
2756
|
});
|
|
@@ -2806,6 +2841,32 @@ function createStoreList(state: ConsoleState) {
|
|
|
2806
2841
|
});
|
|
2807
2842
|
}
|
|
2808
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
|
+
|
|
2809
2870
|
function createStoreQuery(state: ConsoleState) {
|
|
2810
2871
|
return flow("console.store.query", {
|
|
2811
2872
|
plane: "operator",
|
|
@@ -2824,6 +2885,8 @@ function createStoreQuery(state: ConsoleState) {
|
|
|
2824
2885
|
tenant: input.tenant,
|
|
2825
2886
|
});
|
|
2826
2887
|
}
|
|
2888
|
+
const assumed = consoleStoreRls(state, input);
|
|
2889
|
+
if (!assumed.ok) return fail("StoreNotFound", { ref: assumed.reason });
|
|
2827
2890
|
return state.queryStore({
|
|
2828
2891
|
ref: input.ref as ResourceRef,
|
|
2829
2892
|
child: input.child,
|
|
@@ -2834,6 +2897,9 @@ function createStoreQuery(state: ConsoleState) {
|
|
|
2834
2897
|
q: input.q,
|
|
2835
2898
|
topK: input.topK,
|
|
2836
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 } : {}),
|
|
2837
2903
|
});
|
|
2838
2904
|
},
|
|
2839
2905
|
});
|
|
@@ -2869,7 +2935,7 @@ function createStoreReveal(state: ConsoleState) {
|
|
|
2869
2935
|
return {
|
|
2870
2936
|
ok: true as const,
|
|
2871
2937
|
value: row[input.column],
|
|
2872
|
-
at: state.now(),
|
|
2938
|
+
at: isoAt(state.now()),
|
|
2873
2939
|
};
|
|
2874
2940
|
},
|
|
2875
2941
|
});
|
|
@@ -2922,6 +2988,14 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2922
2988
|
const tenantFail = requireTenantIfDeclared(state, input.tenant);
|
|
2923
2989
|
if (tenantFail) return tenantFail;
|
|
2924
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
|
+
|
|
2925
2999
|
if (!input.commit) {
|
|
2926
3000
|
// Return will-not-fire payload without applying — informational confirm.
|
|
2927
3001
|
const preview = await state.editStore(
|
|
@@ -2932,6 +3006,7 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2932
3006
|
id: input.id,
|
|
2933
3007
|
key: input.key,
|
|
2934
3008
|
patch: input.patch,
|
|
3009
|
+
...rlsFields,
|
|
2935
3010
|
},
|
|
2936
3011
|
{ dryRun: true },
|
|
2937
3012
|
);
|
|
@@ -2941,7 +3016,8 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2941
3016
|
applied: false,
|
|
2942
3017
|
willNotFire: preview.willNotFire,
|
|
2943
3018
|
wouldHaveFired: [...preview.wouldHaveFired],
|
|
2944
|
-
at: state.now(),
|
|
3019
|
+
at: isoAt(state.now()),
|
|
3020
|
+
...(preview.rls ? { rls: preview.rls } : {}),
|
|
2945
3021
|
};
|
|
2946
3022
|
}
|
|
2947
3023
|
|
|
@@ -2962,6 +3038,7 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2962
3038
|
id: input.id,
|
|
2963
3039
|
key: input.key,
|
|
2964
3040
|
patch: input.patch,
|
|
3041
|
+
...rlsFields,
|
|
2965
3042
|
},
|
|
2966
3043
|
{ dryRun: false },
|
|
2967
3044
|
);
|
|
@@ -2978,7 +3055,8 @@ function createStoreEdit(state: ConsoleState) {
|
|
|
2978
3055
|
applied: result.applied,
|
|
2979
3056
|
willNotFire: result.willNotFire,
|
|
2980
3057
|
wouldHaveFired: [...result.wouldHaveFired],
|
|
2981
|
-
at: state.now(),
|
|
3058
|
+
at: isoAt(state.now()),
|
|
3059
|
+
...(result.rls ? { rls: result.rls } : {}),
|
|
2982
3060
|
};
|
|
2983
3061
|
},
|
|
2984
3062
|
});
|
|
@@ -3018,7 +3096,7 @@ function createStoreDelete(state: ConsoleState) {
|
|
|
3018
3096
|
return {
|
|
3019
3097
|
ok: true as const,
|
|
3020
3098
|
deleted: result.deleted,
|
|
3021
|
-
at: state.now(),
|
|
3099
|
+
at: isoAt(state.now()),
|
|
3022
3100
|
};
|
|
3023
3101
|
},
|
|
3024
3102
|
});
|
|
@@ -3050,7 +3128,7 @@ function createStorePurgeCache(state: ConsoleState) {
|
|
|
3050
3128
|
return {
|
|
3051
3129
|
ok: true as const,
|
|
3052
3130
|
keys: [...result.keys],
|
|
3053
|
-
at: state.now(),
|
|
3131
|
+
at: isoAt(state.now()),
|
|
3054
3132
|
};
|
|
3055
3133
|
},
|
|
3056
3134
|
});
|
|
@@ -3074,9 +3152,8 @@ function createStoreSql(state: ConsoleState) {
|
|
|
3074
3152
|
tenant: input.tenant,
|
|
3075
3153
|
});
|
|
3076
3154
|
}
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
}
|
|
3155
|
+
const assumed = consoleStoreRls(state, input);
|
|
3156
|
+
if (!assumed.ok) return fail("StoreNotFound", { ref: assumed.reason });
|
|
3080
3157
|
if (input.asGate !== undefined) {
|
|
3081
3158
|
fx.log.info("console.store.sql.asGate", {
|
|
3082
3159
|
operatorId: fx.operator.id,
|
|
@@ -3090,6 +3167,8 @@ function createStoreSql(state: ConsoleState) {
|
|
|
3090
3167
|
revealPii: input.revealPii === true,
|
|
3091
3168
|
tenant: input.tenant,
|
|
3092
3169
|
...(input.asGate !== undefined ? { asGate: input.asGate } : {}),
|
|
3170
|
+
...(input.asUserId !== undefined ? { asUserId: input.asUserId } : {}),
|
|
3171
|
+
...(assumed.rls ? { rls: assumed.rls } : {}),
|
|
3093
3172
|
});
|
|
3094
3173
|
fx.log.info("console.store.sql", {
|
|
3095
3174
|
operatorId: fx.operator.id,
|
|
@@ -3097,6 +3176,7 @@ function createStoreSql(state: ConsoleState) {
|
|
|
3097
3176
|
allowWrite: input.allowWrite === true,
|
|
3098
3177
|
revealPii: input.revealPii === true,
|
|
3099
3178
|
asGate: input.asGate ?? null,
|
|
3179
|
+
asUserId: input.asUserId ?? null,
|
|
3100
3180
|
rowCount: result.rows.length,
|
|
3101
3181
|
});
|
|
3102
3182
|
return result;
|
|
@@ -3312,7 +3392,7 @@ function createStorePreview(state: ConsoleState) {
|
|
|
3312
3392
|
dryRun: true as const,
|
|
3313
3393
|
willNotFire: preview.willNotFire,
|
|
3314
3394
|
wouldHaveFired: [...preview.wouldHaveFired],
|
|
3315
|
-
at: state.now(),
|
|
3395
|
+
at: isoAt(state.now()),
|
|
3316
3396
|
};
|
|
3317
3397
|
} catch (err) {
|
|
3318
3398
|
if (err instanceof DryRunWriteIsolationError) {
|
|
@@ -3368,7 +3448,7 @@ function createVaultCreate(state: ConsoleState) {
|
|
|
3368
3448
|
ok: true as const,
|
|
3369
3449
|
name: result.name,
|
|
3370
3450
|
fingerprint: result.fingerprint,
|
|
3371
|
-
at: state.now(),
|
|
3451
|
+
at: isoAt(state.now()),
|
|
3372
3452
|
};
|
|
3373
3453
|
} catch (err) {
|
|
3374
3454
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -3408,7 +3488,7 @@ function createVaultSet(state: ConsoleState) {
|
|
|
3408
3488
|
ok: true as const,
|
|
3409
3489
|
name: result.name,
|
|
3410
3490
|
fingerprint: result.fingerprint,
|
|
3411
|
-
at: state.now(),
|
|
3491
|
+
at: isoAt(state.now()),
|
|
3412
3492
|
};
|
|
3413
3493
|
} catch (err) {
|
|
3414
3494
|
return fail("VaultNotFound", {
|
|
@@ -3446,7 +3526,7 @@ function createVaultRotate(state: ConsoleState) {
|
|
|
3446
3526
|
ok: true as const,
|
|
3447
3527
|
name: result.name,
|
|
3448
3528
|
fingerprint: result.fingerprint,
|
|
3449
|
-
at: state.now(),
|
|
3529
|
+
at: isoAt(state.now()),
|
|
3450
3530
|
};
|
|
3451
3531
|
} catch (err) {
|
|
3452
3532
|
return fail("VaultNotFound", {
|
|
@@ -3492,7 +3572,7 @@ function createVaultRotateMaster(state: ConsoleState) {
|
|
|
3492
3572
|
kekVersion: result.kekVersion,
|
|
3493
3573
|
remaining: result.remaining,
|
|
3494
3574
|
masterKey: result.masterKey,
|
|
3495
|
-
at: state.now(),
|
|
3575
|
+
at: isoAt(state.now()),
|
|
3496
3576
|
};
|
|
3497
3577
|
} catch (err) {
|
|
3498
3578
|
return mapVaultOperatorError(err);
|
|
@@ -4010,7 +4090,7 @@ function createClockRunNow(state: ConsoleState) {
|
|
|
4010
4090
|
ok: true as const,
|
|
4011
4091
|
name: input.name,
|
|
4012
4092
|
ran: result.ran,
|
|
4013
|
-
at: state.now(),
|
|
4093
|
+
at: isoAt(state.now()),
|
|
4014
4094
|
};
|
|
4015
4095
|
} catch (err) {
|
|
4016
4096
|
if (err instanceof ClockResourceNotFoundError) {
|
|
@@ -4040,7 +4120,7 @@ function createClockPause(state: ConsoleState) {
|
|
|
4040
4120
|
ok: true as const,
|
|
4041
4121
|
name: result.name,
|
|
4042
4122
|
status: result.status,
|
|
4043
|
-
at: state.now(),
|
|
4123
|
+
at: isoAt(state.now()),
|
|
4044
4124
|
};
|
|
4045
4125
|
} catch (err) {
|
|
4046
4126
|
if (err instanceof ClockResourceNotFoundError) {
|
|
@@ -4075,7 +4155,7 @@ function createClockEditSchedule(state: ConsoleState) {
|
|
|
4075
4155
|
name: result.name,
|
|
4076
4156
|
effectiveCron: result.effectiveCron,
|
|
4077
4157
|
effectiveEvery: result.effectiveEvery,
|
|
4078
|
-
at: state.now(),
|
|
4158
|
+
at: isoAt(state.now()),
|
|
4079
4159
|
};
|
|
4080
4160
|
} catch (err) {
|
|
4081
4161
|
if (err instanceof ScheduleNotOverridableError) {
|
|
@@ -4110,7 +4190,7 @@ function createClockWakeEarly(state: ConsoleState) {
|
|
|
4110
4190
|
runId: result.runId,
|
|
4111
4191
|
wakeAt: result.wakeAt,
|
|
4112
4192
|
resumed: result.resumed,
|
|
4113
|
-
at: state.now(),
|
|
4193
|
+
at: isoAt(state.now()),
|
|
4114
4194
|
};
|
|
4115
4195
|
} catch (err) {
|
|
4116
4196
|
if (err instanceof ClockResourceNotFoundError) {
|
|
@@ -4187,7 +4267,7 @@ function createChannelReveal(state: ConsoleState) {
|
|
|
4187
4267
|
ok: true as const,
|
|
4188
4268
|
id: revealed.id,
|
|
4189
4269
|
to: revealed.to,
|
|
4190
|
-
at: state.now(),
|
|
4270
|
+
at: isoAt(state.now()),
|
|
4191
4271
|
};
|
|
4192
4272
|
},
|
|
4193
4273
|
});
|
|
@@ -4234,7 +4314,7 @@ function createChannelSendTest(state: ConsoleState) {
|
|
|
4234
4314
|
});
|
|
4235
4315
|
return {
|
|
4236
4316
|
...result,
|
|
4237
|
-
at: state.now(),
|
|
4317
|
+
at: isoAt(state.now()),
|
|
4238
4318
|
};
|
|
4239
4319
|
} catch (err) {
|
|
4240
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). */
|