@cosmicdrift/kumiko-bundled-features 0.365.0 → 0.366.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/dist/admin-shell/feature.js +9 -9
- package/dist/agent-tools/tool-dispatch.d.ts +9 -1
- package/dist/agent-tools/tool-dispatch.js +55 -5
- package/dist/audit/feature.js +1 -1
- package/dist/auth-email-password/constants.d.ts +0 -1
- package/dist/auth-email-password/constants.js +0 -2
- package/dist/auth-email-password/feature.js +3 -3
- package/dist/auth-email-password/handlers/invite-create.write.js +1 -0
- package/dist/auth-mfa/feature.js +4 -4
- package/dist/auth-mfa-user-data/index.js +1 -1
- package/dist/billing-foundation/consumer-protection/register-consent.js +1 -1
- package/dist/billing-foundation/feature.js +1 -1
- package/dist/cap-counter/cap-reservation.js +73 -25
- package/dist/cap-counter/constants.d.ts +1 -0
- package/dist/cap-counter/constants.js +2 -0
- package/dist/cap-counter/feature.js +2 -2
- package/dist/cap-counter/tables.js +5 -2
- package/dist/cap-overview/feature.js +3 -3
- package/dist/channel-discord/feature.js +2 -2
- package/dist/channel-email/feature.js +1 -1
- package/dist/channel-in-app/feature.js +1 -1
- package/dist/channel-push/feature.js +1 -1
- package/dist/channel-slack/feature.js +2 -2
- package/dist/channel-teams/feature.js +2 -2
- package/dist/channel-telegram/feature.js +2 -2
- package/dist/compliance-profiles/feature.js +1 -1
- package/dist/compliance-profiles-ops/index.js +3 -3
- package/dist/config/feature.js +1 -1
- package/dist/custom-fields/feature.js +2 -2
- package/dist/custom-fields/wire-for-entity.js +17 -13
- package/dist/data-retention/feature.js +1 -1
- package/dist/data-retention/presets.d.ts +4 -4
- package/dist/delivery/db/queries/address-opt-outs.d.ts +1 -1
- package/dist/delivery/db/queries/address-opt-outs.js +6 -2
- package/dist/delivery/db/queries/preferences.d.ts +1 -1
- package/dist/delivery/db/queries/preferences.js +4 -4
- package/dist/delivery/delivery-service.js +9 -2
- package/dist/delivery/feature.js +9 -5
- package/dist/delivery/handlers/resubscribe-address.write.js +13 -9
- package/dist/delivery/handlers/resubscribe-user.write.js +3 -1
- package/dist/delivery/handlers/set-preference.write.js +3 -1
- package/dist/delivery/handlers/unsubscribe-address.write.js +3 -1
- package/dist/delivery/handlers/unsubscribe-user.write.js +3 -1
- package/dist/delivery/notification-type-aliases.d.ts +3 -0
- package/dist/delivery/notification-type-aliases.js +11 -0
- package/dist/derivatives-sharp/feature.js +1 -1
- package/dist/document-ingest-foundation/feature.js +2 -2
- package/dist/file-derivatives/feature.js +3 -3
- package/dist/file-foundation/feature.js +1 -1
- package/dist/file-provider-inmemory/feature.js +2 -2
- package/dist/file-provider-s3/feature.js +3 -3
- package/dist/file-provider-s3-env/feature.js +2 -2
- package/dist/files-tenant-data/index.js +1 -1
- package/dist/folders/feature.js +2 -2
- package/dist/folders-user-data/index.js +1 -1
- package/dist/form-draft/feature.js +2 -2
- package/dist/form-draft-user-data/index.js +1 -1
- package/dist/inbound-mail-foundation/connect-routes.d.ts +3 -0
- package/dist/inbound-mail-foundation/connect-routes.js +6 -1
- package/dist/inbound-mail-foundation/feature.js +1 -1
- package/dist/inbound-mail-foundation/types.d.ts +17 -7
- package/dist/inbound-mail-foundation/watch-supervisor.js +16 -2
- package/dist/inbound-provider-imap/feature.js +2 -2
- package/dist/inbound-provider-inmemory/feature.js +1 -1
- package/dist/ledger/feature.js +5 -5
- package/dist/legal-pages/feature.js +1 -1
- package/dist/mail-foundation/feature.js +1 -1
- package/dist/mail-transport-inmemory/feature.js +2 -2
- package/dist/mail-transport-smtp/feature.js +3 -3
- package/dist/managed-pages/css-gate.js +1 -1
- package/dist/managed-pages/feature.js +2 -2
- package/dist/metrics/feature.js +2 -2
- package/dist/notes-history/feature.js +2 -2
- package/dist/notes-history-user-data/index.js +1 -1
- package/dist/personal-access-tokens/feature.js +17 -13
- package/dist/readiness/feature.js +2 -2
- package/dist/renderer-foundation/feature.js +1 -1
- package/dist/renderer-pdf/feature.js +1 -1
- package/dist/secrets/feature.js +1 -1
- package/dist/seo/feature.js +1 -1
- package/dist/sessions/feature.js +20 -16
- package/dist/step-dispatcher/constants.d.ts +10 -0
- package/dist/step-dispatcher/constants.js +17 -0
- package/dist/step-dispatcher/deliver-dispatch-request.d.ts +14 -0
- package/dist/step-dispatcher/deliver-dispatch-request.js +163 -0
- package/dist/step-dispatcher/feature.js +48 -101
- package/dist/step-dispatcher/webhook-runner.d.ts +7 -4
- package/dist/step-dispatcher/webhook-runner.js +26 -11
- package/dist/subscription-mollie/feature.js +1 -1
- package/dist/subscription-stripe/feature.js +3 -3
- package/dist/tags/feature.js +2 -2
- package/dist/template-resolver/feature.js +2 -2
- package/dist/template-resolver-user-data/index.js +1 -1
- package/dist/tenant/feature.js +4 -4
- package/dist/tenant/seeding.js +1 -1
- package/dist/tenant-lifecycle/feature.js +2 -3
- package/dist/tenant-lifecycle/stages.js +4 -1
- package/dist/tenant-settings/feature.js +1 -1
- package/dist/tier-engine/feature.js +86 -72
- package/dist/user/feature.js +1 -1
- package/dist/user-data-rights/feature.js +4 -4
- package/dist/user-data-rights-defaults/feature.js +2 -2
- package/dist/user-profile/feature.js +4 -4
- package/dist/waitlist/feature.js +2 -2
- package/package.json +10 -10
- package/src/agent-tools/changes.json +6 -0
- package/src/auth-email-password/changes.json +13 -0
- package/src/cap-counter/changes.json +7 -0
- package/src/crypto-shredding/changes.json +13 -0
- package/src/delivery/changes.json +6 -0
- package/src/inbound-mail-foundation/changes.json +13 -0
- package/src/step-dispatcher/changes.json +8 -1
|
@@ -126,9 +126,9 @@ export function createTierEngineFeature(opts = {}) {
|
|
|
126
126
|
category: "billing",
|
|
127
127
|
recommended: false,
|
|
128
128
|
});
|
|
129
|
-
r.requires("config");
|
|
130
|
-
r.requires("tenant");
|
|
131
|
-
r.entity("tier-assignment", tierAssignmentEntity);
|
|
129
|
+
r.requires({ features: ["config"] });
|
|
130
|
+
r.requires({ features: ["tenant"] });
|
|
131
|
+
r.entity({ name: "tier-assignment", ...tierAssignmentEntity });
|
|
132
132
|
// Standard-CRUD via Helper.
|
|
133
133
|
r.writeHandler(defineEntityCreateHandler("tier-assignment", tierAssignmentEntity, {
|
|
134
134
|
...writeAccess,
|
|
@@ -265,27 +265,35 @@ export function createTierEngineFeature(opts = {}) {
|
|
|
265
265
|
};
|
|
266
266
|
onTierAssigned.fn = applyAssignment;
|
|
267
267
|
// Invalidation: tier-assignment CRUD events (e.g. the billing webhook) update the cache.
|
|
268
|
-
r.hook(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
268
|
+
r.hook({
|
|
269
|
+
type: "postSave",
|
|
270
|
+
target: { allOf: "tier-assignment" },
|
|
271
|
+
handler: async (result) => {
|
|
272
|
+
// result.data has tenantId + tier (after entity-update merge)
|
|
273
|
+
const data = result.data; // @cast-boundary engine-payload
|
|
274
|
+
// skip: defensive guard on the payload shape. Correct entity events
|
|
275
|
+
// always carry both fields as strings; a malformed payload (a custom
|
|
276
|
+
// handler bug) skips the cache update instead of throwing, because a
|
|
277
|
+
// hook error must not block the lifecycle pipeline (afterCommit,
|
|
278
|
+
// best-effort side effect).
|
|
279
|
+
if (typeof data.tenantId !== "string" || typeof data.tier !== "string")
|
|
280
|
+
return;
|
|
281
|
+
applyAssignment(data.tenantId, data.tier);
|
|
282
|
+
},
|
|
279
283
|
});
|
|
280
|
-
r.hook(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
284
|
+
r.hook({
|
|
285
|
+
type: "postDelete",
|
|
286
|
+
target: { allOf: "tier-assignment" },
|
|
287
|
+
handler: async (payload) => {
|
|
288
|
+
const data = payload.data; // @cast-boundary engine-payload
|
|
289
|
+
// skip: gleiche type-guard semantik wie postSave-hook oben.
|
|
290
|
+
if (typeof data.tenantId !== "string")
|
|
291
|
+
return;
|
|
292
|
+
const tenantId = data.tenantId;
|
|
293
|
+
takeTicket(tenantId);
|
|
294
|
+
cache.delete(tenantId);
|
|
295
|
+
publishAssignmentChange(tenantId);
|
|
296
|
+
},
|
|
289
297
|
});
|
|
290
298
|
// Auto-default-tier-on-tenant-signup: hook fires inTransaction (atomic
|
|
291
299
|
// mit tenant-create rollback), schreibt tier-assignment via Direct-
|
|
@@ -302,55 +310,61 @@ export function createTierEngineFeature(opts = {}) {
|
|
|
302
310
|
if (opts.defaultTier !== undefined) {
|
|
303
311
|
const defaultTier = opts.defaultTier;
|
|
304
312
|
const autoDefaultTierHookReason = "seeds the default tier-assignment stream of the tenant just created";
|
|
305
|
-
r.hook(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
313
|
+
r.hook({
|
|
314
|
+
type: "postSave",
|
|
315
|
+
target: { allOf: "tenant" },
|
|
316
|
+
handler: async (result, ctx) => {
|
|
317
|
+
// result-shape: kumiko-framework's SaveContext mit isNew + data
|
|
318
|
+
const saveResult = result; // @cast-boundary engine-payload
|
|
319
|
+
// skip: nur bei tenant-create (initial) — tenant-updates feuern
|
|
320
|
+
// auch postSave aber wir wollen kein neues tier-assignment bei
|
|
321
|
+
// re-keying oder name-update.
|
|
322
|
+
if (saveResult.isNew !== true)
|
|
323
|
+
return;
|
|
324
|
+
const data = saveResult.data; // @cast-boundary engine-payload
|
|
325
|
+
// skip: defensive type-guard. Tenant-entity hat id zwingend, aber
|
|
326
|
+
// CrudExecutor's payload-shape ist runtime-unknown.
|
|
327
|
+
if (typeof data.id !== "string")
|
|
328
|
+
return;
|
|
329
|
+
const newTenantId = data.id; // @cast-boundary engine-payload
|
|
330
|
+
const aggregateId = tierAssignmentAggregateId(newTenantId);
|
|
331
|
+
// tenant is an r.systemScope() feature, so this cross-feature hook gets a
|
|
332
|
+
// fail-closed ctx.db — reach for ctx.systemDb instead (see entity-handlers.ts).
|
|
333
|
+
// Event-store paths need the raw DbConnection — TenantDb only exposes
|
|
334
|
+
// select/insert/update/delete, not execute (db.execute(sql`SELECT pg_notify(...)`) would TypeError).
|
|
335
|
+
const rawDb = ctx.systemDb
|
|
336
|
+
? ctx.systemDb.unsafeRaw(autoDefaultTierHookReason)
|
|
337
|
+
: ctx.db && "unsafeRaw" in ctx.db
|
|
338
|
+
? ctx.db.unsafeRaw()
|
|
339
|
+
: undefined;
|
|
340
|
+
// skip: defensive — inTransaction phase always sets db, but AppContext's
|
|
341
|
+
// type makes it optional. Throwing would be overreach (lifecycle
|
|
342
|
+
// blocking), silent-skip is defensive-soft.
|
|
343
|
+
if (!rawDb)
|
|
344
|
+
return;
|
|
345
|
+
// Idempotency: stream-existence-check vor create. Pattern aus
|
|
346
|
+
// seedTenant.ts. Bei re-replay (rebuild) nicht versionsbumpen.
|
|
347
|
+
const streamVersion = await getUnscopedAggregateStreamMaxVersion(rawDb, aggregateId);
|
|
348
|
+
// skip: idempotent — tier-assignment stream already seeded (rebuild/replay).
|
|
349
|
+
if (streamVersion > 0)
|
|
350
|
+
return;
|
|
351
|
+
// SystemUser für den NEUEN tenant — der Hook wird vom signup-
|
|
352
|
+
// user (anderer tenant, oder SystemAdmin) ausgelöst, aber das
|
|
353
|
+
// tier-assignment muss im stream des neu-erzeugten tenants
|
|
354
|
+
// landen (= aggregate-id deterministic auf newTenantId). Memory
|
|
355
|
+
// `feedback_event_store_tenant_consistency`: by.tenantId muss =
|
|
356
|
+
// ziel-tenant.
|
|
357
|
+
const systemUser = {
|
|
358
|
+
id: "00000000-0000-4000-8000-000000000001",
|
|
359
|
+
tenantId: newTenantId,
|
|
360
|
+
roles: ["SystemAdmin"],
|
|
361
|
+
};
|
|
362
|
+
const tdb = createTenantDb(rawDb, newTenantId, "system");
|
|
363
|
+
await tierAssignmentExecutor.create({ id: aggregateId, tier: defaultTier, source: TierAssignmentSources.default }, systemUser, tdb);
|
|
364
|
+
},
|
|
365
|
+
phase: HookPhases.inTransaction,
|
|
366
|
+
escapeHatch: { reason: autoDefaultTierHookReason },
|
|
367
|
+
});
|
|
354
368
|
}
|
|
355
369
|
// Extension-point declaration + self-registration. Pattern analog
|
|
356
370
|
// mail-foundation/file-foundation: das feature deklariert den
|
package/dist/user/feature.js
CHANGED
|
@@ -21,7 +21,7 @@ export function createUserFeature() {
|
|
|
21
21
|
recommended: true,
|
|
22
22
|
});
|
|
23
23
|
r.systemScope();
|
|
24
|
-
r.entity("user", userEntity);
|
|
24
|
+
r.entity({ name: "user", ...userEntity });
|
|
25
25
|
// Self-extension: `user` declares AND fulfils principalStatus (precedent:
|
|
26
26
|
// tier-engine/feature.ts) — wires the blocked-principal check into every stack that mounts `user`.
|
|
27
27
|
r.extendsRegistrar(EXT_PRINCIPAL_STATUS, {});
|
|
@@ -56,7 +56,7 @@ export function createUserDataRightsFeature(opts = {}) {
|
|
|
56
56
|
category: "compliance",
|
|
57
57
|
recommended: false,
|
|
58
58
|
});
|
|
59
|
-
r.requires("user", "data-retention", "compliance-profiles", "sessions");
|
|
59
|
+
r.requires({ features: ["user", "data-retention", "compliance-profiles", "sessions"] });
|
|
60
60
|
r.usesApi("compliance.forTenant");
|
|
61
61
|
r.usesApi("retention.policyFor");
|
|
62
62
|
// S2.U6 — restrict-account ruft sessions.revokeAllForUser cross-feature.
|
|
@@ -92,13 +92,13 @@ export function createUserDataRightsFeature(opts = {}) {
|
|
|
92
92
|
env: "TENANT_MODEL",
|
|
93
93
|
}));
|
|
94
94
|
// S2.U3 Atom 1b — ExportJob-Lifecycle-Entity.
|
|
95
|
-
r.entity("export-job", exportJobEntity);
|
|
95
|
+
r.entity({ name: "export-job", ...exportJobEntity });
|
|
96
96
|
// S2.U3 Atom 4a — Download-Token-Entity. Worker generiert Token beim
|
|
97
97
|
// Flip auf done (siehe run-export-jobs.ts). Hash in DB, plain im
|
|
98
98
|
// RunExportJobsResult fuer Atom 5 (Notification per Email).
|
|
99
|
-
r.entity("export-download-token", exportDownloadTokenEntity);
|
|
99
|
+
r.entity({ name: "export-download-token", ...exportDownloadTokenEntity });
|
|
100
100
|
// S2.U7 — Audit-Trail invalid Download-Attempts (DPO Brute-Force-Detection).
|
|
101
|
-
r.entity("download-attempt", downloadAttemptEntity);
|
|
101
|
+
r.entity({ name: "download-attempt", ...downloadAttemptEntity });
|
|
102
102
|
// S2.U6 — DSGVO Art. 18 Account-Freeze (Verarbeitungs-Pause).
|
|
103
103
|
// Endpoints fuer Restrict + Lift. Login-Block fuer Restricted Users
|
|
104
104
|
// lebt in auth-email-password/login.write.ts.
|
|
@@ -14,7 +14,7 @@ import { userSessionDeleteHook, userSessionExportHook, } from "./hooks/user-sess
|
|
|
14
14
|
// `user` (S2.H1) und `fileRef` (S2.H2).
|
|
15
15
|
//
|
|
16
16
|
// Architektur-Entscheidung (S2.H1+H2): user-data-rights selbst kann
|
|
17
|
-
// nicht r.requires("user", "files") + r.useExtension(EXT_USER_DATA, ...)
|
|
17
|
+
// nicht r.requires({ features: ["user", "files"] }) + r.useExtension(EXT_USER_DATA, ...)
|
|
18
18
|
// machen weil es selbst Provider von EXT_USER_DATA ist (Boot-Validator
|
|
19
19
|
// lehnt self-extension ab). Lösung: drittes optional-mountbares Feature
|
|
20
20
|
// das requires beide Sources + die useExtension-Calls macht.
|
|
@@ -40,7 +40,7 @@ export function createUserDataRightsDefaultsFeature() {
|
|
|
40
40
|
category: "compliance",
|
|
41
41
|
recommended: false,
|
|
42
42
|
});
|
|
43
|
-
r.requires("user", "files", "user-data-rights");
|
|
43
|
+
r.requires({ features: ["user", "files", "user-data-rights"] });
|
|
44
44
|
// Optional sources: hooks are registered unconditionally but each one
|
|
45
45
|
// no-ops at runtime when its source feature isn't mounted (see
|
|
46
46
|
// hooks/feature-mounted.ts) — the export runner has no per-hook
|
|
@@ -22,10 +22,10 @@ export function createUserProfileFeature(options) {
|
|
|
22
22
|
category: "identity",
|
|
23
23
|
recommended: true,
|
|
24
24
|
});
|
|
25
|
-
r.requires("user");
|
|
26
|
-
r.requires("auth-email-password");
|
|
27
|
-
r.requires("user-data-rights");
|
|
28
|
-
r.requires("user-data-rights-defaults");
|
|
25
|
+
r.requires({ features: ["user"] });
|
|
26
|
+
r.requires({ features: ["auth-email-password"] });
|
|
27
|
+
r.requires({ features: ["user-data-rights"] });
|
|
28
|
+
r.requires({ features: ["user-data-rights-defaults"] });
|
|
29
29
|
const handlers = allowEmailChange ? { changeEmail: r.writeHandler(changeEmailWrite) } : {};
|
|
30
30
|
// Boot-validator requires a "screen:<id>.title" key per r.screen(), plus
|
|
31
31
|
// one entry per i18nKey()-marked dot-form label below — kept inline (not
|
package/dist/waitlist/feature.js
CHANGED
|
@@ -15,7 +15,7 @@ export function createWaitlistFeature(opts = {}) {
|
|
|
15
15
|
r.describe("Public waitlist: an anonymous, rate-limited `submit` handler collects name, email and optional company, portfolio and message (a honeypot field and per-email dedupe keep bots and repeat submits out, and the response body is identical whether or not an address was already listed), and mails the submitter a confirmation. SystemAdmins review entries in a list screen and invite or reject them; an invite creates the entrant's own tenant (or joins one shared tenant) and mails an accept link with the configured membership role, never a global role. Entries are platform-wide, their personal data is crypto-shredding-ready, and the EXT_USER_DATA hooks export and erase entries matching a user's email.");
|
|
16
16
|
r.uiHints({ displayLabel: "Waitlist", category: "data", recommended: false });
|
|
17
17
|
r.systemScope();
|
|
18
|
-
r.requires("tenant", "auth-email-password", "user-data-rights");
|
|
18
|
+
r.requires({ features: ["tenant", "auth-email-password", "user-data-rights"] });
|
|
19
19
|
r.translations({ keys: WAITLIST_I18N });
|
|
20
20
|
r.notification("confirmation", {
|
|
21
21
|
variables: WAITLIST_CONFIRMATION_VARIABLES,
|
|
@@ -26,7 +26,7 @@ export function createWaitlistFeature(opts = {}) {
|
|
|
26
26
|
record: WAITLIST_ADMIN_NOTICE_RECORD,
|
|
27
27
|
localizedTemplate: waitlistAdminNoticeTemplate,
|
|
28
28
|
});
|
|
29
|
-
r.entity("waitlistEntry", waitlistEntryEntity);
|
|
29
|
+
r.entity({ name: "waitlistEntry", ...waitlistEntryEntity });
|
|
30
30
|
r.writeHandler(createSubmitHandler(opts));
|
|
31
31
|
r.writeHandler(createInviteHandler(opts.invite));
|
|
32
32
|
r.writeHandler(rejectHandler);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.366.0",
|
|
4
4
|
"description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -524,12 +524,12 @@
|
|
|
524
524
|
}
|
|
525
525
|
},
|
|
526
526
|
"dependencies": {
|
|
527
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
528
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
529
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
530
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
531
|
-
"@cosmicdrift/kumiko-renderer-web": "0.
|
|
532
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
527
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.366.0",
|
|
528
|
+
"@cosmicdrift/kumiko-framework": "0.366.0",
|
|
529
|
+
"@cosmicdrift/kumiko-headless": "0.366.0",
|
|
530
|
+
"@cosmicdrift/kumiko-renderer": "0.366.0",
|
|
531
|
+
"@cosmicdrift/kumiko-renderer-web": "0.366.0",
|
|
532
|
+
"@cosmicdrift/kumiko-types": "0.366.0",
|
|
533
533
|
"@mollie/api-client": "^4.5.0",
|
|
534
534
|
"@node-rs/argon2": "^2.0.2",
|
|
535
535
|
"@tiptap/core": "3.31.3",
|
|
@@ -1078,9 +1078,9 @@
|
|
|
1078
1078
|
],
|
|
1079
1079
|
"devDependencies": {
|
|
1080
1080
|
"@testing-library/user-event": "^14.6.1",
|
|
1081
|
-
"@cosmicdrift/kumiko-locale-de": "0.
|
|
1082
|
-
"@cosmicdrift/kumiko-locale-es": "0.
|
|
1083
|
-
"@cosmicdrift/kumiko-renderer-mail-html": "0.
|
|
1081
|
+
"@cosmicdrift/kumiko-locale-de": "0.366.0",
|
|
1082
|
+
"@cosmicdrift/kumiko-locale-es": "0.366.0",
|
|
1083
|
+
"@cosmicdrift/kumiko-renderer-mail-html": "0.366.0",
|
|
1084
1084
|
"jsqr": "^1.4.0",
|
|
1085
1085
|
"unpdf": "^1.8.1"
|
|
1086
1086
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.366.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Agent tool failures are classified instead of passing raw messages through",
|
|
6
|
+
"detail": "dispatchToolCall now adds a code to failed tool results. Client errors keep their message, rate limits also set retryable and retryAfterSeconds. Server errors and unknown throws are logged with their cause and returned to the model as \"Tool failed unexpectedly\", so internal details such as database messages no longer reach the model. ToolCallRequest accepts an optional log."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.353.0",
|
|
4
10
|
"type": "fix",
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.366.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Removed unused AuthHandlers.inviteCancel constant",
|
|
6
|
+
"detail": "AuthHandlers.inviteCancel pointed at auth-email-password:write:invite-cancel, a handler that never existed. The constant is removed.",
|
|
7
|
+
"migration": "If you referenced AuthHandlers.inviteCancel, use tenant:write:cancel-invitation."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"version": "0.366.0",
|
|
11
|
+
"type": "fix",
|
|
12
|
+
"title": "invite-create is no longer exposed to agents",
|
|
13
|
+
"detail": "The admin invite-create handler is now opted out of the agent tool catalog with agent: { expose: false }, like the other invite handlers, because it mails an accept link to an arbitrary address."
|
|
14
|
+
},
|
|
2
15
|
{
|
|
3
16
|
"version": "0.365.0",
|
|
4
17
|
"type": "fix",
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.366.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "cap-counter calendar settle is idempotent",
|
|
6
|
+
"detail": "Settling a calendar cap reservation now keeps the row as a tombstone (new column store_cap_reservations.settled_at, retained for 24 hours) instead of deleting it. A repeated settle with the same reservation id is a no-op, and confirm, give-back and expiry sweep ignore settled rows. The sweep deletes expired tombstones.",
|
|
7
|
+
"migration": "Apps with cap-counter generate a migration for the new column store_cap_reservations.settled_at (kumiko migrate generate)."
|
|
8
|
+
},
|
|
2
9
|
{
|
|
3
10
|
"version": "0.365.0",
|
|
4
11
|
"type": "breaking",
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.366.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "forget-subject is covered for users stored before the KMS and users without an event stream",
|
|
6
|
+
"detail": "Tests now cover forget-subject for users stored as plaintext before the KMS was configured and for users without an event stream. Both succeed since the KMS tombstone fix, close the login door and write the audit event."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.365.1",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "eraseKey leaves a tombstone for subjects that never had a key",
|
|
12
|
+
"detail": "eraseKey now records an erased entry even when the subject has no key (pre-KMS plaintext). A later createKey or write for that subject fails with subject_erased instead of minting a fresh key and re-encrypting the plaintext. Erase flows must write with writePurpose erasure after eraseKey. kumiko_subject_keys now gets one tombstone row per forgotten record subject and per step dispatch. The tenant destruction stage tenant-row now fails loudly when marking the tenant destroyed does not succeed.",
|
|
13
|
+
"migration": "Run backfill-pii before erasing Pre-KMS data, otherwise untouched plaintext stays readable after eraseKey."
|
|
14
|
+
},
|
|
2
15
|
{
|
|
3
16
|
"version": "0.364.0",
|
|
4
17
|
"type": "fix",
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.366.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Renaming a notification type keeps user preferences and address opt-outs",
|
|
6
|
+
"detail": "r.notification accepts renamedFrom, a list of former qualified names. Preferences and address opt-outs stored under a former name keep applying to the renamed notification, and a stored choice under the current name wins over one under a former name. New writes via setPreference and the unsubscribe and resubscribe handlers are stored under the current name, resubscribeAddress also lifts opt-outs under former names. Boot fails if an alias is a current notification name, is the wildcard, or is claimed by two notifications."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.365.0",
|
|
4
10
|
"type": "fix",
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.366.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Inbound mail fetch can skip already-seen message ids",
|
|
6
|
+
"detail": "InboundMailProviderPlugin.fetch receives an optional filterUnknownMessageIds(providerMessageIds) hook. The watch supervisor implements it with a tenant- and account-scoped lookup of already-seen provider message ids and returns the ids not seen yet, so a plugin can avoid downloading messages it has already processed."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.366.0",
|
|
10
|
+
"type": "breaking",
|
|
11
|
+
"title": "InboundMailContext exposes metricsFor to provider plugins",
|
|
12
|
+
"detail": "InboundMailContext gains an optional metricsFor(featureName) returning a MetricsHandle. runProdApp, the worker app and the dev server wire it from the observability meter, so provider plugins can emit their own metrics through the same pipeline.",
|
|
13
|
+
"migration": "Code that builds SystemWireDeps itself adds metricsFor (createMetricsForFactory(meter))."
|
|
14
|
+
},
|
|
2
15
|
{
|
|
3
16
|
"version": "0.364.0",
|
|
4
17
|
"type": "fix",
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.365.1",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "step-dispatcher delivers each dispatch as a retried job, so a slow receiver no longer delays other tenants",
|
|
6
|
+
"detail": "The step-dispatcher projection now only enqueues one `step-dispatcher:job:deliver` job per dispatch request, and the job performs the webhook or mail delivery. Redis holds only the dispatch stream id and the tenant, never the request payload. Transient failures (network error, timeout, 5xx, 408, 429, any mail adapter failure) are retried 3 times with exponential backoff; the outcome event and the payload key erase follow after the final attempt. Permanent failures (invalid url, blocked host, other 4xx, unavailable auth secret) are recorded at once. At most 2 deliveries per tenant run at the same time, so one tenant's slow receivers cannot hold up the others. This corrects the 0.346.0 note that a hanging receiver no longer stalls the dispatcher for every tenant: the shared consumer still delivered one request at a time.",
|
|
7
|
+
"migration": "step-dispatcher now needs a job runner (Redis) and a worker consuming the default worker lane. Without a job runner the projection throws instead of delivering. Test stacks must pass `jobs` to setupTestStack and call `drainJobs()` after the event dispatcher ran. `r.job` accepts `maxPerTenant: { limit, onLimit: \"defer\", deferMs? }`; a plain number still drops excess enqueues. A `webhook.send` request that gets a retryable status (5xx, 408, 429) is now sent up to 4 times under the same Idempotency-Key. Worker pods must know the deliver job before the projection enqueues it, so deploy worker and API together or the worker first. A dev server only consumes jobs when the app mounts `createJobsFeature()`."
|
|
8
|
+
},
|
|
2
9
|
{
|
|
3
10
|
"version": "0.347.0",
|
|
4
11
|
"type": "fix",
|
|
@@ -21,7 +28,7 @@
|
|
|
21
28
|
"version": "0.346.0",
|
|
22
29
|
"type": "fix",
|
|
23
30
|
"title": "Webhook requests time out after 10 seconds instead of blocking the dispatcher",
|
|
24
|
-
"detail": "Webhook requests time out after 10 seconds\nA hanging receiver now ends as `step.dispatch-failed`
|
|
31
|
+
"detail": "Webhook requests time out after 10 seconds\nA hanging receiver now ends as `step.dispatch-failed` after the timeout instead of waiting indefinitely. Until the step-dispatcher delivered through jobs, the shared consumer still processed requests one at a time, so a slow receiver of one tenant delayed the others."
|
|
25
32
|
},
|
|
26
33
|
{
|
|
27
34
|
"version": "0.346.0",
|