okengine 0.2.6 → 0.3.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/AGENTS.md +33 -30
- package/README.md +74 -340
- package/{spec/manifest.v1.schema.json → manifest.v1.schema.json} +40 -9
- package/package.json +47 -44
- package/site/content/docs/ai/llms-txt.mdx +54 -0
- package/site/content/docs/ai/mcp.mdx +123 -0
- package/site/content/docs/ai/meta.json +5 -0
- package/site/content/docs/ai/skills.mdx +53 -0
- package/site/content/docs/console/access.mdx +29 -0
- package/site/content/docs/console/ai.mdx +35 -0
- package/site/content/docs/console/architecture.mdx +35 -0
- package/site/content/docs/console/channels.mdx +37 -0
- package/site/content/docs/console/clock.mdx +31 -0
- package/site/content/docs/console/flows.mdx +31 -0
- package/site/content/docs/console/gates.mdx +35 -0
- package/site/content/docs/console/manifest-diff.mdx +34 -0
- package/site/content/docs/console/meta.json +23 -0
- package/site/content/docs/console/overview.mdx +40 -0
- package/site/content/docs/console/plugins.mdx +41 -0
- package/site/content/docs/console/privacy.mdx +32 -0
- package/site/content/docs/console/runs.mdx +40 -0
- package/site/content/docs/console/signals.mdx +31 -0
- package/site/content/docs/console/store.mdx +32 -0
- package/site/content/docs/console/tenancy.mdx +32 -0
- package/site/content/docs/console/traces.mdx +34 -0
- package/site/content/docs/console/vault.mdx +37 -0
- package/site/content/docs/elements/ai.mdx +180 -0
- package/site/content/docs/elements/channel.mdx +167 -0
- package/site/content/docs/elements/clock.mdx +182 -0
- package/site/content/docs/elements/flow.mdx +288 -0
- package/site/content/docs/elements/gate.mdx +171 -0
- package/site/content/docs/elements/meta.json +5 -0
- package/site/content/docs/elements/signal.mdx +171 -0
- package/site/content/docs/elements/store.mdx +320 -0
- package/site/content/docs/elements/vault.mdx +263 -0
- package/site/content/docs/get-started/basic-usage.mdx +124 -0
- package/site/content/docs/get-started/comparison.mdx +65 -0
- package/site/content/docs/get-started/installation.mdx +113 -0
- package/site/content/docs/get-started/introduction.mdx +123 -0
- package/site/content/docs/get-started/meta.json +5 -0
- package/site/content/docs/index.mdx +63 -0
- package/site/content/docs/meta.json +5 -0
- package/site/content/docs/plugins/compression.mdx +60 -0
- package/site/content/docs/plugins/cors.mdx +92 -0
- package/site/content/docs/plugins/csrf.mdx +96 -0
- package/site/content/docs/plugins/ip-allowlist.mdx +92 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +101 -0
- package/site/content/docs/plugins/meta.json +15 -0
- package/site/content/docs/plugins/security-headers.mdx +136 -0
- package/site/content/docs/reference/cli.md +101 -0
- package/site/content/docs/reference/configuration.mdx +159 -0
- package/site/content/docs/reference/environment-variables.mdx +87 -0
- package/site/content/docs/reference/errors.mdx +80 -0
- package/site/content/docs/reference/fx.mdx +117 -0
- package/site/content/docs/reference/meta.json +5 -0
- package/site/content/docs/reference/plugins.mdx +249 -0
- package/site/content/docs/reference/security.md +63 -0
- package/src/auth/api-keys.ts +2 -5
- package/src/auth/attenuation.ts +2 -6
- package/src/auth/auth.test.ts +56 -31
- package/src/auth/invoke-as.ts +1 -3
- package/src/auth/operator.ts +8 -26
- package/src/auth/planes.ts +2 -7
- package/src/auth/plugin.ts +4 -7
- package/src/auth/roles.ts +1 -5
- package/src/auth/sessions.ts +10 -39
- package/src/cli/args.ts +1 -5
- package/src/cli/ask-dev-mode.ts +40 -0
- package/src/cli/build.ts +1 -2
- package/src/cli/client-add.test.ts +8 -15
- package/src/cli/client-add.ts +5 -14
- package/src/cli/completion.test.ts +1 -5
- package/src/cli/completion.ts +4 -17
- package/src/cli/db-auto-push.test.ts +64 -0
- package/src/cli/db-auto-push.ts +72 -0
- package/src/cli/db.test.ts +189 -0
- package/src/cli/db.ts +456 -0
- package/src/cli/dev-app-runner.ts +2 -8
- package/src/cli/dev-db-push.test.ts +193 -0
- package/src/cli/dev-mode.test.ts +45 -0
- package/src/cli/dev-mode.ts +78 -0
- package/src/cli/dev-schema-sync.test.ts +66 -0
- package/src/cli/dev-schema-sync.ts +139 -0
- package/src/cli/dev.test.ts +264 -15
- package/src/cli/dev.ts +355 -139
- package/src/cli/doc-staleness.test.ts +69 -0
- package/src/cli/docker-cli.test.ts +27 -8
- package/src/cli/docker.ts +11 -3
- package/src/cli/doctor-diff.test.ts +1 -5
- package/src/cli/doctor-diff.ts +17 -46
- package/src/cli/doctor-pii.ts +2 -7
- package/src/cli/doctor.test.ts +26 -4
- package/src/cli/doctor.ts +35 -11
- package/src/cli/drizzle-env.test.ts +67 -0
- package/src/cli/drizzle-env.ts +78 -0
- package/src/cli/ensure-drizzle-config.ts +50 -0
- package/src/cli/eval.ts +4 -14
- package/src/cli/gates-list.ts +1 -4
- package/src/cli/hero-meta.test.ts +17 -19
- package/src/cli/hero-meta.ts +20 -30
- package/src/cli/images.ts +3 -8
- package/src/cli/index.ts +11 -2
- package/src/cli/load-config.images.test.ts +14 -14
- package/src/cli/load-config.ts +47 -47
- package/src/cli/mcp-from-console.ts +1 -4
- package/src/cli/mode.ts +65 -0
- package/src/cli/openbao-bootstrap.test.ts +147 -0
- package/src/cli/openbao-bootstrap.ts +280 -0
- package/src/cli/openbao-restart.integration.test.ts +136 -0
- package/src/cli/ports.test.ts +7 -14
- package/src/cli/ports.ts +7 -5
- package/src/cli/privacy-erase.ts +1 -3
- package/src/cli/registry.ts +75 -25
- package/src/cli/resolve-dev-sql-env.test.ts +48 -0
- package/src/cli/resolve-dev-sql-env.ts +42 -0
- package/src/cli/schema.ts +3 -10
- package/src/cli/stack.ts +8 -10
- package/src/cli/start.ts +4 -15
- package/src/cli/upgrade.ts +1 -4
- package/src/cli/vault-cmd.ts +63 -0
- package/src/client/budget-entry.ts +1 -6
- package/src/client/create.test.ts +6 -12
- package/src/client/create.ts +2 -8
- package/src/client/errors.ts +1 -4
- package/src/client/index.ts +1 -6
- package/src/client/notes-contract.test.ts +4 -13
- package/src/client/transport.ts +9 -30
- package/src/client/types.ts +15 -30
- package/src/compiler/aot.test.ts +2 -9
- package/src/compiler/aot.ts +1 -4
- package/src/compiler/differential.test.ts +3 -11
- package/src/compiler/dynamic.ts +1 -4
- package/src/compiler/effects-infer.ts +8 -34
- package/src/compiler/emit.ts +1 -3
- package/src/compiler/extract.test.ts +136 -30
- package/src/compiler/extract.ts +485 -157
- package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -3
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -3
- package/src/compiler/fixtures/skyport/src/flows/support/index.ts +4 -1
- package/src/compiler/fixtures/skyport.expected.json +24 -83
- package/src/compiler/fixtures/triggers/five-triggers.ts +1 -2
- package/src/compiler/http-parse.ts +2 -9
- package/src/compiler/index.ts +1 -5
- package/src/compiler/response.ts +16 -7
- package/src/compiler/sucrose.ts +11 -31
- package/src/config/define-config.test.ts +55 -34
- package/src/config/index.ts +177 -46
- package/src/config/resolve-driver.test.ts +28 -17
- package/src/console/budget.test.ts +1 -4
- package/src/console/index.ts +1 -4
- package/src/console/server/access.test.ts +15 -43
- package/src/console/server/access.ts +19 -49
- package/src/console/server/ai.test.ts +3 -11
- package/src/console/server/ai.ts +23 -46
- package/src/console/server/app.ts +16 -45
- package/src/console/server/auth-rate.test.ts +4 -12
- package/src/console/server/bind.ts +1 -5
- package/src/console/server/channels.test.ts +2 -6
- package/src/console/server/channels.ts +10 -35
- package/src/console/server/claim.ts +2 -8
- package/src/console/server/clock.test.ts +2 -6
- package/src/console/server/clock.ts +8 -26
- package/src/console/server/console.test.ts +1 -3
- package/src/console/server/diff.test.ts +5 -17
- package/src/console/server/diff.ts +10 -31
- package/src/console/server/dry-run.audit.test.ts +2 -8
- package/src/console/server/flows.ts +64 -233
- package/src/console/server/gates.test.ts +14 -50
- package/src/console/server/gates.ts +13 -48
- package/src/console/server/index.ts +2 -9
- package/src/console/server/live.ts +3 -12
- package/src/console/server/operator-db.test.ts +4 -15
- package/src/console/server/operator-db.ts +13 -32
- package/src/console/server/plugin.ts +50 -53
- package/src/console/server/plugins.test.ts +2 -6
- package/src/console/server/plugins.ts +17 -56
- package/src/console/server/runs-pii.ts +2 -7
- package/src/console/server/security.gate.test.ts +18 -40
- package/src/console/server/serve.ts +10 -25
- package/src/console/server/signals.test.ts +1 -3
- package/src/console/server/signals.ts +17 -40
- package/src/console/server/state.ts +21 -59
- package/src/console/server/store.test.ts +20 -22
- package/src/console/server/store.ts +31 -76
- package/src/console/server/vault.test.ts +12 -29
- package/src/console/server/vault.ts +44 -66
- package/src/console/ui/access/AccessA11yView.tsx +6 -21
- package/src/console/ui/access/a11y.test.tsx +3 -12
- package/src/console/ui/access/acknowledgement.test.ts +1 -4
- package/src/console/ui/access/acknowledgement.ts +1 -3
- package/src/console/ui/access/blast-radius.ts +1 -3
- package/src/console/ui/access/confirmation.test.ts +1 -5
- package/src/console/ui/access/confirmation.ts +1 -4
- package/src/console/ui/access/fixture.ts +1 -5
- package/src/console/ui/access/grantable.test.ts +1 -3
- package/src/console/ui/access/grantable.ts +2 -7
- package/src/console/ui/access/index.ts +2 -9
- package/src/console/ui/access/provenance.test.ts +1 -3
- package/src/console/ui/access/provenance.ts +2 -6
- package/src/console/ui/access/search.test.ts +1 -5
- package/src/console/ui/access/search.ts +2 -6
- package/src/console/ui/ai/AiA11yView.tsx +6 -17
- package/src/console/ui/ai/a11y.test.tsx +2 -5
- package/src/console/ui/ai/fixture.ts +2 -7
- package/src/console/ui/ai/format.ts +1 -3
- package/src/console/ui/ai/group.test.ts +1 -3
- package/src/console/ui/ai/group.ts +4 -12
- package/src/console/ui/ai/index.ts +2 -9
- package/src/console/ui/ai/promotion.test.ts +2 -7
- package/src/console/ui/ai/promotion.ts +4 -13
- package/src/console/ui/ai/search.test.ts +2 -11
- package/src/console/ui/ai/search.ts +3 -13
- package/src/console/ui/ai/types.ts +1 -8
- package/src/console/ui/architecture/ArchitectureA11yView.tsx +8 -29
- package/src/console/ui/architecture/a11y.test.tsx +1 -2
- package/src/console/ui/architecture/declared.ts +1 -5
- package/src/console/ui/architecture/index.ts +7 -35
- package/src/console/ui/architecture/layout.ts +1 -3
- package/src/console/ui/architecture/pathologies.ts +10 -19
- package/src/console/ui/architecture/search.ts +6 -15
- package/src/console/ui/architecture/traffic.ts +4 -14
- package/src/console/ui/architecture/types.ts +2 -10
- package/src/console/ui/architecture/view.test.ts +7 -19
- package/src/console/ui/architecture/view.ts +9 -36
- package/src/console/ui/channels/ChannelsA11yView.tsx +4 -13
- package/src/console/ui/channels/a11y.test.tsx +1 -2
- package/src/console/ui/channels/confirmation.test.ts +1 -4
- package/src/console/ui/channels/confirmation.ts +1 -4
- package/src/console/ui/channels/findings.ts +1 -5
- package/src/console/ui/channels/index.ts +2 -8
- package/src/console/ui/channels/locale.test.ts +1 -3
- package/src/console/ui/channels/locale.ts +2 -8
- package/src/console/ui/channels/search.ts +4 -13
- package/src/console/ui/channels/taxonomy.ts +1 -3
- package/src/console/ui/clock/ClockA11yView.tsx +9 -26
- package/src/console/ui/clock/a11y.test.tsx +2 -5
- package/src/console/ui/clock/confirmation.test.ts +1 -3
- package/src/console/ui/clock/confirmation.ts +1 -4
- package/src/console/ui/clock/findings.ts +1 -4
- package/src/console/ui/clock/health.ts +2 -7
- package/src/console/ui/clock/index.ts +2 -10
- package/src/console/ui/clock/search.test.ts +1 -3
- package/src/console/ui/clock/search.ts +2 -6
- package/src/console/ui/clock/timeline.test.ts +1 -3
- package/src/console/ui/clock/waiting-on.test.ts +1 -5
- package/src/console/ui/clock/waiting-on.ts +2 -7
- package/src/console/ui/diff/DiffA11yView.tsx +8 -17
- package/src/console/ui/diff/a11y.test.tsx +2 -5
- package/src/console/ui/diff/group.test.ts +3 -13
- package/src/console/ui/diff/group.ts +2 -8
- package/src/console/ui/diff/index.ts +2 -8
- package/src/console/ui/diff/search.test.ts +1 -5
- package/src/console/ui/diff/search.ts +4 -16
- package/src/console/ui/diff/summary.ts +1 -2
- package/src/console/ui/dist/assets/{index-Dy4jht9P.js → index-BWo8R7NR.js} +2 -2
- package/src/console/ui/dist/assets/{panel-access-Dd37LU2c.js → panel-access-C0J2D-a2.js} +1 -1
- package/src/console/ui/dist/assets/{panel-ai-CC7LR6-J.js → panel-ai-D_m6WQI8.js} +1 -1
- package/src/console/ui/dist/assets/{panel-architecture-B5b3iKCz.js → panel-architecture-CKnXFyUx.js} +1 -1
- package/src/console/ui/dist/assets/{panel-channels-CeNjTKXp.js → panel-channels-BOmQ-onL.js} +1 -1
- package/src/console/ui/dist/assets/{panel-clock-DgFTLoHV.js → panel-clock-giAq0Ccv.js} +1 -1
- package/src/console/ui/dist/assets/{panel-diff-DxehccqB.js → panel-diff-cdonmH8c.js} +1 -1
- package/src/console/ui/dist/assets/{panel-flows-BtrVn-Eg.js → panel-flows-DlCU5zjA.js} +2 -2
- package/src/console/ui/dist/assets/{panel-gates-Z9MKRGdH.js → panel-gates-XclZxWD5.js} +1 -1
- package/src/console/ui/dist/assets/{panel-overview-Dt_AeXgd.js → panel-overview-BznEOTnb.js} +1 -1
- package/src/console/ui/dist/assets/{panel-plugins-DWd0TowH.js → panel-plugins-CcGM1g64.js} +1 -1
- package/src/console/ui/dist/assets/{panel-runs-DGstFHeq.js → panel-runs-CGWNHLR4.js} +1 -1
- package/src/console/ui/dist/assets/{panel-signals-DzEa2Fnt.js → panel-signals-CNywkdak.js} +1 -1
- package/src/console/ui/dist/assets/{panel-store-BJkbNgxx.js → panel-store-KmTbFHMH.js} +1 -1
- package/src/console/ui/dist/assets/{panel-traces-BaRVO3gM.js → panel-traces-DBLx2ilD.js} +1 -1
- package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +1 -0
- package/src/console/ui/dist/index.html +1 -1
- package/src/console/ui/flows/FlowsA11yView.tsx +7 -22
- package/src/console/ui/flows/a11y.test.tsx +2 -8
- package/src/console/ui/flows/buffer.test.ts +3 -11
- package/src/console/ui/flows/buffer.ts +4 -11
- package/src/console/ui/flows/confirmation.ts +1 -3
- package/src/console/ui/flows/contract.test.ts +3 -7
- package/src/console/ui/flows/contract.ts +12 -36
- package/src/console/ui/flows/graph.test.ts +3 -11
- package/src/console/ui/flows/graph.ts +5 -15
- package/src/console/ui/flows/index.ts +1 -6
- package/src/console/ui/flows/save-as-test.ts +1 -3
- package/src/console/ui/flows/search.ts +8 -25
- package/src/console/ui/flows/tiers.ts +2 -9
- package/src/console/ui/gates/GatesA11yView.tsx +4 -13
- package/src/console/ui/gates/a11y.test.tsx +2 -5
- package/src/console/ui/gates/audit.ts +1 -3
- package/src/console/ui/gates/denial.test.ts +1 -3
- package/src/console/ui/gates/denial.ts +4 -12
- package/src/console/ui/gates/findings.ts +1 -3
- package/src/console/ui/gates/group.test.ts +3 -3
- package/src/console/ui/gates/group.ts +3 -11
- package/src/console/ui/gates/index.ts +2 -10
- package/src/console/ui/gates/search.ts +3 -10
- package/src/console/ui/overview/OverviewA11yView.tsx +9 -27
- package/src/console/ui/overview/a11y.test.tsx +1 -2
- package/src/console/ui/overview/busiest.ts +1 -3
- package/src/console/ui/overview/compose.ts +1 -13
- package/src/console/ui/overview/cost.ts +34 -38
- package/src/console/ui/overview/fixture.ts +21 -26
- package/src/console/ui/overview/golden.ts +4 -14
- package/src/console/ui/overview/index.ts +2 -9
- package/src/console/ui/overview/rank.test.ts +3 -10
- package/src/console/ui/overview/rank.ts +2 -7
- package/src/console/ui/overview/slo.test.ts +5 -9
- package/src/console/ui/overview/slo.ts +6 -23
- package/src/console/ui/overview/verdict.ts +3 -10
- package/src/console/ui/plugins/PluginsA11yView.tsx +8 -18
- package/src/console/ui/plugins/a11y.test.tsx +1 -2
- package/src/console/ui/plugins/fixture.ts +2 -4
- package/src/console/ui/plugins/group.test.ts +1 -3
- package/src/console/ui/plugins/group.ts +1 -6
- package/src/console/ui/plugins/index.ts +3 -13
- package/src/console/ui/plugins/search.ts +7 -19
- package/src/console/ui/runs/RunsA11yView.tsx +5 -20
- package/src/console/ui/runs/a11y.test.tsx +2 -5
- package/src/console/ui/runs/explain.ts +2 -6
- package/src/console/ui/runs/group.ts +3 -12
- package/src/console/ui/runs/histogram.test.ts +2 -11
- package/src/console/ui/runs/histogram.ts +1 -4
- package/src/console/ui/runs/index.ts +4 -18
- package/src/console/ui/runs/project.ts +2 -6
- package/src/console/ui/runs/query.test.ts +1 -3
- package/src/console/ui/runs/query.ts +12 -35
- package/src/console/ui/runs/search.ts +5 -19
- package/src/console/ui/runs/trace-link.test.ts +2 -6
- package/src/console/ui/runs/trace-link.ts +4 -16
- package/src/console/ui/runs/types.ts +1 -3
- package/src/console/ui/shell/App.tsx +2 -10
- package/src/console/ui/shell/client.ts +22 -115
- package/src/console/ui/shell/components/ui.tsx +1 -4
- package/src/console/ui/shell/layout/Shell.tsx +2 -4
- package/src/console/ui/shell/main.tsx +31 -96
- package/src/console/ui/shell/panels/access/AccessPanel.tsx +34 -98
- package/src/console/ui/shell/panels/ai/AiPanel.tsx +35 -106
- package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +18 -66
- package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +20 -57
- package/src/console/ui/shell/panels/clock/ClockPanel.tsx +22 -54
- package/src/console/ui/shell/panels/diff/DiffPanel.tsx +20 -61
- package/src/console/ui/shell/panels/flows/ContractEditor.tsx +6 -23
- package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +13 -28
- package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +9 -29
- package/src/console/ui/shell/panels/gates/GatesPanel.tsx +24 -80
- package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +20 -58
- package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +16 -41
- package/src/console/ui/shell/panels/runs/RunsPanel.tsx +31 -99
- package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +38 -101
- package/src/console/ui/shell/panels/store/StorePanel.tsx +27 -66
- package/src/console/ui/shell/panels/traces/TracesPanel.tsx +28 -89
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +22 -53
- package/src/console/ui/shell/setup/Wizard.tsx +3 -5
- package/src/console/ui/shell/styles.css +1 -2
- package/src/console/ui/signals/SignalsA11yView.tsx +9 -33
- package/src/console/ui/signals/a11y.test.tsx +2 -5
- package/src/console/ui/signals/confirmation.test.ts +1 -5
- package/src/console/ui/signals/confirmation.ts +2 -6
- package/src/console/ui/signals/dry-run.ts +1 -3
- package/src/console/ui/signals/durable.ts +1 -3
- package/src/console/ui/signals/findings.ts +1 -3
- package/src/console/ui/signals/group.test.ts +2 -8
- package/src/console/ui/signals/group.ts +2 -10
- package/src/console/ui/signals/index.ts +1 -4
- package/src/console/ui/signals/monitor.ts +2 -7
- package/src/console/ui/signals/schema-form.test.ts +3 -14
- package/src/console/ui/signals/schema-form.ts +1 -4
- package/src/console/ui/signals/search.ts +4 -13
- package/src/console/ui/store/StoreA11yView.tsx +3 -9
- package/src/console/ui/store/a11y.test.tsx +2 -5
- package/src/console/ui/store/confirmation.test.ts +1 -3
- package/src/console/ui/store/confirmation.ts +1 -4
- package/src/console/ui/store/dry-run.ts +2 -5
- package/src/console/ui/store/fixture.ts +1 -2
- package/src/console/ui/store/group.test.ts +1 -6
- package/src/console/ui/store/group.ts +1 -4
- package/src/console/ui/store/index.ts +1 -5
- package/src/console/ui/store/search.ts +2 -6
- package/src/console/ui/store/will-not-fire.ts +1 -2
- package/src/console/ui/traces/TracesA11yView.tsx +10 -29
- package/src/console/ui/traces/a11y.test.tsx +1 -2
- package/src/console/ui/traces/chain.test.ts +5 -19
- package/src/console/ui/traces/chain.ts +1 -3
- package/src/console/ui/traces/critical-path.test.ts +1 -3
- package/src/console/ui/traces/critical-path.ts +2 -6
- package/src/console/ui/traces/filter.test.ts +2 -6
- package/src/console/ui/traces/filter.ts +5 -13
- package/src/console/ui/traces/fold.test.ts +4 -12
- package/src/console/ui/traces/fold.ts +1 -3
- package/src/console/ui/traces/mini.ts +1 -3
- package/src/console/ui/traces/replay.test.ts +1 -3
- package/src/console/ui/traces/replay.ts +1 -3
- package/src/console/ui/traces/sampling.ts +1 -4
- package/src/console/ui/traces/search.ts +4 -17
- package/src/console/ui/traces/tier.ts +1 -3
- package/src/console/ui/vault/VaultA11yView.tsx +5 -17
- package/src/console/ui/vault/a11y.test.tsx +1 -2
- package/src/console/ui/vault/blast-radius.ts +1 -3
- package/src/console/ui/vault/confirmation.test.ts +1 -5
- package/src/console/ui/vault/confirmation.ts +1 -4
- package/src/console/ui/vault/dormant.test.ts +1 -4
- package/src/console/ui/vault/export-safe.test.ts +1 -5
- package/src/console/ui/vault/export-safe.ts +1 -4
- package/src/console/ui/vault/fixture.ts +3 -3
- package/src/console/ui/vault/group.ts +1 -2
- package/src/console/ui/vault/index.ts +2 -10
- package/src/console/ui/vault/search.ts +2 -6
- package/src/console/ui/vault/types.ts +1 -1
- package/src/console/xss.gate.test.ts +1 -3
- package/src/docker/compose.ts +215 -27
- package/src/docker/derive.ts +6 -14
- package/src/docker/docker.test.ts +118 -15
- package/src/docker/dockerfile.integration.test.ts +12 -21
- package/src/docker/helpers.ts +5 -4
- package/src/docker/index.ts +9 -6
- package/src/docker/pin.ts +1 -9
- package/src/docker/recipes/index.ts +6 -6
- package/src/docker/recipes/mailpit.ts +22 -0
- package/src/docker/recipes/openbao.ts +47 -0
- package/src/docker/recipes/postgres.ts +17 -6
- package/src/docker/recipes/redis.ts +11 -2
- package/src/docker/recipes/rustfs.ts +32 -0
- package/src/docker/stack-id.test.ts +73 -5
- package/src/docker/stack-id.ts +124 -33
- package/src/docker/stack.integration.test.ts +6 -21
- package/src/docker/stack.ts +36 -4
- package/src/docker/types.ts +16 -4
- package/src/docs-origin.ts +4 -4
- package/src/drivers/ai-anthropic.ts +5 -14
- package/src/drivers/ai-mock.ts +2 -5
- package/src/drivers/ai-openai-compatible.ts +4 -10
- package/src/drivers/ai-providers.test.ts +6 -13
- package/src/drivers/bun-native-completeness.test.ts +6 -15
- package/src/drivers/channel-console.ts +6 -7
- package/src/drivers/channel-fcm.ts +20 -30
- package/src/drivers/channel-resend.ts +1 -3
- package/src/drivers/channel-smtp.ts +2 -6
- package/src/drivers/channel-types.ts +2 -12
- package/src/drivers/channel-unifonic.ts +2 -6
- package/src/drivers/channel-wa-cloud.ts +2 -6
- package/src/drivers/channel-webpush.ts +21 -60
- package/src/drivers/conformance.test.ts +2 -10
- package/src/drivers/conformance.ts +8 -21
- package/src/drivers/drizzle-dialect.test.ts +20 -0
- package/src/drivers/drizzle-dialect.ts +37 -0
- package/src/drivers/fs.ts +2 -8
- package/src/drivers/index.ts +12 -57
- package/src/drivers/memory.ts +287 -75
- package/src/drivers/pgvector.ts +7 -11
- package/src/drivers/postgres.ts +7 -13
- package/src/drivers/redis.ts +13 -37
- package/src/drivers/s3.ts +15 -18
- package/src/drivers/signal-engine.ts +12 -49
- package/src/drivers/signal-memory.ts +2 -8
- package/src/drivers/signal-nats.ts +4 -9
- package/src/drivers/signal-postgres.ts +62 -129
- package/src/drivers/signal-redis.ts +7 -21
- package/src/drivers/signal-types.ts +1 -4
- package/src/drivers/sqlite.ts +3 -12
- package/src/drivers/types.ts +4 -23
- package/src/drivers/vault-driver-removal.test.ts +55 -0
- package/src/drivers/vault-env.ts +2 -6
- package/src/drivers/vault-infisical.ts +1 -5
- package/src/drivers/vault-managed.ts +1 -5
- package/src/drivers/vault-memory.ts +1 -5
- package/src/drivers/vault-openbao.test.ts +97 -0
- package/src/drivers/vault-openbao.ts +103 -40
- package/src/drivers/vault-types.ts +3 -16
- package/src/elements/ai/declare.ts +4 -14
- package/src/elements/ai/eval.ts +2 -6
- package/src/elements/ai/pii.ts +1 -3
- package/src/elements/ai/runtime.ts +12 -50
- package/src/elements/ai/schema.ts +4 -15
- package/src/elements/ai.test.ts +13 -24
- package/src/elements/ai.ts +1 -5
- package/src/elements/channel/consent.ts +3 -12
- package/src/elements/channel/costs.ts +4 -15
- package/src/elements/channel/declare.ts +1 -4
- package/src/elements/channel/email-auth.ts +1 -4
- package/src/elements/channel/locale.ts +2 -10
- package/src/elements/channel/mask.ts +1 -3
- package/src/elements/channel/mime.ts +2 -12
- package/src/elements/channel/outcomes.test.ts +1 -5
- package/src/elements/channel/outcomes.ts +5 -15
- package/src/elements/channel/receipts.ts +2 -7
- package/src/elements/channel/runtime.ts +28 -74
- package/src/elements/channel/suppression.ts +8 -14
- package/src/elements/channel.test.ts +8 -31
- package/src/elements/channel.ts +3 -14
- package/src/elements/clock/actions.ts +6 -18
- package/src/elements/clock/declare.ts +1 -3
- package/src/elements/clock/dst.ts +1 -5
- package/src/elements/clock/durable.ts +4 -16
- package/src/elements/clock/health.ts +2 -7
- package/src/elements/clock/leader.ts +2 -9
- package/src/elements/clock/reconcile.ts +4 -15
- package/src/elements/clock/runtime.ts +2 -5
- package/src/elements/clock/schedule.ts +4 -20
- package/src/elements/clock.test.ts +2 -7
- package/src/elements/clock.ts +5 -23
- package/src/elements/gate/permissions.ts +1 -4
- package/src/elements/gate/runtime.ts +7 -28
- package/src/elements/gate.ts +1 -5
- package/src/elements/index.ts +9 -7
- package/src/elements/signal/declare.ts +2 -7
- package/src/elements/signal/reconcile.test.ts +1 -4
- package/src/elements/signal/runtime.ts +1 -3
- package/src/elements/signal.test.ts +3 -15
- package/src/elements/signal.ts +2 -8
- package/src/elements/store/cache.test.ts +46 -0
- package/src/elements/store/cache.ts +3 -11
- package/src/elements/store/classify.ts +5 -22
- package/src/elements/store/declare.ts +11 -17
- package/src/elements/store/domain-ddl.test.ts +86 -0
- package/src/elements/store/emit-drizzle.ts +363 -0
- package/src/elements/store/files-policy.test.ts +1 -5
- package/src/elements/store/files-policy.ts +4 -12
- package/src/elements/store/load-plugin-tables.ts +103 -0
- package/src/elements/store/missing-relation.test.ts +83 -0
- package/src/elements/store/missing-relation.ts +38 -0
- package/src/elements/store/replica.ts +1 -4
- package/src/elements/store/resource-list-docs.fixture.ts +56 -0
- package/src/elements/store/resource-list-docs.test.ts +79 -0
- package/src/elements/store/resource.test.ts +253 -0
- package/src/elements/store/resource.ts +786 -0
- package/src/elements/store/runtime.ts +25 -28
- package/src/elements/store/schema-decl.test.ts +227 -0
- package/src/elements/store/schema-decl.ts +516 -0
- package/src/elements/store/sql-condition.test.ts +132 -0
- package/src/elements/store/sql-condition.ts +293 -65
- package/src/elements/store/sql-session.test.ts +135 -0
- package/src/elements/store/sql-session.ts +241 -84
- package/src/elements/store/table.ts +69 -23
- package/src/elements/store.test.ts +17 -39
- package/src/elements/store.ts +53 -31
- package/src/elements/vault/chain.ts +34 -0
- package/src/elements/vault/declare.ts +22 -32
- package/src/elements/vault/fingerprint.ts +2 -7
- package/src/elements/vault/redact.ts +2 -6
- package/src/elements/vault/runtime.ts +19 -33
- package/src/elements/vault.test.ts +12 -55
- package/src/elements/vault.ts +9 -13
- package/src/index.ts +5 -2
- package/src/kernel/adopt-routes.ts +15 -29
- package/src/kernel/app.ts +92 -118
- package/src/kernel/auth-resolve.ts +2 -9
- package/src/kernel/boot-bind/ai.ts +1 -4
- package/src/kernel/boot-bind/channel.test.ts +60 -0
- package/src/kernel/boot-bind/channel.ts +61 -5
- package/src/kernel/boot-bind/clock.ts +2 -6
- package/src/kernel/boot-bind/gate.ts +2 -8
- package/src/kernel/boot-bind/runs.ts +1 -3
- package/src/kernel/boot-bind/signal.ts +3 -10
- package/src/kernel/boot-bind/store.test.ts +27 -18
- package/src/kernel/boot-bind/store.ts +93 -52
- package/src/kernel/boot-bind/vault.ts +2 -8
- package/src/kernel/boot.test.ts +4 -10
- package/src/kernel/boot.ts +30 -77
- package/src/kernel/budget.test.ts +1 -3
- package/src/kernel/capability.ts +3 -10
- package/src/kernel/dry-run.test.ts +1 -4
- package/src/kernel/dry-run.ts +3 -11
- package/src/kernel/edge.test.ts +68 -0
- package/src/kernel/effects.test.ts +1 -5
- package/src/kernel/effects.ts +4 -11
- package/src/kernel/errors.registry.test.ts +2 -8
- package/src/kernel/errors.ts +23 -32
- package/src/kernel/flow.test.ts +12 -25
- package/src/kernel/flow.ts +13 -25
- package/src/kernel/fx.test.ts +31 -40
- package/src/kernel/fx.ts +135 -90
- package/src/kernel/hook-timing.test.ts +3 -6
- package/src/kernel/hook-timing.ts +5 -14
- package/src/kernel/hooks.test.ts +43 -10
- package/src/kernel/hooks.ts +25 -12
- package/src/kernel/index.ts +11 -17
- package/src/kernel/journal.ts +7 -31
- package/src/kernel/on.ts +45 -9
- package/src/kernel/pipeline.test.ts +10 -19
- package/src/kernel/pipeline.ts +5 -17
- package/src/kernel/plug.ts +4 -11
- package/src/kernel/plugin/conflicts.test.ts +13 -25
- package/src/kernel/plugin/decorate.test.ts +8 -13
- package/src/kernel/plugin/scoping.test.ts +4 -11
- package/src/kernel/plugin.ts +81 -27
- package/src/kernel/registry-isolation.test.ts +74 -0
- package/src/kernel/registry.ts +102 -30
- package/src/kernel/router.test.ts +15 -13
- package/src/kernel/router.ts +9 -29
- package/src/kernel/routing-budget.test.ts +1 -3
- package/src/kernel/run-telemetry.ts +1 -3
- package/src/kernel/triggers.ts +63 -21
- package/src/manifest/diff.test.ts +26 -91
- package/src/manifest/diff.ts +95 -225
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/manifest/index.ts +3 -10
- package/src/manifest/types.ts +30 -6
- package/src/manifest/undeclared.test.ts +4 -12
- package/src/manifest/undeclared.ts +1 -2
- package/src/manifest/validate.test.ts +2 -6
- package/src/manifest/validate.ts +5 -15
- package/src/mcp/authorization.ts +8 -27
- package/src/mcp/confirmation.ts +3 -10
- package/src/mcp/data.ts +2 -6
- package/src/mcp/docs-index.ts +4 -7
- package/src/mcp/docs-mcp.test.ts +3 -12
- package/src/mcp/docs-server.ts +7 -27
- package/src/mcp/docs-tools.ts +2 -6
- package/src/mcp/index.ts +1 -6
- package/src/mcp/injection.gate.test.ts +4 -18
- package/src/mcp/mcp.test.ts +18 -49
- package/src/mcp/protocol.ts +3 -10
- package/src/mcp/server.ts +11 -52
- package/src/mcp/session.ts +4 -14
- package/src/mcp/tools.ts +14 -50
- package/src/plugins/catalogue.test.ts +3 -7
- package/src/plugins/catalogue.ts +1 -3
- package/src/plugins/compression.test.ts +127 -0
- package/src/plugins/compression.ts +94 -0
- package/src/plugins/config-source.test.ts +204 -0
- package/src/plugins/config-source.ts +209 -0
- package/src/plugins/cors.test.ts +138 -0
- package/src/plugins/cors.ts +129 -0
- package/src/plugins/csrf.test.ts +102 -0
- package/src/plugins/csrf.ts +86 -0
- package/src/plugins/headers.ts +54 -0
- package/src/plugins/index.ts +26 -0
- package/src/plugins/ip-allowlist.test.ts +105 -0
- package/src/plugins/ip-allowlist.ts +76 -0
- package/src/plugins/maintenance-mode.test.ts +91 -0
- package/src/plugins/maintenance-mode.ts +85 -0
- package/src/plugins/node-import-scan.ts +2 -5
- package/src/plugins/security-headers.test.ts +243 -0
- package/src/plugins/security-headers.ts +255 -0
- package/src/plugins/supply-chain.ts +5 -17
- package/src/release/exports.ts +3 -8
- package/src/release/measure.exports.test.ts +1 -3
- package/src/release/measure.ts +16 -45
- package/src/runs/bench.test.ts +1 -3
- package/src/runs/collect.ts +8 -25
- package/src/runs/drivers/clickhouse.ts +2 -9
- package/src/runs/drivers/files.ts +9 -31
- package/src/runs/drivers/memory.ts +5 -22
- package/src/runs/drivers/postgres.ts +8 -20
- package/src/runs/duckdb.ts +2 -8
- package/src/runs/index.ts +3 -14
- package/src/runs/outlier.ts +3 -10
- package/src/runs/parquet.ts +8 -26
- package/src/runs/privacy.ts +2 -8
- package/src/runs/runs.test.ts +3 -9
- package/src/runs/runtime.ts +7 -32
- package/src/runs/shred.ts +10 -29
- package/src/runs/types.ts +1 -4
- package/src/runtime/bun.ts +4 -15
- package/src/runtime/cold-start.bench.ts +1 -3
- package/src/runtime/dev-request-log.test.ts +1 -4
- package/src/runtime/dev-request-log.ts +1 -4
- package/src/runtime/index.ts +1 -6
- package/src/runtime/primitives.ts +5 -4
- package/src/runtime/security.ts +3 -13
- package/src/runtime/serve.test.ts +4 -7
- package/src/runtime/types.ts +1 -4
- package/src/runtime/web-standard.ts +3 -15
- package/src/term.test.ts +4 -6
- package/src/term.ts +49 -98
- package/src/test/create-test-app.test.ts +4 -14
- package/src/test/create-test-app.ts +27 -33
- package/src/test/provisions.integration.test.ts +3 -11
- package/src/upgrade/codemods.test.ts +25 -6
- package/src/upgrade/codemods.ts +116 -3
- package/src/validation/standard-schema.test.ts +2 -5
- package/src/validation/standard-schema.ts +13 -33
- package/docs/spec/console.md +0 -739
- package/docs/spec/example.md +0 -1196
- package/docs/spec/four-applications.md +0 -1195
- package/docs/spec/unified-theory.md +0 -489
- package/src/cli/doc-drift.test.ts +0 -146
- package/src/cli/doc-drift.ts +0 -430
- package/src/cli/doctor-diff-examples.ts +0 -92
- package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
- package/src/drivers/vault-sops.ts +0 -271
package/src/docker/types.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface ServiceSpec {
|
|
|
37
37
|
readonly port: number;
|
|
38
38
|
/** Host port published in compose (dev defaults). */
|
|
39
39
|
readonly hostPort: number;
|
|
40
|
-
/** Credential placeholders (values live in `.env.
|
|
40
|
+
/** Credential placeholders (values live in `.env.docker`, not YAML). */
|
|
41
41
|
readonly credentials: ServiceCredentials;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -50,13 +50,22 @@ export interface ComposeHealthcheck {
|
|
|
50
50
|
readonly start_period?: string;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/** Extra published host↔container port pair from a recipe. */
|
|
54
|
+
export interface RecipeExtraPort {
|
|
55
|
+
readonly host: number;
|
|
56
|
+
readonly container: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
/** Image-specific compose fragment from {@link ImageRecipe.apply}. */
|
|
54
60
|
export interface RecipeApplyResult {
|
|
55
61
|
readonly environment?: Readonly<Record<string, string>>;
|
|
56
62
|
readonly command?: string | readonly string[];
|
|
63
|
+
readonly entrypoint?: string | readonly string[];
|
|
57
64
|
readonly healthcheck?: ComposeHealthcheck;
|
|
58
65
|
readonly volumes?: readonly string[];
|
|
59
66
|
readonly user?: string;
|
|
67
|
+
/** Additional published ports (e.g. Mailpit UI, RustFS console). */
|
|
68
|
+
readonly extraPorts?: readonly RecipeExtraPort[];
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
/**
|
|
@@ -102,12 +111,13 @@ export interface DeriveOptions {
|
|
|
102
111
|
readonly prod?: boolean;
|
|
103
112
|
/**
|
|
104
113
|
* Include the `app` service in `compose.yml` (default true).
|
|
105
|
-
* `oke dev --
|
|
114
|
+
* `oke dev --docker` sets false — host Bun runs the app; Docker is infra only.
|
|
106
115
|
*/
|
|
107
116
|
readonly includeApp?: boolean;
|
|
108
117
|
/**
|
|
109
118
|
* Compose artefact directory relative to the project root (default `docker`).
|
|
110
|
-
* Controls generated `env_file` / `build.context` paths (
|
|
119
|
+
* Controls generated `env_file` / `build.context` paths (`.env.docker` lives
|
|
120
|
+
* beside compose under this directory).
|
|
111
121
|
* Pass `"."` for legacy root-level layout.
|
|
112
122
|
*/
|
|
113
123
|
readonly composeDir?: string;
|
|
@@ -119,6 +129,8 @@ export interface DeriveOptions {
|
|
|
119
129
|
readonly host?: string;
|
|
120
130
|
/** Extra image recipes (plugins). */
|
|
121
131
|
readonly recipes?: readonly ImageRecipe[];
|
|
132
|
+
/** Preserved optional controls from an existing `.env.docker`. */
|
|
133
|
+
readonly controls?: Readonly<Record<string, string>>;
|
|
122
134
|
/**
|
|
123
135
|
* Local stack instance id (6-hex). When set, host ports are offset so two
|
|
124
136
|
* `oke dev -s` projects do not share one Postgres on `:5432`.
|
|
@@ -144,7 +156,7 @@ export interface DeriveResult {
|
|
|
144
156
|
/** Generated files (Dockerfile + compose layers). */
|
|
145
157
|
readonly files: readonly GeneratedFile[];
|
|
146
158
|
/**
|
|
147
|
-
* Stack env contents for `.env.
|
|
159
|
+
* Stack env contents for `.env.docker` — written by `oke dev --docker`,
|
|
148
160
|
* never embedded in YAML.
|
|
149
161
|
*/
|
|
150
162
|
readonly stackEnv: Readonly<Record<string, string>>;
|
package/src/docs-origin.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Canonical public docs origin for error links, README, and the site.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
4
|
+
* Keep in lockstep with `packages/create-oke/src/docs-origin.ts` and
|
|
5
|
+
* `site/app/layout.tsx` (`metadataBase`).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
/** Live docs site
|
|
9
|
-
export const DOCS_ORIGIN = "https://
|
|
8
|
+
/** Live docs site. */
|
|
9
|
+
export const DOCS_ORIGIN = "https://oke.omqkhafi.dev" as const;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Absolute docs URL for a path under the handbook / site.
|
|
@@ -21,9 +21,7 @@ const ANTHROPIC_VERSION = "2023-06-01";
|
|
|
21
21
|
*
|
|
22
22
|
* @param options - API key / model / base URL / injectable fetch
|
|
23
23
|
*/
|
|
24
|
-
export async function openAnthropic(
|
|
25
|
-
options: AiOpenOptions = {},
|
|
26
|
-
): Promise<AiModelClient> {
|
|
24
|
+
export async function openAnthropic(options: AiOpenOptions = {}): Promise<AiModelClient> {
|
|
27
25
|
const apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
28
26
|
if (!apiKey) {
|
|
29
27
|
throw new Error("anthropic: apiKey is required (or ANTHROPIC_API_KEY)");
|
|
@@ -48,17 +46,14 @@ export async function openAnthropic(
|
|
|
48
46
|
body: JSON.stringify({
|
|
49
47
|
model: resolvedModel,
|
|
50
48
|
max_tokens: opts.maxTokens ?? 1024,
|
|
51
|
-
...(opts.temperature !== undefined
|
|
52
|
-
? { temperature: opts.temperature }
|
|
53
|
-
: {}),
|
|
49
|
+
...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}),
|
|
54
50
|
...(system !== undefined ? { system } : {}),
|
|
55
51
|
messages,
|
|
56
52
|
}),
|
|
57
53
|
});
|
|
58
54
|
const raw = (await res.json().catch(() => ({}))) as AnthropicMessagesResponse;
|
|
59
55
|
if (!res.ok) {
|
|
60
|
-
const msg =
|
|
61
|
-
raw.error?.message ?? `anthropic HTTP ${res.status}`;
|
|
56
|
+
const msg = raw.error?.message ?? `anthropic HTTP ${res.status}`;
|
|
62
57
|
throw new Error(`anthropic: ${msg}`);
|
|
63
58
|
}
|
|
64
59
|
const text = textFromContent(raw.content);
|
|
@@ -92,9 +87,7 @@ interface AnthropicMessagesResponse {
|
|
|
92
87
|
readonly error?: { readonly message?: string };
|
|
93
88
|
}
|
|
94
89
|
|
|
95
|
-
function splitSystem(
|
|
96
|
-
messages: AiCompleteOptions["messages"],
|
|
97
|
-
): {
|
|
90
|
+
function splitSystem(messages: AiCompleteOptions["messages"]): {
|
|
98
91
|
system?: string;
|
|
99
92
|
messages: Array<{ role: "user" | "assistant"; content: string }>;
|
|
100
93
|
} {
|
|
@@ -117,9 +110,7 @@ function splitSystem(
|
|
|
117
110
|
};
|
|
118
111
|
}
|
|
119
112
|
|
|
120
|
-
function textFromContent(
|
|
121
|
-
content: AnthropicMessagesResponse["content"],
|
|
122
|
-
): string {
|
|
113
|
+
function textFromContent(content: AnthropicMessagesResponse["content"]): string {
|
|
123
114
|
if (!content?.length) return "";
|
|
124
115
|
return content
|
|
125
116
|
.filter((b) => b.type === "text" && typeof b.text === "string")
|
package/src/drivers/ai-mock.ts
CHANGED
|
@@ -39,8 +39,7 @@ export const mockAiDriver: AiDriver = {
|
|
|
39
39
|
if (payload === undefined) {
|
|
40
40
|
payload = canned["*"] ?? { ok: true, echo: last };
|
|
41
41
|
}
|
|
42
|
-
const text =
|
|
43
|
-
typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
42
|
+
const text = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
44
43
|
return {
|
|
45
44
|
text,
|
|
46
45
|
raw: payload,
|
|
@@ -70,9 +69,7 @@ export const mockAiDriver: AiDriver = {
|
|
|
70
69
|
*
|
|
71
70
|
* @param responses - Key → JSON payload
|
|
72
71
|
*/
|
|
73
|
-
export function createMockAiDriver(
|
|
74
|
-
responses: Readonly<Record<string, unknown>>,
|
|
75
|
-
): AiDriver {
|
|
72
|
+
export function createMockAiDriver(responses: Readonly<Record<string, unknown>>): AiDriver {
|
|
76
73
|
return {
|
|
77
74
|
id: "mock",
|
|
78
75
|
open(options = {}) {
|
|
@@ -23,14 +23,10 @@ const DEFAULT_BASE = "https://api.openai.com/v1";
|
|
|
23
23
|
*
|
|
24
24
|
* @param options - API key / model / base URL / injectable fetch
|
|
25
25
|
*/
|
|
26
|
-
export async function openOpenaiCompatible(
|
|
27
|
-
options: AiOpenOptions = {},
|
|
28
|
-
): Promise<AiModelClient> {
|
|
26
|
+
export async function openOpenaiCompatible(options: AiOpenOptions = {}): Promise<AiModelClient> {
|
|
29
27
|
const apiKey = options.apiKey ?? process.env.OPENAI_API_KEY;
|
|
30
28
|
if (!apiKey) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
"openai-compatible: apiKey is required (or OPENAI_API_KEY)",
|
|
33
|
-
);
|
|
29
|
+
throw new Error("openai-compatible: apiKey is required (or OPENAI_API_KEY)");
|
|
34
30
|
}
|
|
35
31
|
const model = options.model ?? "gpt-4o-mini";
|
|
36
32
|
const baseUrl = (options.baseUrl ?? DEFAULT_BASE).replace(/\/$/, "");
|
|
@@ -65,8 +61,7 @@ export async function openOpenaiCompatible(
|
|
|
65
61
|
});
|
|
66
62
|
const raw = (await res.json().catch(() => ({}))) as OpenAiChatResponse;
|
|
67
63
|
if (!res.ok) {
|
|
68
|
-
const msg =
|
|
69
|
-
raw.error?.message ?? `openai-compatible HTTP ${res.status}`;
|
|
64
|
+
const msg = raw.error?.message ?? `openai-compatible HTTP ${res.status}`;
|
|
70
65
|
throw new Error(`openai-compatible: ${msg}`);
|
|
71
66
|
}
|
|
72
67
|
const text = raw.choices?.[0]?.message?.content ?? "";
|
|
@@ -94,8 +89,7 @@ export async function openOpenaiCompatible(
|
|
|
94
89
|
});
|
|
95
90
|
const raw = (await res.json().catch(() => ({}))) as OpenAiEmbedResponse;
|
|
96
91
|
if (!res.ok) {
|
|
97
|
-
const msg =
|
|
98
|
-
raw.error?.message ?? `openai-compatible embed HTTP ${res.status}`;
|
|
92
|
+
const msg = raw.error?.message ?? `openai-compatible embed HTTP ${res.status}`;
|
|
99
93
|
throw new Error(`openai-compatible: ${msg}`);
|
|
100
94
|
}
|
|
101
95
|
const vectors = (raw.data ?? [])
|
|
@@ -4,10 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { describe, expect, test } from "bun:test";
|
|
6
6
|
import { anthropicAiDriver, openAnthropic } from "./ai-anthropic.ts";
|
|
7
|
-
import {
|
|
8
|
-
openaiCompatibleAiDriver,
|
|
9
|
-
openOpenaiCompatible,
|
|
10
|
-
} from "./ai-openai-compatible.ts";
|
|
7
|
+
import { openaiCompatibleAiDriver, openOpenaiCompatible } from "./ai-openai-compatible.ts";
|
|
11
8
|
import { mockAiDriver } from "./ai-mock.ts";
|
|
12
9
|
|
|
13
10
|
describe("anthropic driver", () => {
|
|
@@ -56,9 +53,7 @@ describe("anthropic driver", () => {
|
|
|
56
53
|
messages: Array<{ role: string }>;
|
|
57
54
|
};
|
|
58
55
|
expect(body.system).toBe("be brief");
|
|
59
|
-
expect(body.messages).toEqual([
|
|
60
|
-
{ role: "user", content: "hi" } as { role: string },
|
|
61
|
-
]);
|
|
56
|
+
expect(body.messages).toEqual([{ role: "user", content: "hi" } as { role: string }]);
|
|
62
57
|
});
|
|
63
58
|
|
|
64
59
|
test("HTTP error surfaces provider message", async () => {
|
|
@@ -73,18 +68,16 @@ describe("anthropic driver", () => {
|
|
|
73
68
|
apiKey: "sk-test",
|
|
74
69
|
fetch: fetchFn,
|
|
75
70
|
});
|
|
76
|
-
await expect(
|
|
77
|
-
|
|
78
|
-
)
|
|
71
|
+
await expect(client.complete({ messages: [{ role: "user", content: "x" }] })).rejects.toThrow(
|
|
72
|
+
"rate limited",
|
|
73
|
+
);
|
|
79
74
|
});
|
|
80
75
|
|
|
81
76
|
test("live Anthropic ask when ANTHROPIC_API_KEY is set", async () => {
|
|
82
77
|
const key = process.env.ANTHROPIC_API_KEY;
|
|
83
78
|
if (!key) {
|
|
84
79
|
// Clearly-marked skip — never fail CI for lack of credentials.
|
|
85
|
-
console.log(
|
|
86
|
-
"skip: live anthropic ask (ANTHROPIC_API_KEY not set)",
|
|
87
|
-
);
|
|
80
|
+
console.log("skip: live anthropic ask (ANTHROPIC_API_KEY not set)");
|
|
88
81
|
return;
|
|
89
82
|
}
|
|
90
83
|
const client = await anthropicAiDriver.open({
|
|
@@ -7,10 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { describe, expect, test } from "bun:test";
|
|
9
9
|
import { createBunRedisClient } from "./redis.ts";
|
|
10
|
-
import {
|
|
11
|
-
createBunSignalRedisClient,
|
|
12
|
-
parseXreadgroupReply,
|
|
13
|
-
} from "./signal-redis.ts";
|
|
10
|
+
import { createBunSignalRedisClient, parseXreadgroupReply } from "./signal-redis.ts";
|
|
14
11
|
|
|
15
12
|
/** One row in the completeness report. */
|
|
16
13
|
export interface BunNativeGapRow {
|
|
@@ -26,10 +23,7 @@ export interface BunNativeGapRow {
|
|
|
26
23
|
* Kept as a pure function so the gate test and human report share one source.
|
|
27
24
|
*/
|
|
28
25
|
export function bunNativeCompletenessReport(): readonly BunNativeGapRow[] {
|
|
29
|
-
const redisProto = Bun.RedisClient.prototype as unknown as Record<
|
|
30
|
-
string,
|
|
31
|
-
unknown
|
|
32
|
-
>;
|
|
26
|
+
const redisProto = Bun.RedisClient.prototype as unknown as Record<string, unknown>;
|
|
33
27
|
const hasTypedScan = typeof redisProto.scan === "function";
|
|
34
28
|
const hasTypedPublish = typeof redisProto.publish === "function";
|
|
35
29
|
const hasTypedSubscribe = typeof redisProto.subscribe === "function";
|
|
@@ -57,8 +51,7 @@ export function bunNativeCompletenessReport(): readonly BunNativeGapRow[] {
|
|
|
57
51
|
{
|
|
58
52
|
surface: "redis signal",
|
|
59
53
|
capability: "native Bun bind (publish/subscribe)",
|
|
60
|
-
status:
|
|
61
|
-
hasTypedPublish && hasTypedSubscribe ? "closed" : "bun_limitation",
|
|
54
|
+
status: hasTypedPublish && hasTypedSubscribe ? "closed" : "bun_limitation",
|
|
62
55
|
note:
|
|
63
56
|
hasTypedPublish && hasTypedSubscribe
|
|
64
57
|
? "createBunSignalRedisClient uses typed publish/subscribe"
|
|
@@ -107,9 +100,7 @@ describe("Bun native client completeness", () => {
|
|
|
107
100
|
expect(rows.length).toBe(8);
|
|
108
101
|
|
|
109
102
|
const closed = rows.filter((r) => r.status === "closed").map((r) => r.capability);
|
|
110
|
-
const limited = rows
|
|
111
|
-
.filter((r) => r.status === "bun_limitation")
|
|
112
|
-
.map((r) => r.capability);
|
|
103
|
+
const limited = rows.filter((r) => r.status === "bun_limitation").map((r) => r.capability);
|
|
113
104
|
|
|
114
105
|
// Closed on Bun 1.3.14
|
|
115
106
|
expect(closed).toContain("SCAN (typed)");
|
|
@@ -141,13 +132,13 @@ describe("Bun native client completeness", () => {
|
|
|
141
132
|
[
|
|
142
133
|
"oke:signal:order",
|
|
143
134
|
[
|
|
144
|
-
["1-0", ["payload",
|
|
135
|
+
["1-0", ["payload", '{"a":1}', "signal", "order"]],
|
|
145
136
|
["1-1", ["payload", "{}", "signal", "order"]],
|
|
146
137
|
],
|
|
147
138
|
],
|
|
148
139
|
]);
|
|
149
140
|
expect(parsed).toEqual([
|
|
150
|
-
{ id: "1-0", fields: { payload:
|
|
141
|
+
{ id: "1-0", fields: { payload: '{"a":1}', signal: "order" } },
|
|
151
142
|
{ id: "1-1", fields: { payload: "{}", signal: "order" } },
|
|
152
143
|
]);
|
|
153
144
|
expect(parseXreadgroupReply(null)).toEqual([]);
|
|
@@ -21,9 +21,7 @@ import { createChannelInbox } from "./channel-types.ts";
|
|
|
21
21
|
function formatAddressInput(input: AddressInput): string {
|
|
22
22
|
if (typeof input === "string") return input;
|
|
23
23
|
if (Array.isArray(input)) {
|
|
24
|
-
return input
|
|
25
|
-
.map((t) => (typeof t === "string" ? t : t.address))
|
|
26
|
-
.join(",");
|
|
24
|
+
return input.map((t) => (typeof t === "string" ? t : t.address)).join(",");
|
|
27
25
|
}
|
|
28
26
|
return input.address;
|
|
29
27
|
}
|
|
@@ -33,9 +31,7 @@ function formatAddressInput(input: AddressInput): string {
|
|
|
33
31
|
*
|
|
34
32
|
* @param options - Optional shared inbox
|
|
35
33
|
*/
|
|
36
|
-
export function openConsoleChannel(
|
|
37
|
-
options: ChannelOpenOptions = {},
|
|
38
|
-
): ChannelDriver {
|
|
34
|
+
export function openConsoleChannel(options: ChannelOpenOptions = {}): ChannelDriver {
|
|
39
35
|
const inbox = options.inbox ?? createChannelInbox();
|
|
40
36
|
|
|
41
37
|
const channel: ChannelTransport = {
|
|
@@ -88,7 +84,10 @@ export function openConsoleChannel(
|
|
|
88
84
|
template: mail.template,
|
|
89
85
|
at: Date.now(),
|
|
90
86
|
});
|
|
91
|
-
const recipients = to
|
|
87
|
+
const recipients = to
|
|
88
|
+
.split(",")
|
|
89
|
+
.map((s) => s.trim())
|
|
90
|
+
.filter(Boolean);
|
|
92
91
|
return {
|
|
93
92
|
messageId: id,
|
|
94
93
|
accepted: recipients,
|
|
@@ -15,9 +15,7 @@ import type {
|
|
|
15
15
|
*
|
|
16
16
|
* @param options - `token` (OAuth access token) + `from` (project id)
|
|
17
17
|
*/
|
|
18
|
-
export function openFcmChannel(
|
|
19
|
-
options: ChannelOpenOptions = {},
|
|
20
|
-
): ChannelDriver {
|
|
18
|
+
export function openFcmChannel(options: ChannelOpenOptions = {}): ChannelDriver {
|
|
21
19
|
const accessToken = options.token ?? options.apiKey;
|
|
22
20
|
const projectId = options.from;
|
|
23
21
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
@@ -30,31 +28,25 @@ export function openFcmChannel(
|
|
|
30
28
|
if (!accessToken || !projectId) {
|
|
31
29
|
throw new Error("fcm: token and from (project id) are required");
|
|
32
30
|
}
|
|
33
|
-
const res = await fetchFn(
|
|
34
|
-
|
|
35
|
-
{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Authorization: `Bearer ${accessToken}`,
|
|
39
|
-
"Content-Type": "application/json",
|
|
40
|
-
},
|
|
41
|
-
body: JSON.stringify({
|
|
42
|
-
message: {
|
|
43
|
-
token: message.to,
|
|
44
|
-
notification: {
|
|
45
|
-
title: message.subject ?? message.template ?? "notification",
|
|
46
|
-
body: message.text ?? "",
|
|
47
|
-
},
|
|
48
|
-
data: Object.fromEntries(
|
|
49
|
-
Object.entries(message.data ?? {}).map(([k, v]) => [
|
|
50
|
-
k,
|
|
51
|
-
String(v),
|
|
52
|
-
]),
|
|
53
|
-
),
|
|
54
|
-
},
|
|
55
|
-
}),
|
|
31
|
+
const res = await fetchFn(`${base}/v1/projects/${projectId}/messages:send`, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: {
|
|
34
|
+
Authorization: `Bearer ${accessToken}`,
|
|
35
|
+
"Content-Type": "application/json",
|
|
56
36
|
},
|
|
57
|
-
|
|
37
|
+
body: JSON.stringify({
|
|
38
|
+
message: {
|
|
39
|
+
token: message.to,
|
|
40
|
+
notification: {
|
|
41
|
+
title: message.subject ?? message.template ?? "notification",
|
|
42
|
+
body: message.text ?? "",
|
|
43
|
+
},
|
|
44
|
+
data: Object.fromEntries(
|
|
45
|
+
Object.entries(message.data ?? {}).map(([k, v]) => [k, String(v)]),
|
|
46
|
+
),
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
58
50
|
const body = (await res.json().catch(() => ({}))) as {
|
|
59
51
|
name?: string;
|
|
60
52
|
error?: { message?: string };
|
|
@@ -79,9 +71,7 @@ export function openFcmChannel(
|
|
|
79
71
|
ok: true,
|
|
80
72
|
messageId: id,
|
|
81
73
|
driverId: "fcm",
|
|
82
|
-
attempts: [
|
|
83
|
-
{ driverId: "fcm", ok: true, at: Date.now(), messageId: id },
|
|
84
|
-
],
|
|
74
|
+
attempts: [{ driverId: "fcm", ok: true, at: Date.now(), messageId: id }],
|
|
85
75
|
};
|
|
86
76
|
},
|
|
87
77
|
};
|
|
@@ -10,9 +10,7 @@ import type { ChannelDriver, ChannelOpenOptions } from "./channel-types.ts";
|
|
|
10
10
|
*
|
|
11
11
|
* @param options - API key
|
|
12
12
|
*/
|
|
13
|
-
export function openResendChannel(
|
|
14
|
-
options: ChannelOpenOptions = {},
|
|
15
|
-
): ChannelDriver {
|
|
13
|
+
export function openResendChannel(options: ChannelOpenOptions = {}): ChannelDriver {
|
|
16
14
|
if (!options.apiKey) {
|
|
17
15
|
throw new Error("resend channel: apiKey is required");
|
|
18
16
|
}
|
|
@@ -10,18 +10,14 @@ import type { ChannelDriver, ChannelOpenOptions } from "./channel-types.ts";
|
|
|
10
10
|
*
|
|
11
11
|
* @param options - Host / port / auth
|
|
12
12
|
*/
|
|
13
|
-
export function openSmtpChannel(
|
|
14
|
-
options: ChannelOpenOptions = {},
|
|
15
|
-
): ChannelDriver {
|
|
13
|
+
export function openSmtpChannel(options: ChannelOpenOptions = {}): ChannelDriver {
|
|
16
14
|
if (!options.host) {
|
|
17
15
|
throw new Error("smtp channel: host is required");
|
|
18
16
|
}
|
|
19
17
|
const transport = new SMTPTransport({
|
|
20
18
|
host: options.host,
|
|
21
19
|
port: options.port ?? 587,
|
|
22
|
-
...(options.user && options.pass
|
|
23
|
-
? { auth: { user: options.user, pass: options.pass } }
|
|
24
|
-
: {}),
|
|
20
|
+
...(options.user && options.pass ? { auth: { user: options.user, pass: options.pass } } : {}),
|
|
25
21
|
});
|
|
26
22
|
return { id: "smtp", transport };
|
|
27
23
|
}
|
|
@@ -5,12 +5,7 @@
|
|
|
5
5
|
* run unchanged. Non-email media (sms / whatsapp / push) use {@link ChannelTransport}.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
9
|
-
MailOptions,
|
|
10
|
-
SendResult,
|
|
11
|
-
Transport,
|
|
12
|
-
VerifyResult,
|
|
13
|
-
} from "sently";
|
|
8
|
+
import type { MailOptions, SendResult, Transport, VerifyResult } from "sently";
|
|
14
9
|
|
|
15
10
|
export type {
|
|
16
11
|
Address,
|
|
@@ -35,12 +30,7 @@ export type ChannelDriverId =
|
|
|
35
30
|
| "webpush";
|
|
36
31
|
|
|
37
32
|
/** Channel medium. */
|
|
38
|
-
export type ChannelMediumId =
|
|
39
|
-
| "email"
|
|
40
|
-
| "sms"
|
|
41
|
-
| "whatsapp"
|
|
42
|
-
| "push"
|
|
43
|
-
| "any";
|
|
33
|
+
export type ChannelMediumId = "email" | "sms" | "whatsapp" | "push" | "any";
|
|
44
34
|
|
|
45
35
|
/** Unified outbound message (medium-agnostic). */
|
|
46
36
|
export interface ChannelMessage {
|
|
@@ -15,9 +15,7 @@ import type {
|
|
|
15
15
|
*
|
|
16
16
|
* @param options - `apiKey` + optional `from` (sender id)
|
|
17
17
|
*/
|
|
18
|
-
export function openUnifonicChannel(
|
|
19
|
-
options: ChannelOpenOptions = {},
|
|
20
|
-
): ChannelDriver {
|
|
18
|
+
export function openUnifonicChannel(options: ChannelOpenOptions = {}): ChannelDriver {
|
|
21
19
|
const apiKey = options.apiKey;
|
|
22
20
|
const from = options.from ?? "OKE";
|
|
23
21
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
@@ -62,9 +60,7 @@ export function openUnifonicChannel(
|
|
|
62
60
|
ok: true,
|
|
63
61
|
messageId: id,
|
|
64
62
|
driverId: "unifonic",
|
|
65
|
-
attempts: [
|
|
66
|
-
{ driverId: "unifonic", ok: true, at: Date.now(), messageId: id },
|
|
67
|
-
],
|
|
63
|
+
attempts: [{ driverId: "unifonic", ok: true, at: Date.now(), messageId: id }],
|
|
68
64
|
};
|
|
69
65
|
},
|
|
70
66
|
};
|
|
@@ -15,9 +15,7 @@ import type {
|
|
|
15
15
|
*
|
|
16
16
|
* @param options - `token` (access token) + `from` (phone number id)
|
|
17
17
|
*/
|
|
18
|
-
export function openWaCloudChannel(
|
|
19
|
-
options: ChannelOpenOptions = {},
|
|
20
|
-
): ChannelDriver {
|
|
18
|
+
export function openWaCloudChannel(options: ChannelOpenOptions = {}): ChannelDriver {
|
|
21
19
|
const token = options.token ?? options.apiKey;
|
|
22
20
|
const phoneNumberId = options.from;
|
|
23
21
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
@@ -67,9 +65,7 @@ export function openWaCloudChannel(
|
|
|
67
65
|
ok: true,
|
|
68
66
|
messageId: id,
|
|
69
67
|
driverId: "wa-cloud",
|
|
70
|
-
attempts: [
|
|
71
|
-
{ driverId: "wa-cloud", ok: true, at: Date.now(), messageId: id },
|
|
72
|
-
],
|
|
68
|
+
attempts: [{ driverId: "wa-cloud", ok: true, at: Date.now(), messageId: id }],
|
|
73
69
|
};
|
|
74
70
|
},
|
|
75
71
|
};
|
|
@@ -47,9 +47,7 @@ function b64urlEncode(bytes: Uint8Array): string {
|
|
|
47
47
|
*
|
|
48
48
|
* @param privateKeyB64 - Base64url private key
|
|
49
49
|
*/
|
|
50
|
-
async function importVapidPrivateKey(
|
|
51
|
-
privateKeyB64: string,
|
|
52
|
-
): Promise<CryptoKey> {
|
|
50
|
+
async function importVapidPrivateKey(privateKeyB64: string): Promise<CryptoKey> {
|
|
53
51
|
const raw = b64urlDecode(privateKeyB64);
|
|
54
52
|
// Prefer PKCS8; fall back to raw JWK construction for 32-byte seeds.
|
|
55
53
|
if (raw.length > 32) {
|
|
@@ -64,11 +62,10 @@ async function importVapidPrivateKey(
|
|
|
64
62
|
// Build a minimal JWK from d (and a synthetic public x/y via derive is hard);
|
|
65
63
|
// tests inject fetch and only need Authorization header shape — use ECDSA
|
|
66
64
|
// with a generated key when raw seed is provided without full PKCS8.
|
|
67
|
-
const pair = await crypto.subtle.generateKey(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
);
|
|
65
|
+
const pair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, [
|
|
66
|
+
"sign",
|
|
67
|
+
"verify",
|
|
68
|
+
]);
|
|
72
69
|
return pair.privateKey;
|
|
73
70
|
}
|
|
74
71
|
|
|
@@ -89,17 +86,11 @@ async function buildVapidJwt(
|
|
|
89
86
|
);
|
|
90
87
|
const exp = Math.floor(Date.now() / 1000) + 12 * 60 * 60;
|
|
91
88
|
const payload = b64urlEncode(
|
|
92
|
-
new TextEncoder().encode(
|
|
93
|
-
JSON.stringify({ aud: audience, exp, sub: subject }),
|
|
94
|
-
),
|
|
89
|
+
new TextEncoder().encode(JSON.stringify({ aud: audience, exp, sub: subject })),
|
|
95
90
|
);
|
|
96
91
|
const data = new TextEncoder().encode(`${header}.${payload}`);
|
|
97
92
|
const sig = new Uint8Array(
|
|
98
|
-
await crypto.subtle.sign(
|
|
99
|
-
{ name: "ECDSA", hash: "SHA-256" },
|
|
100
|
-
privateKey,
|
|
101
|
-
data,
|
|
102
|
-
),
|
|
93
|
+
await crypto.subtle.sign({ name: "ECDSA", hash: "SHA-256" }, privateKey, data),
|
|
103
94
|
);
|
|
104
95
|
// Convert DER → raw r||s if needed; Web Crypto in Bun returns raw P-1363.
|
|
105
96
|
return `${header}.${payload}.${b64urlEncode(sig)}`;
|
|
@@ -127,29 +118,19 @@ async function encryptPushBody(
|
|
|
127
118
|
true,
|
|
128
119
|
[],
|
|
129
120
|
);
|
|
130
|
-
const local = await crypto.subtle.generateKey(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
["deriveBits"],
|
|
134
|
-
);
|
|
121
|
+
const local = await crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, true, [
|
|
122
|
+
"deriveBits",
|
|
123
|
+
]);
|
|
135
124
|
const shared = new Uint8Array(
|
|
136
|
-
await crypto.subtle.deriveBits(
|
|
137
|
-
{ name: "ECDH", public: userPublic },
|
|
138
|
-
local.privateKey,
|
|
139
|
-
256,
|
|
140
|
-
),
|
|
125
|
+
await crypto.subtle.deriveBits({ name: "ECDH", public: userPublic }, local.privateKey, 256),
|
|
141
126
|
);
|
|
142
127
|
const salt = crypto.getRandomValues(new Uint8Array(16));
|
|
143
128
|
const authSecret = b64urlDecode(auth);
|
|
144
129
|
|
|
145
130
|
// HKDF-SHA-256 as in RFC 8291
|
|
146
|
-
const ikmKey = await crypto.subtle.importKey(
|
|
147
|
-
"
|
|
148
|
-
|
|
149
|
-
"HKDF",
|
|
150
|
-
false,
|
|
151
|
-
["deriveBits"],
|
|
152
|
-
);
|
|
131
|
+
const ikmKey = await crypto.subtle.importKey("raw", asBufferSource(shared), "HKDF", false, [
|
|
132
|
+
"deriveBits",
|
|
133
|
+
]);
|
|
153
134
|
const prk = new Uint8Array(
|
|
154
135
|
await crypto.subtle.deriveBits(
|
|
155
136
|
{
|
|
@@ -163,9 +144,7 @@ async function encryptPushBody(
|
|
|
163
144
|
),
|
|
164
145
|
);
|
|
165
146
|
// Simplified content encryption key / nonce derivation for aes128gcm
|
|
166
|
-
const prkKey = await crypto.subtle.importKey("raw", prk, "HKDF", false, [
|
|
167
|
-
"deriveBits",
|
|
168
|
-
]);
|
|
147
|
+
const prkKey = await crypto.subtle.importKey("raw", prk, "HKDF", false, ["deriveBits"]);
|
|
169
148
|
const cek = new Uint8Array(
|
|
170
149
|
await crypto.subtle.deriveBits(
|
|
171
150
|
{
|
|
@@ -190,13 +169,7 @@ async function encryptPushBody(
|
|
|
190
169
|
96,
|
|
191
170
|
),
|
|
192
171
|
);
|
|
193
|
-
const aes = await crypto.subtle.importKey(
|
|
194
|
-
"raw",
|
|
195
|
-
cek,
|
|
196
|
-
{ name: "AES-GCM" },
|
|
197
|
-
false,
|
|
198
|
-
["encrypt"],
|
|
199
|
-
);
|
|
172
|
+
const aes = await crypto.subtle.importKey("raw", cek, { name: "AES-GCM" }, false, ["encrypt"]);
|
|
200
173
|
// Add RFC 8188 padding delimiter (0x02) then encrypt
|
|
201
174
|
const padded = new Uint8Array(plaintext.length + 1);
|
|
202
175
|
padded.set(plaintext, 0);
|
|
@@ -204,17 +177,13 @@ async function encryptPushBody(
|
|
|
204
177
|
const ciphertext = new Uint8Array(
|
|
205
178
|
await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, aes, padded),
|
|
206
179
|
);
|
|
207
|
-
const localPublic = new Uint8Array(
|
|
208
|
-
await crypto.subtle.exportKey("raw", local.publicKey),
|
|
209
|
-
);
|
|
180
|
+
const localPublic = new Uint8Array(await crypto.subtle.exportKey("raw", local.publicKey));
|
|
210
181
|
|
|
211
182
|
// Body = salt (16) || rs (4) || idlen (1) || keyid || ciphertext
|
|
212
183
|
const rs = new Uint8Array(4);
|
|
213
184
|
new DataView(rs.buffer).setUint32(0, 4096);
|
|
214
185
|
const idlen = new Uint8Array([localPublic.length]);
|
|
215
|
-
const body = new Uint8Array(
|
|
216
|
-
16 + 4 + 1 + localPublic.length + ciphertext.length,
|
|
217
|
-
);
|
|
186
|
+
const body = new Uint8Array(16 + 4 + 1 + localPublic.length + ciphertext.length);
|
|
218
187
|
body.set(salt, 0);
|
|
219
188
|
body.set(rs, 16);
|
|
220
189
|
body.set(idlen, 20);
|
|
@@ -228,9 +197,7 @@ async function encryptPushBody(
|
|
|
228
197
|
*
|
|
229
198
|
* @param options - VAPID keys + subject
|
|
230
199
|
*/
|
|
231
|
-
export function openWebPushChannel(
|
|
232
|
-
options: ChannelOpenOptions = {},
|
|
233
|
-
): ChannelDriver {
|
|
200
|
+
export function openWebPushChannel(options: ChannelOpenOptions = {}): ChannelDriver {
|
|
234
201
|
const vapidPublic = options.vapidPublicKey;
|
|
235
202
|
const vapidPrivate = options.vapidPrivateKey;
|
|
236
203
|
const subject = options.vapidSubject ?? "mailto:ops@oke.local";
|
|
@@ -263,11 +230,7 @@ export function openWebPushChannel(
|
|
|
263
230
|
};
|
|
264
231
|
|
|
265
232
|
if (sub?.keys?.p256dh && sub.keys.auth) {
|
|
266
|
-
const enc = await encryptPushBody(
|
|
267
|
-
plaintext,
|
|
268
|
-
sub.keys.p256dh,
|
|
269
|
-
sub.keys.auth,
|
|
270
|
-
);
|
|
233
|
+
const enc = await encryptPushBody(plaintext, sub.keys.p256dh, sub.keys.auth);
|
|
271
234
|
body = enc.body;
|
|
272
235
|
headers["Content-Encoding"] = "aes128gcm";
|
|
273
236
|
headers["Content-Type"] = "application/octet-stream";
|
|
@@ -300,9 +263,7 @@ export function openWebPushChannel(
|
|
|
300
263
|
ok: true,
|
|
301
264
|
messageId: id,
|
|
302
265
|
driverId: "webpush",
|
|
303
|
-
attempts: [
|
|
304
|
-
{ driverId: "webpush", ok: true, at: Date.now(), messageId: id },
|
|
305
|
-
],
|
|
266
|
+
attempts: [{ driverId: "webpush", ok: true, at: Date.now(), messageId: id }],
|
|
306
267
|
};
|
|
307
268
|
},
|
|
308
269
|
};
|