@cosmicdrift/kumiko-bundled-features 0.365.1 → 0.367.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/email-channel.d.ts +5 -1
- package/dist/channel-email/email-channel.js +8 -2
- package/dist/channel-email/feature.js +2 -2
- 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/channel-context.js +1 -0
- 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.d.ts +2 -0
- package/dist/delivery/delivery-service.js +39 -6
- package/dist/delivery/feature.js +10 -6
- 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.d.ts +6 -0
- package/dist/delivery/handlers/unsubscribe-address.write.js +11 -6
- package/dist/delivery/handlers/unsubscribe-user.write.js +3 -1
- package/dist/delivery/index.d.ts +3 -0
- package/dist/delivery/index.js +2 -0
- package/dist/delivery/notification-type-aliases.d.ts +3 -0
- package/dist/delivery/notification-type-aliases.js +11 -0
- package/dist/delivery/testing.d.ts +2 -0
- package/dist/delivery/types.d.ts +2 -1
- package/dist/delivery/unsubscribe-link.d.ts +25 -0
- package/dist/delivery/unsubscribe-link.js +40 -0
- package/dist/delivery/unsubscribe-page-strings.d.ts +11 -0
- package/dist/delivery/unsubscribe-page-strings.js +15 -0
- package/dist/delivery/unsubscribe.d.ts +3 -0
- package/dist/delivery/unsubscribe.js +65 -29
- 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.d.ts +16 -1
- package/dist/mail-foundation/feature.js +30 -9
- package/dist/mail-foundation/index.d.ts +1 -1
- package/dist/mail-foundation/index.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/feature.js +1 -1
- 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/compile-document-body.js +47 -11
- package/dist/template-resolver/document-sanitizer.d.ts +2 -0
- package/dist/template-resolver/document-sanitizer.js +16 -1
- package/dist/template-resolver/document-schema.d.ts +2 -0
- package/dist/template-resolver/document-schema.js +31 -0
- package/dist/template-resolver/feature.js +2 -2
- package/dist/template-resolver/handlers/bundle-import.js +3 -2
- package/dist/template-resolver/handlers/copy-locale.write.js +3 -2
- package/dist/template-resolver/handlers/find-by-id.query.js +5 -1
- package/dist/template-resolver/handlers/list.query.js +3 -1
- package/dist/template-resolver/handlers/overview.query.js +4 -2
- package/dist/template-resolver/handlers/template-write.d.ts +2 -1
- package/dist/template-resolver/handlers/template-write.js +12 -1
- package/dist/template-resolver/index.d.ts +3 -2
- package/dist/template-resolver/index.js +3 -2
- package/dist/template-resolver/qualified-names.d.ts +1 -0
- package/dist/template-resolver/qualified-names.js +1 -0
- package/dist/template-resolver/seeding.d.ts +4 -0
- package/dist/template-resolver/seeding.js +40 -5
- package/dist/template-resolver/template-preview.js +2 -0
- package/dist/template-resolver/template-system-only.d.ts +8 -0
- package/dist/template-resolver/template-system-only.js +11 -0
- package/dist/template-resolver/template-validation.js +42 -28
- package/dist/template-resolver/web/i18n.js +1 -0
- 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-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/channel-email/changes.json +6 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/delivery/changes.json +18 -0
- package/src/inbound-mail-foundation/changes.json +13 -0
- package/src/template-resolver/changes.json +25 -0
- package/src/user-data-rights/changes.json +6 -0
|
@@ -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.367.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.367.0",
|
|
528
|
+
"@cosmicdrift/kumiko-framework": "0.367.0",
|
|
529
|
+
"@cosmicdrift/kumiko-headless": "0.367.0",
|
|
530
|
+
"@cosmicdrift/kumiko-renderer": "0.367.0",
|
|
531
|
+
"@cosmicdrift/kumiko-renderer-web": "0.367.0",
|
|
532
|
+
"@cosmicdrift/kumiko-types": "0.367.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.367.0",
|
|
1082
|
+
"@cosmicdrift/kumiko-locale-es": "0.367.0",
|
|
1083
|
+
"@cosmicdrift/kumiko-renderer-mail-html": "0.367.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,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.367.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Email channel can send through the tenant's own mail provider",
|
|
6
|
+
"detail": "EmailChannelOptions gets tenantTransport, a resolver called per send with the delivery channel context. mail-foundation exports tenantMailTransport for it: a tenant with a provider configured sends through its own transport, a broken provider fails the send, a tenant without a provider uses the app transport. The transport is built per send and never cached, and the tenant comes from the server-side delivery context only. ChannelContext now carries the tenant's config accessor as config. Without tenantTransport nothing changes."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.365.0",
|
|
4
10
|
"type": "fix",
|
|
@@ -1,4 +1,10 @@
|
|
|
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
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.365.1",
|
|
4
10
|
"type": "fix",
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.367.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Delivery signs unsubscribe links itself",
|
|
6
|
+
"detail": "r.notification(name, { unsubscribe: true }) makes delivery put a signed data.unsubscribeUrl into every email of that notification when the service has unsubscribeLinks. User recipients get a user token, route recipients an address token (only with a blind-index key, otherwise no link). The token is scoped to tenant, notification and channel; a link the caller passes in data.unsubscribeUrl wins. runProdApp option unsubscribe: { secret } mounts createUnsubscribeRoutes and wires the links; the base URL comes from auth.publicOrigin, auth.mail.baseUrl or APP_BASE_URL, and without one boot warns and no link is added."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.367.0",
|
|
10
|
+
"type": "improvement",
|
|
11
|
+
"title": "Unsubscribe links use the tenant's host and the mail's language, apps learn about address opt-outs",
|
|
12
|
+
"detail": "unsubscribeLinks and the runProdApp option unsubscribe take tenantOrigin, an app callback that returns the sending tenant's own origin (subdomain or custom domain) per send; null, a throw or a non-https value fall back to the app origin and never fail the send. The signed token now carries the mail's locale (notify option locale), so the confirmation, result and undo pages render in that language; tokens without it keep working and show English. A form post to the resubscribe route now answers with an HTML page, JSON callers are unchanged. After a committed address opt-out an app job declared with trigger on DeliveryHandlers.unsubscribeAddress receives addressHash, notificationType and channel (unsubscribeAddressPayloadSchema) with the tenant in ctx.triggeredBy.tenantId; hashUnsubscribeAddress(email) matches it to the app's own subscriber. UNSUBSCRIBE_PAGE_EN exports the English page texts, German and Spanish come with the locale packages."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.366.0",
|
|
16
|
+
"type": "improvement",
|
|
17
|
+
"title": "Renaming a notification type keeps user preferences and address opt-outs",
|
|
18
|
+
"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."
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"version": "0.365.0",
|
|
4
22
|
"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,29 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.367.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Notifications can keep their mail template system-only",
|
|
6
|
+
"detail": "r.notification(name, { systemOnly: true }) marks the stored mail template as a platform text. Tenant admins no longer see it in the template overview, list or detail, and creating a tenant version (upsert-tenant, copy-locale, import-bundle, also a SystemAdmin writing for a tenant) is refused with access_denied and templateResolver.errors.systemOnlyTemplate. SystemAdmins edit the system template as before, and the mail renderer always uses it, even if a tenant row exists from before."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.367.0",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "Rich text placeholders no longer nest paragraphs",
|
|
12
|
+
"detail": "A richText placeholder alone in a paragraph compiles into a div that keeps the paragraph attributes, and one inside other text renders inline with line breaks instead of its own paragraphs. Mails and PDFs no longer contain <p><p>. richText and stepIs are now reserved template variable names, like the other renderer helpers.",
|
|
13
|
+
"migration": "A notification that declares a template variable called richText, stepIs or percent fails at boot; rename the variable."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"version": "0.367.0",
|
|
17
|
+
"type": "improvement",
|
|
18
|
+
"title": "Template bundles with a logo can be seeded",
|
|
19
|
+
"detail": "seedSystemTemplateBundle(db, bundle, { dispatcher }) now seeds bundles that carry resources such as a logo by running the import-bundle-system write on the given seed dispatcher. With ifExists \"skip\" (default) nothing is written when every locale row already exists; if only some exist, the whole bundle is imported again. Without a dispatcher such a bundle still fails with a message that names the missing option."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"version": "0.367.0",
|
|
23
|
+
"type": "improvement",
|
|
24
|
+
"title": "Template conditions with data-if and a percent variable type",
|
|
25
|
+
"detail": "A paragraph, heading or table row with data-if=\"name\" renders only when the variable has a value (0 counts as a value); inside a repeat row the name refers to the row field, on the repeat row itself to the root variable. The sanitizer keeps the attribute, and template validation reports a condition on an undeclared variable. New variable type percent (templateVariable.percent()) takes percentage points and renders locale-aware, 12 as \"12 %\" in German and \"12%\" in English; the preview uses its example value. The document designer has no toolbar control for conditions yet; the attribute survives editing."
|
|
26
|
+
},
|
|
2
27
|
{
|
|
3
28
|
"version": "0.365.0",
|
|
4
29
|
"type": "breaking",
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.367.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Tests seed tenant memberships and events through the framework",
|
|
6
|
+
"detail": "Test-only change. Integration tests create read_tenant_memberships from tenantMembershipEntity and seed rows with seedRow instead of hand-written DDL and raw INSERTs. Fake events go through the event-store append, and backdated audit events are written with runSeedWritesAt instead of an UPDATE on created_at. No runtime behavior changes."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.365.0",
|
|
4
10
|
"type": "improvement",
|