okengine 0.14.1 → 0.16.0
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 +9 -0
- package/site/content/docs/elements/gate.mdx +80 -22
- package/site/content/docs/elements/signal.mdx +4 -4
- package/site/content/docs/elements/store.mdx +84 -27
- package/site/content/docs/elements/vault.mdx +4 -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 +28 -21
- package/site/content/docs/reference/fx.mdx +29 -18
- package/site/content/docs/reference/security.md +2 -2
- package/src/auth/api-key-sql.test.ts +47 -0
- package/src/auth/api-key-sql.ts +254 -0
- package/src/auth/api-keys.ts +273 -14
- package/src/auth/auth.test.ts +56 -0
- package/src/auth/bindings.ts +14 -5
- package/src/auth/config.ts +5 -5
- package/src/auth/cross-plane.ts +10 -3
- package/src/auth/index.ts +25 -1
- package/src/auth/schema.ts +8 -0
- 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 +40 -2
- package/src/cli/attach-host-console.ts +9 -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 +17 -2
- 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/access.test.ts +116 -8
- package/src/console/server/access.ts +70 -23
- package/src/console/server/app.ts +1 -0
- package/src/console/server/bind.ts +2 -2
- package/src/console/server/console.test.ts +3 -0
- package/src/console/server/dev-identities.test.ts +127 -0
- package/src/console/server/dev-identities.ts +229 -0
- package/src/console/server/flows-invoke.test.ts +21 -4
- package/src/console/server/flows.ts +233 -98
- package/src/console/server/gates.test.ts +24 -0
- package/src/console/server/gates.ts +8 -21
- package/src/console/server/index.ts +1 -0
- 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/live.test.ts +26 -1
- package/src/console/server/live.ts +4 -2
- package/src/console/server/operator-db.ts +2 -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 +37 -55
- package/src/console/server/store.test.ts +7 -4
- package/src/console/server/store.ts +142 -58
- package/src/console/ui-next/dist/assets/access-page-CAGHrA9H.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +1 -0
- package/src/console/ui-next/dist/assets/{duration-tone-oiRxPVsZ.js → duration-tone-sC3lGABz.js} +1 -1
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-B-OUtiAu.js +1 -0
- package/src/console/ui-next/dist/assets/{highlighted-json-CvDPvveV.js → highlighted-json-Awq7gYdu.js} +1 -1
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +1 -0
- package/src/console/ui-next/dist/assets/index-CGoZkILK.js +66 -0
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +2 -0
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +1 -0
- package/src/console/ui-next/dist/assets/observability-page-BDyXalNR.js +4 -0
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +1 -0
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +1 -0
- package/src/console/ui-next/dist/assets/{skeleton-CL_X0GCj.js → skeleton-D-czQJT6.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-Xh8Kn3rx.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-DkOXA12R.js +54 -0
- package/src/console/ui-next/dist/assets/units-page-Dpk40kOQ.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-Cl79j_ku.js → use-vault-list-uk4WVboC.js} +1 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +1 -0
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +1 -0
- package/src/console/ui-next/dist/assets/vault-page-B1dB9Ft0.js +2 -0
- package/src/console/ui-next/dist/index.html +12 -10
- package/src/console/ui-next/index.html +3 -3
- package/src/console/ui-next/src/client.ts +202 -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/shell/app-sidebar.tsx +2 -0
- package/src/console/ui-next/src/components/shell/command-items.test.ts +1 -0
- package/src/console/ui-next/src/components/shell/command-items.ts +8 -0
- package/src/console/ui-next/src/components/shell/shell-layout.tsx +2 -1
- package/src/console/ui-next/src/components/ui/kbd.tsx +2 -2
- package/src/console/ui-next/src/components/ui/sheet-form.tsx +8 -3
- package/src/console/ui-next/src/features/access/access-page.tsx +347 -0
- package/src/console/ui-next/src/features/access/data/use-access.ts +23 -0
- package/src/console/ui-next/src/features/access/detail/access-detail.tsx +552 -0
- package/src/console/ui-next/src/features/access/explorer/access-list.tsx +125 -0
- package/src/console/ui-next/src/features/access/lib/format-when.test.ts +139 -0
- package/src/console/ui-next/src/features/access/lib/format-when.ts +296 -0
- package/src/console/ui-next/src/features/access/lib/scope-groups.test.ts +34 -0
- package/src/console/ui-next/src/features/access/lib/scope-groups.ts +40 -0
- package/src/console/ui-next/src/features/access/sheets/access-allow-fields.tsx +236 -0
- package/src/console/ui-next/src/features/access/sheets/access-create-sheet.tsx +316 -0
- package/src/console/ui-next/src/features/access/sheets/access-edit-sheet.tsx +240 -0
- package/src/console/ui-next/src/features/access/sheets/access-expiry-fields.tsx +66 -0
- package/src/console/ui-next/src/features/access/sheets/access-refresh-sheet.tsx +104 -0
- package/src/console/ui-next/src/features/access/sheets/access-scope-field.tsx +115 -0
- package/src/console/ui-next/src/features/access/sheets/access-secret-sheet.tsx +89 -0
- package/src/console/ui-next/src/features/access/sheets/access-sheet-search.tsx +49 -0
- package/src/console/ui-next/src/features/access/state/access-selection.ts +84 -0
- package/src/console/ui-next/src/features/auth/auth-redirect.test.ts +5 -0
- package/src/console/ui-next/src/features/auth/auth-redirect.ts +18 -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/not-found/not-found-page.tsx +1 -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/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/console/ui-next/src/lib/document-meta.test.ts +1 -0
- package/src/console/ui-next/src/lib/document-meta.ts +2 -1
- package/src/console/ui-next/src/lib/last-module-search.test.ts +1 -0
- package/src/console/ui-next/src/lib/last-module-search.ts +2 -1
- package/src/console/ui-next/src/lib/shortcut.test.ts +2 -0
- package/src/console/ui-next/src/lib/shortcut.ts +3 -0
- package/src/console/ui-next/src/router.tsx +10 -1
- package/src/console/ui-next/ui-next-seed-app-schema.ts +88 -37
- package/src/console/ui-next/ui-next-seed-store.ts +43 -15
- package/src/console/xss.gate.test.ts +1 -0
- 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 +38 -4
- package/src/elements/gate/flatten.ts +1 -1
- package/src/elements/gate/runtime.ts +1 -1
- package/src/elements/store/cache.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 +18 -0
- package/src/elements/store/schema-decl.test.ts +37 -0
- package/src/elements/store/schema-decl.ts +260 -41
- 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-select.types.test.ts +71 -0
- package/src/elements/store/sql-session.ts +135 -35
- package/src/elements/store/upsert-app.test.ts +1 -1
- package/src/elements/store.ts +17 -0
- package/src/http.ts +20 -3
- package/src/index.ts +11 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +1 -1
- package/src/kernel/adopt-routes.ts +30 -2
- package/src/kernel/api-key-host-persist.test.ts +143 -0
- package/src/kernel/app.ts +145 -16
- package/src/kernel/auth-resolve.ts +10 -5
- package/src/kernel/auto-cache.test.ts +8 -8
- package/src/kernel/auto-registry.test.ts +49 -9
- package/src/kernel/boot.test.ts +5 -5
- 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-auth-keys.test.ts +88 -0
- package/src/kernel/fx-auth-keys.ts +198 -0
- package/src/kernel/fx.test.ts +17 -1
- package/src/kernel/fx.ts +59 -18
- 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-api-key.test.ts +192 -7
- package/src/kernel/pipeline.test.ts +2 -2
- package/src/kernel/pipeline.ts +4 -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 +22 -3
- package/src/release/build-lib.ts +1 -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/cache-glyph-BanhLsEY.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-bqkxMrJH.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DYb0xU8C.js +0 -1
- package/src/console/ui-next/dist/assets/confirm-sheet-DDCRmG62.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-HjTnVQoR.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/link-DF7SZ9Ek.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-BEZDzyYh.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-Cgzuv4k1.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DO4IsVqv.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
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default invoke-as identities — ten rungs from owner to guest.
|
|
3
|
+
*
|
|
4
|
+
* `user_demo` (owner) and `user_member` keep their historic ids so Call API
|
|
5
|
+
* tests and Access fixtures stay stable. Owner scopes follow the Manifest;
|
|
6
|
+
* lower rungs intersect a named profile with that catalog. Keel (`app ===
|
|
7
|
+
* "keel"`) always unions {@link KEEL_SCOPES} so seeding is not missing a
|
|
8
|
+
* declared Gate. No leftover app catalog is invented for other apps.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { setRoleGrants, upsertRole, type RoleStore } from "../../auth/index.ts";
|
|
12
|
+
import type { Manifest } from "../../manifest/types.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Every Keel user-plane scope — `gate.policy("member")` plus `gate.scope`.
|
|
16
|
+
* Seeded onto the owner → guest ladder when the Manifest app is `keel`.
|
|
17
|
+
*/
|
|
18
|
+
export const KEEL_SCOPES = [
|
|
19
|
+
"member",
|
|
20
|
+
"task:write",
|
|
21
|
+
"comment:write",
|
|
22
|
+
"files:write",
|
|
23
|
+
"project:admin",
|
|
24
|
+
"member:admin",
|
|
25
|
+
"webhook:admin",
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
/** One seeded development identity. */
|
|
29
|
+
export interface SeededDevIdentity {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly email: string;
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly status: "active";
|
|
34
|
+
readonly scopes: readonly string[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Stable person for one authorization rung. */
|
|
38
|
+
export interface DevIdentityPerson {
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly email: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/** Workspace / Access role label, owner → guest. */
|
|
43
|
+
readonly role: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Ten people, owner → guest. Demo and Member keep historic ids.
|
|
48
|
+
*/
|
|
49
|
+
export const DEV_IDENTITY_LADDER = [
|
|
50
|
+
{ id: "user_demo", email: "demo@example.com", name: "Demo User", role: "owner" },
|
|
51
|
+
{ id: "user_admin", email: "admin@example.com", name: "Admin", role: "admin" },
|
|
52
|
+
{
|
|
53
|
+
id: "user_workspace",
|
|
54
|
+
email: "workspace@example.com",
|
|
55
|
+
name: "Workspace Admin",
|
|
56
|
+
role: "workspace_admin",
|
|
57
|
+
},
|
|
58
|
+
{ id: "user_pm", email: "pm@example.com", name: "Project Manager", role: "project_manager" },
|
|
59
|
+
{ id: "user_lead", email: "lead@example.com", name: "Lead", role: "lead" },
|
|
60
|
+
{ id: "user_dev", email: "developer@example.com", name: "Developer", role: "developer" },
|
|
61
|
+
{ id: "user_writer", email: "writer@example.com", name: "Contributor", role: "contributor" },
|
|
62
|
+
{ id: "user_member", email: "member@example.com", name: "Member", role: "member" },
|
|
63
|
+
{ id: "user_commenter", email: "commenter@example.com", name: "Commenter", role: "commenter" },
|
|
64
|
+
{ id: "user_guest", email: "guest@example.com", name: "Guest", role: "guest" },
|
|
65
|
+
] as const satisfies readonly DevIdentityPerson[];
|
|
66
|
+
|
|
67
|
+
/** One Keel ladder role and the scopes it holds. */
|
|
68
|
+
export type KeelLadderRole = (typeof DEV_IDENTITY_LADDER)[number]["role"];
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Owner → guest grants. Owner and admin hold {@link KEEL_SCOPES}.
|
|
72
|
+
*/
|
|
73
|
+
export const KEEL_LADDER_GRANTS: Readonly<Record<KeelLadderRole, readonly string[]>> = {
|
|
74
|
+
owner: KEEL_SCOPES,
|
|
75
|
+
admin: KEEL_SCOPES,
|
|
76
|
+
workspace_admin: [
|
|
77
|
+
"member",
|
|
78
|
+
"task:write",
|
|
79
|
+
"comment:write",
|
|
80
|
+
"files:write",
|
|
81
|
+
"project:admin",
|
|
82
|
+
"member:admin",
|
|
83
|
+
],
|
|
84
|
+
project_manager: ["member", "task:write", "comment:write", "files:write", "project:admin"],
|
|
85
|
+
lead: ["member", "task:write", "comment:write", "project:admin"],
|
|
86
|
+
developer: ["member", "task:write", "comment:write", "files:write"],
|
|
87
|
+
contributor: ["member", "task:write", "comment:write"],
|
|
88
|
+
member: ["member"],
|
|
89
|
+
commenter: ["member", "comment:write"],
|
|
90
|
+
guest: [],
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/** `*` = every catalog scope (owner). Other rungs follow {@link KEEL_LADDER_GRANTS}. */
|
|
94
|
+
const LADDER_SCOPE_PROFILES: readonly (readonly string[] | "*")[] = [
|
|
95
|
+
"*",
|
|
96
|
+
...DEV_IDENTITY_LADDER.slice(1).map((person) => KEEL_LADDER_GRANTS[person.role]),
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Whether this Manifest is the Keel example (full scope seed applies).
|
|
101
|
+
*
|
|
102
|
+
* @param manifest - Optional Manifest
|
|
103
|
+
*/
|
|
104
|
+
export function isKeelManifest(manifest?: Manifest | null): boolean {
|
|
105
|
+
return manifest?.app === "keel";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Application scopes implied by a Manifest — gate `scopes`, scoped gate
|
|
110
|
+
* ids, and flow gate refs. Always includes `member`.
|
|
111
|
+
*
|
|
112
|
+
* @param manifest - Optional Manifest
|
|
113
|
+
*/
|
|
114
|
+
export function demoScopesFromManifest(manifest?: Manifest | null): string[] {
|
|
115
|
+
const scopes = new Set<string>(["member"]);
|
|
116
|
+
if (isKeelManifest(manifest)) {
|
|
117
|
+
for (const scope of KEEL_SCOPES) scopes.add(scope);
|
|
118
|
+
}
|
|
119
|
+
if (!manifest) return [...scopes].sort();
|
|
120
|
+
for (const [gateId, gate] of Object.entries(manifest.gates ?? {})) {
|
|
121
|
+
for (const scope of gate.scopes ?? []) scopes.add(scope);
|
|
122
|
+
if (gateId.includes(":") && !gateId.startsWith("rate:")) scopes.add(gateId);
|
|
123
|
+
}
|
|
124
|
+
for (const flow of Object.values(manifest.flows ?? {})) {
|
|
125
|
+
for (const gate of flow.gates ?? []) {
|
|
126
|
+
if (gate.includes(":") && !gate.startsWith("rate:")) scopes.add(gate);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return [...scopes].sort();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Scopes for one ladder rung — owner is the full catalog; others intersect
|
|
134
|
+
* their profile. `member` stays on every signed-in rung.
|
|
135
|
+
*
|
|
136
|
+
* @param rung - 0 (owner) … 9 (guest)
|
|
137
|
+
* @param catalog - Manifest-derived scopes
|
|
138
|
+
*/
|
|
139
|
+
export function scopesForDevIdentityRung(rung: number, catalog: readonly string[]): string[] {
|
|
140
|
+
const profile = LADDER_SCOPE_PROFILES[rung];
|
|
141
|
+
if (profile === undefined) return [];
|
|
142
|
+
if (profile === "*") return [...catalog].sort((a, b) => a.localeCompare(b));
|
|
143
|
+
const allowed = new Set(catalog);
|
|
144
|
+
return [...new Set(profile.filter((scope) => scope === "member" || allowed.has(scope)))].sort(
|
|
145
|
+
(a, b) => a.localeCompare(b),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Default development identities for the invoke-as picker.
|
|
151
|
+
*
|
|
152
|
+
* @param manifest - Optional Manifest used to derive application scopes
|
|
153
|
+
*/
|
|
154
|
+
export function defaultDevIdentities(manifest?: Manifest | null): SeededDevIdentity[] {
|
|
155
|
+
const catalog = demoScopesFromManifest(manifest);
|
|
156
|
+
return DEV_IDENTITY_LADDER.map((person, rung) => ({
|
|
157
|
+
id: person.id,
|
|
158
|
+
email: person.email,
|
|
159
|
+
name: person.name,
|
|
160
|
+
status: "active",
|
|
161
|
+
scopes: scopesForDevIdentityRung(rung, catalog),
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Whether the live list is still the built-in ladder (safe to refresh).
|
|
167
|
+
*
|
|
168
|
+
* @param identities - Live identity list
|
|
169
|
+
*/
|
|
170
|
+
export function isDefaultIdentitySeed(identities: readonly { readonly id: string }[]): boolean {
|
|
171
|
+
if (identities.length !== DEV_IDENTITY_LADDER.length) return false;
|
|
172
|
+
const ids = new Set(identities.map((row) => row.id));
|
|
173
|
+
return DEV_IDENTITY_LADDER.every((person) => ids.has(person.id));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Signed-in ladder ids (guest excluded) — default `role_member` holders.
|
|
178
|
+
*/
|
|
179
|
+
export function defaultMemberIdentityIds(): string[] {
|
|
180
|
+
return DEV_IDENTITY_LADDER.filter((person) => person.role !== "guest").map((person) => person.id);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Replace the default ladder when a Manifest arrives.
|
|
185
|
+
*
|
|
186
|
+
* @param identities - Live identity list
|
|
187
|
+
* @param manifest - New Manifest
|
|
188
|
+
*/
|
|
189
|
+
export function refreshSeededIdentities(
|
|
190
|
+
identities: Array<{
|
|
191
|
+
id: string;
|
|
192
|
+
email: string;
|
|
193
|
+
name: string;
|
|
194
|
+
status: "active" | "disabled";
|
|
195
|
+
scopes: readonly string[];
|
|
196
|
+
}>,
|
|
197
|
+
manifest: Manifest | null,
|
|
198
|
+
): void {
|
|
199
|
+
if (!isDefaultIdentitySeed(identities)) return;
|
|
200
|
+
const next = defaultDevIdentities(manifest);
|
|
201
|
+
identities.splice(0, identities.length, ...next);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Seed Access roles for Keel — every {@link KEEL_SCOPES} pair lands on the
|
|
206
|
+
* owner / admin rung; lower rungs use {@link KEEL_LADDER_GRANTS}.
|
|
207
|
+
*
|
|
208
|
+
* @param roles - Role store
|
|
209
|
+
* @param roleMembers - roleId → principal ids
|
|
210
|
+
*/
|
|
211
|
+
export function seedKeelAccessRoles(roles: RoleStore, roleMembers: Map<string, string[]>): void {
|
|
212
|
+
for (const person of DEV_IDENTITY_LADDER) {
|
|
213
|
+
const roleId = `role_${person.role}`;
|
|
214
|
+
upsertRole(roles, {
|
|
215
|
+
id: roleId,
|
|
216
|
+
name: person.role,
|
|
217
|
+
plane: "user",
|
|
218
|
+
description:
|
|
219
|
+
person.role === "owner"
|
|
220
|
+
? "Full workspace authorization"
|
|
221
|
+
: person.role === "guest"
|
|
222
|
+
? "Least authorization — no write scopes"
|
|
223
|
+
: `Keel ${person.role.replaceAll("_", " ")}`,
|
|
224
|
+
});
|
|
225
|
+
setRoleGrants(roles, roleId, KEEL_LADDER_GRANTS[person.role]);
|
|
226
|
+
roleMembers.set(roleId, person.role === "guest" ? [] : [person.id]);
|
|
227
|
+
}
|
|
228
|
+
roleMembers.set("role_member", defaultMemberIdentityIds());
|
|
229
|
+
}
|
|
@@ -15,12 +15,29 @@ import { http } from "../../kernel/triggers.ts";
|
|
|
15
15
|
import { field, store } from "../../elements/store.ts";
|
|
16
16
|
import { PII_MASK } from "../../elements/store/classify.ts";
|
|
17
17
|
import { createTestApp } from "../../test/create-test-app.ts";
|
|
18
|
+
import type { Manifest } from "../../manifest/types.ts";
|
|
18
19
|
import { FLOWS_TEST_MANIFEST } from "../ui-next/src/features/flows/fixture.ts";
|
|
19
20
|
import { bindHostInvokeUserFlow } from "./invoke-user-flow.ts";
|
|
20
21
|
import { startConsoleApp } from "./serve.ts";
|
|
21
22
|
import { setManifest } from "./state.ts";
|
|
22
23
|
import type { InvokeUserFlowInput } from "./invoke-user-flow.ts";
|
|
23
24
|
|
|
25
|
+
/** Fixture plus the booking gate the host actually enforces. */
|
|
26
|
+
const BOOKING_INVOKE_MANIFEST: Manifest = {
|
|
27
|
+
...FLOWS_TEST_MANIFEST,
|
|
28
|
+
gates: {
|
|
29
|
+
member: { kind: "policy", scopes: ["member"] },
|
|
30
|
+
"booking:create": { kind: "policy", scopes: ["booking:create"] },
|
|
31
|
+
},
|
|
32
|
+
flows: {
|
|
33
|
+
...FLOWS_TEST_MANIFEST.flows,
|
|
34
|
+
"bookings.create": {
|
|
35
|
+
...FLOWS_TEST_MANIFEST.flows!["bookings.create"]!,
|
|
36
|
+
gates: ["member", "booking:create"],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
24
41
|
const memoryDrivers = {
|
|
25
42
|
store: { kv: { dev: "memory", test: "memory", prod: "memory" } },
|
|
26
43
|
signal: { dev: "memory", test: "memory", prod: "memory" },
|
|
@@ -147,11 +164,11 @@ describe("console flows invoke", () => {
|
|
|
147
164
|
secret: "test-secret-flows",
|
|
148
165
|
silentClaim: true,
|
|
149
166
|
production: false,
|
|
150
|
-
manifest:
|
|
167
|
+
manifest: BOOKING_INVOKE_MANIFEST,
|
|
151
168
|
});
|
|
152
169
|
const host = await bootInvokeHost();
|
|
153
170
|
try {
|
|
154
|
-
setManifest(handle.state,
|
|
171
|
+
setManifest(handle.state, BOOKING_INVOKE_MANIFEST);
|
|
155
172
|
handle.state.invokeUserFlow = bindHostInvokeUserFlow(host);
|
|
156
173
|
const auth = await claimOperator(handle);
|
|
157
174
|
|
|
@@ -214,12 +231,12 @@ describe("console flows invoke", () => {
|
|
|
214
231
|
secret: "test-secret-flows-adv",
|
|
215
232
|
silentClaim: true,
|
|
216
233
|
production: false,
|
|
217
|
-
manifest:
|
|
234
|
+
manifest: BOOKING_INVOKE_MANIFEST,
|
|
218
235
|
});
|
|
219
236
|
const host = await bootInvokeHost();
|
|
220
237
|
const seen: InvokeUserFlowInput[] = [];
|
|
221
238
|
try {
|
|
222
|
-
setManifest(handle.state,
|
|
239
|
+
setManifest(handle.state, BOOKING_INVOKE_MANIFEST);
|
|
223
240
|
const bound = bindHostInvokeUserFlow(host);
|
|
224
241
|
handle.state.invokeUserFlow = async (input) => {
|
|
225
242
|
seen.push(input);
|