@cosmicdrift/kumiko-samples 0.344.0 → 0.346.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 +1 -1
- package/packages/bundled-features/package.json +1 -1
- package/packages/bundled-features/src/audit/changes.json +12 -0
- package/packages/bundled-features/src/audit/constants.ts +5 -0
- package/packages/bundled-features/src/audit/feature.ts +1 -1
- package/packages/bundled-features/src/audit/handlers/details.query.ts +14 -3
- package/packages/bundled-features/src/audit/handlers/list.query.ts +11 -2
- package/packages/bundled-features/src/audit/handlers/resolve-audit-tenant.ts +22 -0
- package/packages/bundled-features/src/audit/i18n.ts +3 -0
- package/packages/bundled-features/src/audit/run-escape-hatch-retention.ts +31 -12
- package/packages/bundled-features/src/auth-email-password/changes.json +24 -0
- package/packages/bundled-features/src/auth-email-password/constants.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/feature.ts +9 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +33 -10
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +32 -15
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +60 -0
- package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +8 -1
- package/packages/bundled-features/src/auth-email-password/i18n.ts +2 -0
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +20 -7
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +11 -1
- package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
- package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +31 -11
- package/packages/bundled-features/src/step-dispatcher/changes.json +31 -0
- package/packages/bundled-features/src/step-dispatcher/dispatch-payload.ts +144 -0
- package/packages/bundled-features/src/step-dispatcher/feature.ts +32 -152
- package/packages/bundled-features/src/step-dispatcher/webhook-runner.ts +30 -3
- package/packages/bundled-features/src/tier-engine/constants.ts +7 -0
- package/packages/bundled-features/src/tier-engine/entity.ts +2 -4
- package/packages/bundled-features/src/tier-engine/feature.ts +7 -2
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +10 -4
- package/packages/bundled-features/src/tier-engine/index.ts +6 -1
- package/samples/apps/use-all-bundled/feature-manifest.json +3 -2
- package/samples/recipes/i18n/README.md +1 -1
- package/samples/recipes/rate-limiting/README.md +1 -1
- package/samples/recipes/webhook-step/README.md +9 -2
- package/samples/recipes/webhook-step/package.json +1 -1
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { defineWriteHandler, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
8
|
import * as z from "zod";
|
|
9
9
|
import { tierAssignmentAggregateId } from "../aggregate-id.js";
|
|
10
|
+
import { TierAssignmentSources } from "../constants.js";
|
|
10
11
|
import { type TierAssignmentRow, tierAssignmentEntity } from "../entity.js";
|
|
11
12
|
|
|
12
13
|
// SystemAdmin setzt das Tier eines BELIEBIGEN Tenants — manueller Grant ohne
|
|
@@ -21,8 +22,8 @@ import { type TierAssignmentRow, tierAssignmentEntity } from "../entity.js";
|
|
|
21
22
|
// funktioniert nur für SYSTEM_TENANT_ID (immer im IN-Filter). Dies ist das
|
|
22
23
|
// auto-default-Hook-Muster (feature.ts), generalisiert auf einen Request-Handler.
|
|
23
24
|
//
|
|
24
|
-
// `source:
|
|
25
|
-
//
|
|
25
|
+
// `source: TierAssignmentSources.manual` marks the grant so the billing sync skips it.
|
|
26
|
+
// Upsert: one aggregate per tenant (deterministic aggregate id).
|
|
26
27
|
//
|
|
27
28
|
// Effective-set invalidation: the executor write does not fire the
|
|
28
29
|
// `tier-assignment:postSave` entity hook, and a per-handler postSave would not
|
|
@@ -90,7 +91,7 @@ export function createSetTenantTierWrite(opts: SetTenantTierOptions = {}) {
|
|
|
90
91
|
{
|
|
91
92
|
id: existing.id,
|
|
92
93
|
version: existing.version,
|
|
93
|
-
changes: { tier, source:
|
|
94
|
+
changes: { tier, source: TierAssignmentSources.manual },
|
|
94
95
|
},
|
|
95
96
|
systemUser,
|
|
96
97
|
tdb,
|
|
@@ -101,7 +102,12 @@ export function createSetTenantTierWrite(opts: SetTenantTierOptions = {}) {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
const result = await executor.create(
|
|
104
|
-
{
|
|
105
|
+
{
|
|
106
|
+
id: tierAssignmentAggregateId(tenantId),
|
|
107
|
+
tier,
|
|
108
|
+
source: TierAssignmentSources.manual,
|
|
109
|
+
tenantId,
|
|
110
|
+
},
|
|
105
111
|
systemUser,
|
|
106
112
|
tdb,
|
|
107
113
|
);
|
|
@@ -17,7 +17,12 @@ export {
|
|
|
17
17
|
type TierDefinition,
|
|
18
18
|
type TierMap,
|
|
19
19
|
} from "./compose-app.js";
|
|
20
|
-
export {
|
|
20
|
+
export {
|
|
21
|
+
TIER_ENGINE_FEATURE,
|
|
22
|
+
TierAssignmentSources,
|
|
23
|
+
TierEngineHandlers,
|
|
24
|
+
TierEngineQueries,
|
|
25
|
+
} from "./constants.js";
|
|
21
26
|
export { tierAssignmentEntity } from "./entity.js";
|
|
22
27
|
export {
|
|
23
28
|
type CreateTierEngineOptions,
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"name": "audit",
|
|
54
|
-
"description": "Exposes the framework's event store as a paginated, filterable audit log via the `audit:query:list` handler (accessible to `Admin` and `SystemAdmin` roles). No separate table or projection — the event store is the audit trail by construction: every entity write already records who, when, what entity, and the event payload with PII stripped. Filter by `aggregateType`, `aggregateId`, `eventType`, `userId`, or time range. Also records `audit:event:escape-hatch-used` whenever a handler uses one of the framework's escape hatches (unsafeRaw, acknowledgeCrossTenant, db.global() writes, or a granted identity switch).",
|
|
54
|
+
"description": "Exposes the framework's event store as a paginated, filterable audit log via the `audit:query:list` handler (accessible to `Admin` and `SystemAdmin` roles). No separate table or projection — the event store is the audit trail by construction: every entity write already records who, when, what entity, and the event payload with PII stripped. A SystemAdmin can pass `scope: \"system\"` to read the app-instance system events such as `app.started`. Filter by `aggregateType`, `aggregateId`, `eventType`, `userId`, or time range. Also records `audit:event:escape-hatch-used` whenever a handler uses one of the framework's escape hatches (unsafeRaw, acknowledgeCrossTenant, db.global() writes, or a granted identity switch).",
|
|
55
55
|
"toggleableDefault": null,
|
|
56
56
|
"requires": [
|
|
57
57
|
"tenant",
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"auth-email-password:write:reset-password",
|
|
128
128
|
"auth-email-password:write:signup-confirm",
|
|
129
129
|
"auth-email-password:write:signup-request",
|
|
130
|
+
"auth-email-password:write:switch-tenant-mfa-gate",
|
|
130
131
|
"auth-email-password:write:system-invite-create",
|
|
131
132
|
"auth-email-password:write:verify-email"
|
|
132
133
|
],
|
|
@@ -2301,7 +2302,7 @@
|
|
|
2301
2302
|
},
|
|
2302
2303
|
{
|
|
2303
2304
|
"name": "step-dispatcher",
|
|
2304
|
-
"description": "Internal system feature that drains deferred Tier-2 side-effects (currently `webhook.send` and `mail.send`) after their originating transaction commits. Listens via `r.multiStreamProjection` on the `kumiko:system:step.dispatch-requested` system event, performs the actual HTTP or mail delivery, then appends `kumiko:system:step.dispatched` or `kumiko:system:step.dispatch-failed` back onto the same stream so the outcome is recorded in the event log without a separate status table. Mount this feature explicitly via `createStepDispatcherFeature()` in your app's feature list alongside any features that use `r.step.webhook.send` or `r.step.mail.send`. Requires the `secrets` feature (`createSecretsFeature()`) to be mounted — `webhook.send` auth resolves per-tenant through it, under `step-dispatcher:webhook-auth.<name>`.",
|
|
2305
|
+
"description": "Internal system feature that drains deferred Tier-2 side-effects (currently `webhook.send` and `mail.send`) after their originating transaction commits. Listens via `r.multiStreamProjection` on the `kumiko:system:step.dispatch-requested` system event, performs the actual HTTP or mail delivery, then appends `kumiko:system:step.dispatched` or `kumiko:system:step.dispatch-failed` back onto the same stream so the outcome is recorded in the event log without a separate status table. Mount this feature explicitly via `createStepDispatcherFeature()` in your app's feature list alongside any features that use `r.step.webhook.send` or `r.step.mail.send`. Requires the `secrets` feature (`createSecretsFeature()`) to be mounted — `webhook.send` auth resolves per-tenant through it, under `step-dispatcher:webhook-auth.<name>`. Every `webhook.send` request carries `Idempotency-Key: <dispatch stream id>`, stable across redeliveries of the same dispatch request; an explicit `Idempotency-Key` in `headers` takes precedence.",
|
|
2305
2306
|
"toggleableDefault": null,
|
|
2306
2307
|
"requires": [
|
|
2307
2308
|
"secrets"
|
|
@@ -13,7 +13,7 @@ A translation value can be a CLDR plural-forms object instead of a plain
|
|
|
13
13
|
string. `other` is required; the rest (`zero`/`one`/`two`/`few`/`many`) only
|
|
14
14
|
exist where the locale's grammar needs them:
|
|
15
15
|
|
|
16
|
-
```ts
|
|
16
|
+
```ts illustration
|
|
17
17
|
"greeting.unread_count": {
|
|
18
18
|
de: { one: "{count} ungelesene Nachricht", other: "{count} ungelesene Nachrichten" },
|
|
19
19
|
en: { one: "{count} unread message", other: "{count} unread messages" },
|
|
@@ -12,7 +12,7 @@ End-to-end rate limiting: L1 global-IP + L2 auth + L3 handler opt-in.
|
|
|
12
12
|
A public write handler that mails an address typed by the caller is also limited per
|
|
13
13
|
address, so rotating IPs does not help against mail flooding. Declare it next to `rateLimit`:
|
|
14
14
|
|
|
15
|
-
```ts
|
|
15
|
+
```ts illustration
|
|
16
16
|
r.writeHandler({
|
|
17
17
|
// ...
|
|
18
18
|
access: { roles: ["anonymous"] },
|
|
@@ -5,7 +5,7 @@ Workflow / pipeline step that calls an HTTP webhook.
|
|
|
5
5
|
## What it shows
|
|
6
6
|
|
|
7
7
|
- Webhook step registration in a workflow
|
|
8
|
-
-
|
|
8
|
+
- Failure surface for outbound HTTP (one delivery attempt per request)
|
|
9
9
|
- Authenticated webhooks via a tenant-owned secret (`incident:open-authenticated`)
|
|
10
10
|
|
|
11
11
|
## Auth secret
|
|
@@ -16,7 +16,7 @@ never a process-wide env var. The `secrets` feature must be mounted
|
|
|
16
16
|
(`createSecretsFeature()` + a `MasterKeyProvider`) alongside
|
|
17
17
|
`step-dispatcher`. Set the secret per tenant before dispatching:
|
|
18
18
|
|
|
19
|
-
```ts
|
|
19
|
+
```ts illustration
|
|
20
20
|
await stack.http.writeOk(
|
|
21
21
|
"secrets:write:set",
|
|
22
22
|
{ key: "step-dispatcher:webhook-auth.incident-hook", value: "<token>" },
|
|
@@ -33,6 +33,13 @@ Never combine `auth.secret` with a caller-controlled `url`: the caller would
|
|
|
33
33
|
receive the secret as the `Authorization` header. `incident:open-authenticated`
|
|
34
34
|
therefore posts to a fixed URL.
|
|
35
35
|
|
|
36
|
+
## Idempotency-Key
|
|
37
|
+
|
|
38
|
+
Every webhook request carries `Idempotency-Key: <dispatch stream id>`. The
|
|
39
|
+
value is the same when the same dispatch request is delivered again, so a
|
|
40
|
+
receiver can deduplicate redelivered calls. An `Idempotency-Key` set explicitly in
|
|
41
|
+
`headers` (any casing) wins.
|
|
42
|
+
|
|
36
43
|
## Source
|
|
37
44
|
|
|
38
45
|
Feature entry point: `src/feature.ts`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-sample-webhook-step",
|
|
3
|
-
"description": "Tier-2 r.step.webhook.send showcase: deferred webhook dispatch via step-dispatcher subscription, no outbox table
|
|
3
|
+
"description": "Tier-2 r.step.webhook.send showcase: deferred webhook dispatch via step-dispatcher subscription, no outbox table.",
|
|
4
4
|
"private": true,
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@cosmicdrift/kumiko-bundled-features": "workspace:*",
|