@cosmicdrift/kumiko-samples 0.390.1 → 0.391.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.
Files changed (70) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +1 -1
  3. package/packages/bundled-features/src/audit/changes.json +6 -0
  4. package/packages/bundled-features/src/audit/event-classification.ts +5 -0
  5. package/packages/bundled-features/src/audit/handlers/audit-events.ts +15 -1
  6. package/packages/bundled-features/src/audit/handlers/details.query.ts +11 -4
  7. package/packages/bundled-features/src/audit/handlers/list.query.ts +1 -0
  8. package/packages/bundled-features/src/audit/handlers/resolve-audit-tenant.ts +11 -2
  9. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  10. package/packages/bundled-features/src/auth-mfa/i18n.ts +1 -0
  11. package/packages/bundled-features/src/auth-mfa/screens.ts +3 -0
  12. package/packages/bundled-features/src/file-foundation/changes.json +6 -0
  13. package/packages/bundled-features/src/file-foundation/feature.ts +6 -0
  14. package/packages/bundled-features/src/file-foundation/i18n.ts +13 -0
  15. package/packages/bundled-features/src/file-foundation/index.ts +4 -0
  16. package/packages/bundled-features/src/file-foundation/probe.ts +68 -0
  17. package/packages/bundled-features/src/{user-data-rights/lib → file-foundation}/storage-provider-resolver.ts +2 -2
  18. package/packages/bundled-features/src/inbound-mail-foundation/changes.json +6 -0
  19. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -0
  20. package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +2 -0
  21. package/packages/bundled-features/src/inbound-mail-foundation/probe-keys.ts +17 -0
  22. package/packages/bundled-features/src/inbound-mail-foundation/probe.ts +109 -0
  23. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +3 -0
  24. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +3 -11
  25. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +16 -0
  26. package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
  27. package/packages/bundled-features/src/mail-foundation/feature.ts +2 -0
  28. package/packages/bundled-features/src/mail-foundation/i18n.ts +27 -0
  29. package/packages/bundled-features/src/mail-foundation/index.ts +4 -0
  30. package/packages/bundled-features/src/{user-data-rights/lib → mail-foundation}/mail-transport-resolver.ts +2 -2
  31. package/packages/bundled-features/src/mail-foundation/probe.ts +81 -0
  32. package/packages/bundled-features/src/readiness/built-in-probes.ts +58 -0
  33. package/packages/bundled-features/src/readiness/changes.json +7 -0
  34. package/packages/bundled-features/src/readiness/collect-probes.ts +47 -0
  35. package/packages/bundled-features/src/readiness/constants.ts +25 -0
  36. package/packages/bundled-features/src/readiness/execute-probes.ts +116 -0
  37. package/packages/bundled-features/src/readiness/feature.ts +91 -3
  38. package/packages/bundled-features/src/readiness/handlers/latest-results.query.ts +15 -0
  39. package/packages/bundled-features/src/readiness/handlers/latest-summary.query.ts +53 -0
  40. package/packages/bundled-features/src/readiness/handlers/run-detail.query.ts +31 -0
  41. package/packages/bundled-features/src/readiness/handlers/run-list.query.ts +48 -0
  42. package/packages/bundled-features/src/readiness/handlers/run-probes.write.ts +98 -0
  43. package/packages/bundled-features/src/readiness/handlers/run-results.query.ts +18 -0
  44. package/packages/bundled-features/src/readiness/handlers/run-tone.ts +6 -0
  45. package/packages/bundled-features/src/readiness/i18n.ts +55 -0
  46. package/packages/bundled-features/src/readiness/index.ts +1 -1
  47. package/packages/bundled-features/src/readiness/probe-boot-check.ts +53 -0
  48. package/packages/bundled-features/src/readiness/probe-context.ts +57 -0
  49. package/packages/bundled-features/src/readiness/run-probes-job.ts +104 -0
  50. package/packages/bundled-features/src/readiness/run-view.ts +48 -0
  51. package/packages/bundled-features/src/readiness/schema/probe-run.ts +89 -0
  52. package/packages/bundled-features/src/readiness/screens.ts +191 -0
  53. package/packages/bundled-features/src/readiness/visible-results.ts +106 -0
  54. package/packages/bundled-features/src/tenant/changes.json +12 -0
  55. package/packages/bundled-features/src/tenant/membership-stream-history.ts +224 -0
  56. package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
  57. package/packages/bundled-features/src/tenant/seeding.ts +8 -13
  58. package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +45 -1
  59. package/packages/bundled-features/src/user-data-rights/feature.ts +2 -2
  60. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +1 -1
  61. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +1 -1
  62. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +1 -1
  63. package/packages/bundled-features/src/user-profile/changes.json +6 -0
  64. package/packages/bundled-features/src/user-profile/feature.ts +20 -0
  65. package/packages/bundled-features/src/user-profile/web/constants.ts +5 -0
  66. package/packages/bundled-features/src/user-profile/web/i18n.ts +2 -0
  67. package/samples/apps/use-all-bundled/feature-manifest.json +23 -4
  68. package/samples/apps/use-all-bundled/kumiko/migrations/0054_readiness-probe-runs.rebuild.json +4 -0
  69. package/samples/apps/use-all-bundled/src/app/admin-nav-feature.ts +27 -0
  70. package/samples/apps/use-all-bundled/src/run-config.ts +3 -1
@@ -17,6 +17,8 @@ import {
17
17
  } from "@cosmicdrift/kumiko-framework/observability";
18
18
  import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
19
19
  import { createConfigAccessor } from "../config/index.ts";
20
+ import { makeTenantStorageProviderResolver } from "../file-foundation/index.ts";
21
+ import { makeTenantMailTransportResolver } from "../mail-foundation/index.ts";
20
22
  import { validateGdprHookCompleteness, validateGdprPiiHookCoverage } from "./boot-checks.ts";
21
23
  import { deletionTokenSecretEnvSchema } from "./env.ts";
22
24
  import { cancelDeletionWrite } from "./handlers/cancel-deletion.write.ts";
@@ -50,9 +52,7 @@ import {
50
52
  makeDefaultExportFailedEmail,
51
53
  makeDefaultExportReadyEmail,
52
54
  } from "./lib/default-mailers.ts";
53
- import { makeTenantMailTransportResolver } from "./lib/mail-transport-resolver.ts";
54
55
  import { resolveAppTenantModel } from "./lib/resolve-tenant-model.ts";
55
- import { makeTenantStorageProviderResolver } from "./lib/storage-provider-resolver.ts";
56
56
  import { registerGdprMails } from "./mail-notifications.ts";
57
57
  import {
58
58
  EXPORT_CLEANUP_BACKLOG_AGE_METRIC,
@@ -33,8 +33,8 @@ import {
33
33
  import { NotFoundError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
34
34
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
35
35
  import * as z from "zod";
36
+ import { makeTenantStorageProviderResolver } from "../../file-foundation/index.ts";
36
37
  import { recordDownloadUse, recordInvalidAttempt } from "../audit-download.ts";
37
- import { makeTenantStorageProviderResolver } from "../lib/storage-provider-resolver.ts";
38
38
  import { exportDownloadTokensTable } from "../schema/download-token.ts";
39
39
  import { EXPORT_JOB_STATUS, exportJobsTable } from "../schema/export-job.ts";
40
40
 
@@ -34,8 +34,8 @@ import {
34
34
  import { NotFoundError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
35
35
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
36
36
  import * as z from "zod";
37
+ import { makeTenantStorageProviderResolver } from "../../file-foundation/index.ts";
37
38
  import { recordDownloadUse, recordInvalidAttempt } from "../audit-download.ts";
38
- import { makeTenantStorageProviderResolver } from "../lib/storage-provider-resolver.ts";
39
39
  import { exportDownloadTokensTable } from "../schema/download-token.ts";
40
40
  import { EXPORT_JOB_STATUS, exportJobsTable } from "../schema/export-job.ts";
41
41
  import { hashDownloadToken } from "../token-helpers.ts";
@@ -15,8 +15,8 @@ import { access, defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine
15
15
  import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
16
16
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
17
17
  import * as z from "zod";
18
+ import { makeTenantStorageProviderResolver } from "../../file-foundation/index.ts";
18
19
  import { resolveAppTenantModel } from "../lib/resolve-tenant-model.ts";
19
- import { makeTenantStorageProviderResolver } from "../lib/storage-provider-resolver.ts";
20
20
  import {
21
21
  FORGET_CLEANUP_HANDLER_NAME,
22
22
  runForgetCleanup,
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.391.0",
4
+ "type": "improvement",
5
+ "title": "The profile can link to account security",
6
+ "detail": "createUserProfileFeature({ linkAccountSecurity: true }) adds a header action that opens the account-security screen, which offers MFA enable or disable by the user's status. It requires the account-security feature; the default stays off. New key profile.mfa.open in all locale packages."
7
+ },
2
8
  {
3
9
  "version": "0.360.0",
4
10
  "type": "improvement",
@@ -9,6 +9,7 @@ import {
9
9
  CHANGE_PASSWORD_SECTION_EXTENSION_NAME,
10
10
  PROFILE_SCREEN_ID,
11
11
  UserDataRightsHandlers,
12
+ UserProfileForeignScreens,
12
13
  UserProfileQueries,
13
14
  } from "./web/constants.ts";
14
15
 
@@ -16,10 +17,15 @@ export type UserProfileFeatureOptions = {
16
17
  /** Default true. false drops the change-email handler and the email
17
18
  * section — for apps whose login email is managed elsewhere (SSO, admin-set). */
18
19
  readonly allowEmailChange?: boolean;
20
+ /** Default false. true adds a header action opening the account-security screen,
21
+ * which offers MFA enable or disable by the user's status; needs the
22
+ * account-security feature mounted. */
23
+ readonly linkAccountSecurity?: boolean;
19
24
  };
20
25
 
21
26
  export function createUserProfileFeature(options?: UserProfileFeatureOptions): FeatureDefinition {
22
27
  const allowEmailChange = options?.allowEmailChange ?? true;
28
+ const linkAccountSecurity = options?.linkAccountSecurity ?? false;
23
29
  return defineFeature("user-profile", (r) => {
24
30
  r.describe(
25
31
  "Self-service account page (fw#2312: declarative `projectionDetail` bound to " +
@@ -45,6 +51,7 @@ export function createUserProfileFeature(options?: UserProfileFeatureOptions): F
45
51
  r.requires({ features: ["auth-email-password"] });
46
52
  r.requires({ features: ["user-data-rights"] });
47
53
  r.requires({ features: ["user-data-rights-defaults"] });
54
+ if (linkAccountSecurity) r.requires({ features: ["account-security"] });
48
55
 
49
56
  const handlers = allowEmailChange ? { changeEmail: r.writeHandler(changeEmailWrite) } : {};
50
57
 
@@ -72,6 +79,7 @@ export function createUserProfileFeature(options?: UserProfileFeatureOptions): F
72
79
  en: "After the grace period your data will be permanently deleted. Until then you can cancel.",
73
80
  },
74
81
  "profile.danger.cancelDeletion": { en: "Cancel deletion" },
82
+ "profile.mfa.open": { en: "Manage two-factor authentication" },
75
83
  },
76
84
  });
77
85
 
@@ -139,6 +147,18 @@ export function createUserProfileFeature(options?: UserProfileFeatureOptions): F
139
147
  ],
140
148
  },
141
149
  actions: [
150
+ ...(linkAccountSecurity
151
+ ? [
152
+ {
153
+ kind: "navigate" as const,
154
+ id: "open-account-security",
155
+ label: i18nKey("profile.mfa.open"),
156
+ screen: UserProfileForeignScreens.accountSecurity,
157
+ icon: "shield-check" as const,
158
+ style: "secondary" as const,
159
+ },
160
+ ]
161
+ : []),
142
162
  {
143
163
  id: "request-deletion",
144
164
  label: i18nKey("profile.danger.delete"),
@@ -24,6 +24,11 @@ export const UserProfileQueries = {
24
24
  me: "user:query:user:me",
25
25
  } as const;
26
26
 
27
+ // Short id: navigate targets resolve short ids app-wide, a cross-feature QN is not a navigate target.
28
+ export const UserProfileForeignScreens = {
29
+ accountSecurity: "account-security",
30
+ } as const;
31
+
27
32
  export const UserDataRightsHandlers = {
28
33
  requestDeletion: "user-data-rights:write:request-deletion",
29
34
  cancelDeletion: "user-data-rights:write:cancel-deletion",
@@ -37,6 +37,8 @@ export const defaultTranslations: TranslationsByLocale = {
37
37
  "profile.danger.gracePeriodEnd": "Deletion date",
38
38
  "profile.danger.cancelDeletion": "Cancel deletion",
39
39
 
40
+ "profile.mfa.open": "Manage two-factor authentication",
41
+
40
42
  "profile.errors.generic": "Something went wrong.",
41
43
  "profile.errors.emailUnchanged": "That is already your email address.",
42
44
  "user.errors.emailAlreadyExists": "This email address is already in use.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "source": "samples/apps/use-all-bundled APP_FEATURES (composeFeatures includeBundled + signup)",
3
- "featureCount": 88,
3
+ "featureCount": 89,
4
4
  "features": [
5
5
  {
6
6
  "name": "account-security",
@@ -19,6 +19,20 @@
19
19
  "secrets": [],
20
20
  "writeHandlers": []
21
21
  },
22
+ {
23
+ "name": "admin-nav",
24
+ "description": "Administration group in the sidebar of this sample app.",
25
+ "toggleableDefault": null,
26
+ "requires": [],
27
+ "optionalRequires": [],
28
+ "configReads": [],
29
+ "exposesApis": [],
30
+ "usesApis": [],
31
+ "extensionsUsed": [],
32
+ "configKeys": [],
33
+ "secrets": [],
34
+ "writeHandlers": []
35
+ },
22
36
  {
23
37
  "name": "admin-shell",
24
38
  "description": "Registers tenant-admin and platform-admin workspaces with provider nav into owner-feature screens (`tenant:screen:members`, `audit:screen:audit-log`, `audit:screen:audit-log-all-tenants`, `tenant:screen:tenant-list`, `jobs:screen:job-runs`, optional `tier-engine:screen:tier-admin`, optional `cap-overview:screen:my-caps`/`cap-overview:screen:tenant-cap-list`, optional `document-designer` template navs) and the two overview dashboards, built from the metrics list (`metrics` option, default DEFAULT_METRICS). Mount after user, tenant, audit, jobs, metrics and metrics-system; pass `workspaceIds` to match app URL conventions (e.g. Studio `d`/`s`, PublicStatus `admin`/`sysadmin`). Client: `adminShellClient()`, `tenantClient()`, `auditClient()`, `jobsClient()`, optional `tierEngineClient()`.",
@@ -2146,20 +2160,25 @@
2146
2160
  },
2147
2161
  {
2148
2162
  "name": "readiness",
2149
- "description": "One-call tenant-onboarding probe: `readiness:query:status` rolls up every config key and secret declared `required: true` across all mounted features and reports which still lack a usable value for the calling tenant, plus a single `ready` boolean. Provider-features under an `r.extensionSelector`-declared extension point count only while their provider is the selected one — a tenant on the inmemory mail transport is not blocked by unset SMTP keys. Mount it (together with `config` and `secrets`) when an admin UI needs a settings checklist before the first mail-send or file-write; the per-concern lists stay available via `config:query:readiness` and `secrets:query:list`.",
2163
+ "description": "One-call tenant-onboarding probe: `readiness:query:status` rolls up every config key and secret declared `required: true` across all mounted features and reports which still lack a usable value for the calling tenant, plus a single `ready` boolean. Provider-features under an `r.extensionSelector`-declared extension point count only while their provider is the selected one — a tenant on the inmemory mail transport is not blocked by unset SMTP keys. Mount it (together with `config` and `secrets`) when an admin UI needs a settings checklist before the first mail-send or file-write; the per-concern lists stay available via `config:query:readiness` and `secrets:query:list`. `readiness:write:run-probes` runs the live probes features register with `r.probe` (mail, files, mailboxes, PDF service and more) as a job; the system-check screen shows the latest run and the history once `nav` is passed.",
2150
2164
  "toggleableDefault": null,
2165
+ "adoptsBundledLists": true,
2151
2166
  "requires": [
2152
2167
  "config",
2153
2168
  "secrets"
2154
2169
  ],
2155
- "optionalRequires": [],
2170
+ "optionalRequires": [
2171
+ "user"
2172
+ ],
2156
2173
  "configReads": [],
2157
2174
  "exposesApis": [],
2158
2175
  "usesApis": [],
2159
2176
  "extensionsUsed": [],
2160
2177
  "configKeys": [],
2161
2178
  "secrets": [],
2162
- "writeHandlers": [],
2179
+ "writeHandlers": [
2180
+ "readiness:write:run-probes"
2181
+ ],
2163
2182
  "uiHints": {
2164
2183
  "displayLabel": "Readiness · Onboarding Probe",
2165
2184
  "category": "operations",
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": 1,
3
+ "tables": ["read_readiness_probe_runs"]
4
+ }
@@ -0,0 +1,27 @@
1
+ import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
2
+
3
+ // Sidebar group for the admin screens. Bundled features have no shared admin group,
4
+ // so the app owns it and mounts e.g. readiness's system check below it.
5
+ export const ADMIN_NAV_QN = "admin-nav:nav:administration";
6
+ // Each nav joins only the workspaces it names, so the group and every child list them.
7
+ export const ADMIN_NAV_WORKSPACES = [
8
+ "admin-shell:workspace:tenant-admin",
9
+ "admin-shell:workspace:platform",
10
+ ] as const;
11
+
12
+ export const adminNavFeature = defineFeature("admin-nav", (r) => {
13
+ r.describe("Administration group in the sidebar of this sample app.");
14
+ r.nav({
15
+ id: "administration",
16
+ label: "admin-nav:nav.administration",
17
+ icon: "settings",
18
+ order: 80,
19
+ workspaces: ADMIN_NAV_WORKSPACES,
20
+ });
21
+ r.translations({
22
+ keys: {
23
+ "admin-nav:nav.administration": { de: "Verwaltung", en: "Administration" },
24
+ },
25
+ });
26
+ return {};
27
+ });
@@ -99,6 +99,7 @@ import { createDocumentDesignerFeature } from "@cosmicdrift/kumiko-document-desi
99
99
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
100
100
  import { localeDe } from "@cosmicdrift/kumiko-locale-de";
101
101
  import { createRendererPuppeteerClientFeature } from "@cosmicdrift/kumiko-renderer-puppeteer-client";
102
+ import { ADMIN_NAV_QN, ADMIN_NAV_WORKSPACES, adminNavFeature } from "./app/admin-nav-feature";
102
103
  import { DEV_TENANT_ID } from "./app/auth-constants";
103
104
  import { CAP_OVERVIEW_CAPS } from "./app/cap-overview-caps";
104
105
  import { capOverviewLabelsFeature } from "./app/cap-overview-labels-feature";
@@ -164,7 +165,8 @@ export const APP_FEATURES = [
164
165
  },
165
166
  }),
166
167
  patScopeLabelsFeature,
167
- createReadinessFeature(),
168
+ adminNavFeature,
169
+ createReadinessFeature({ nav: { parent: ADMIN_NAV_QN, workspaces: ADMIN_NAV_WORKSPACES } }),
168
170
 
169
171
  // delivery + channels
170
172
  createDeliveryFeature(),