@cosmicdrift/kumiko-samples 0.391.1 → 0.392.1
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/admin-shell/changes.json +6 -0
- package/packages/bundled-features/src/admin-shell/feature.ts +60 -31
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +2 -2
- package/packages/bundled-features/src/cap-overview/changes.json +18 -0
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -0
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +3 -2
- package/packages/bundled-features/src/cap-overview/i18n.ts +4 -0
- package/packages/bundled-features/src/cap-overview/types.ts +4 -1
- package/packages/bundled-features/src/cap-overview/web/cap-amount-format.ts +37 -0
- package/packages/bundled-features/src/cap-overview/web/cap-cards-panel.tsx +137 -54
- package/packages/bundled-features/src/cap-overview/web/cap-usage-bar.tsx +18 -4
- package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +6 -3
- package/packages/bundled-features/src/cap-overview/web/usage-math.ts +5 -1
- package/packages/bundled-features/src/channel-email/app-transport.ts +37 -0
- package/packages/bundled-features/src/channel-email/changes.json +6 -0
- package/packages/bundled-features/src/channel-email/feature.ts +6 -0
- package/packages/bundled-features/src/channel-email/index.ts +5 -0
- package/packages/bundled-features/src/channel-email/smtp-transport.ts +2 -22
- package/packages/bundled-features/src/foundation-shared/changes.json +6 -0
- package/packages/bundled-features/src/foundation-shared/index.ts +1 -0
- package/packages/bundled-features/src/foundation-shared/mail-display-name.ts +20 -0
- package/packages/bundled-features/src/inbound-mail-foundation/account-record.ts +48 -0
- package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +17 -0
- package/packages/bundled-features/src/inbound-mail-foundation/index.ts +18 -0
- package/packages/bundled-features/src/inbound-mail-foundation/outbound-mail.ts +66 -0
- package/packages/bundled-features/src/inbound-mail-foundation/probe.ts +8 -45
- package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +14 -0
- package/packages/bundled-features/src/inbound-mail-foundation/send-from-account.ts +118 -0
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +8 -0
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +13 -8
- package/packages/bundled-features/src/inbound-provider-imap/changes.json +18 -0
- package/packages/bundled-features/src/inbound-provider-imap/connect-mailbox.ts +158 -0
- package/packages/bundled-features/src/inbound-provider-imap/constants.ts +44 -0
- package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +47 -1
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +12 -35
- package/packages/bundled-features/src/inbound-provider-imap/i18n.ts +49 -0
- package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +1 -1
- package/packages/bundled-features/src/inbound-provider-imap/screens.ts +52 -0
- package/packages/bundled-features/src/inbound-provider-imap/send-mail.ts +73 -0
- package/packages/bundled-features/src/inbound-provider-imap/sent-folder.ts +49 -0
- package/packages/bundled-features/src/inbound-provider-imap/smtp-client.ts +135 -0
- package/packages/bundled-features/src/legal-pages/README.md +5 -10
- package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
- package/packages/bundled-features/src/mail-foundation/i18n.ts +9 -1
- package/packages/bundled-features/src/mail-foundation/probe.ts +43 -22
- package/packages/bundled-features/src/readiness/built-in-probes.ts +15 -2
- package/packages/bundled-features/src/readiness/changes.json +30 -0
- package/packages/bundled-features/src/readiness/constants.ts +2 -0
- package/packages/bundled-features/src/readiness/i18n.ts +7 -1
- package/packages/bundled-features/src/readiness/index.ts +6 -1
- package/packages/bundled-features/src/readiness/screens.ts +25 -2
- package/packages/bundled-features/src/readiness/visible-results.ts +2 -1
- package/packages/bundled-features/src/renderer-foundation/README.md +19 -21
- package/packages/bundled-features/src/template-resolver/README.md +144 -165
- package/packages/bundled-features/src/tier-engine/changes.json +6 -0
- package/packages/bundled-features/src/tier-engine/feature.ts +17 -6
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +5 -3
- package/packages/bundled-features/src/user-data-rights/token-helpers.ts +5 -4
- package/samples/apps/cap-billing-demo/bin/server.ts +7 -7
- package/samples/apps/cap-billing-demo/src/feature.ts +38 -38
- package/samples/apps/cap-billing-demo/src/run-config.ts +20 -20
- package/samples/apps/cap-billing-demo/src/tier-map.ts +14 -14
- package/samples/apps/config-demo/src/app/server.ts +4 -4
- package/samples/apps/config-demo/src/features/demo/feature.ts +4 -4
- package/samples/apps/marketing-demo/playwright.config.ts +3 -3
- package/samples/apps/marketing-demo/src/app/client.tsx +2 -2
- package/samples/apps/marketing-demo/src/app/seed-data.ts +9 -9
- package/samples/apps/marketing-demo/src/app/seed.ts +14 -14
- package/samples/apps/marketing-demo/src/app/server.ts +7 -7
- package/samples/apps/marketing-demo/src/app/shell.tsx +3 -3
- package/samples/apps/marketing-demo/src/features/assets/feature.ts +3 -3
- package/samples/apps/marketing-demo/src/features/assets/i18n.ts +7 -7
- package/samples/apps/marketing-demo/src/features/assets/web/index.ts +2 -2
- package/samples/apps/showcase/src/app/client.tsx +3 -3
- package/samples/apps/showcase/src/app/seed-items.ts +14 -14
- package/samples/apps/showcase/src/app/server.ts +7 -7
- package/samples/apps/showcase/src/features/demos/feature.ts +13 -13
- package/samples/apps/showcase/src/features/demos/i18n.ts +2 -2
- package/samples/apps/showcase/src/features/demos/web/components/page.tsx +5 -5
- package/samples/apps/showcase/src/features/demos/web/index.ts +4 -4
- package/samples/apps/showcase/src/features/demos/web/pages/dialog.tsx +1 -1
- package/samples/apps/showcase/src/features/demos/web/pages/inputs.tsx +8 -8
- package/samples/apps/showcase/src/features/demos/web/pages/layout.tsx +5 -5
- package/samples/apps/showcase/src/features/demos/web/pages/toast.tsx +3 -3
- package/samples/apps/showcase/src/features/items/feature.ts +8 -8
- package/samples/apps/showcase/src/features/items/i18n.ts +3 -3
- package/samples/apps/showcase/src/features/items/index.ts +3 -3
- package/samples/apps/showcase/src/features/items/schema/index.ts +4 -4
- package/samples/apps/showcase/src/features/items/schema/item.ts +27 -27
- package/samples/apps/showcase/src/features/items/web/index.ts +6 -6
- package/samples/apps/styleguide/src/app/seed.ts +3 -3
- package/samples/apps/styleguide/src/app/server.ts +2 -2
- package/samples/apps/styleguide/src/app/shell.tsx +4 -4
- package/samples/apps/styleguide/src/features/content/web.tsx +6 -6
- package/samples/apps/styleguide/src/features/examples/feature.ts +8 -8
- package/samples/apps/styleguide/src/features/gallery/feature.ts +9 -9
- package/samples/apps/styleguide/src/features/gallery/web/Gallery.tsx +12 -12
- package/samples/apps/styleguide/src/features/widgets/feature.ts +2 -2
- package/samples/apps/styleguide/src/features/widgets/web/DashboardFilterEcho.tsx +3 -3
- package/samples/apps/styleguide/src/features/widgets/web/DashboardKpiIcon.tsx +4 -4
- package/samples/apps/ui-walkthrough/playwright.config.ts +6 -6
- package/samples/apps/ui-walkthrough/scripts/emit-e2e-data.ts +5 -5
- package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +13 -13
- package/samples/apps/ui-walkthrough/src/app/client.tsx +2 -2
- package/samples/apps/ui-walkthrough/src/app/server.ts +14 -14
- package/samples/apps/ui-walkthrough/src/app/shell.tsx +3 -3
- package/samples/apps/use-all-bundled/bin/main.ts +5 -5
- package/samples/apps/use-all-bundled/feature-manifest.json +10 -4
- package/samples/apps/use-all-bundled/kumiko/schema.ts +7 -7
- package/samples/apps/use-all-bundled/scripts/check-coverage.ts +20 -20
- package/samples/apps/use-all-bundled/src/app/auth-constants.ts +4 -4
- package/samples/apps/use-all-bundled/src/app/client.tsx +4 -4
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +12 -12
- package/samples/apps/use-all-bundled/src/app/seed.ts +6 -6
- package/samples/apps/user-data-rights-demo/src/feature.ts +23 -23
- package/samples/apps/workspaces/playwright.config.ts +5 -5
- package/samples/apps/workspaces/src/app/auth-constants.ts +3 -3
- package/samples/apps/workspaces/src/app/server.ts +16 -16
- package/samples/apps/workspaces/src/app/shell.tsx +2 -2
- package/samples/apps/workspaces/src/features/demo/schema/order.ts +4 -4
- package/samples/apps/workspaces/src/features/demo-driver/feature.ts +5 -5
- package/samples/recipes/apex-surface-auth/src/feature.ts +31 -31
- package/samples/recipes/designer-demo/src/feature.ts +6 -6
- package/samples/recipes/encrypted-tenant-config/src/feature.ts +20 -20
- package/samples/recipes/lane-routing/src/feature.ts +5 -5
- package/samples/recipes/legal-pages/src/feature.ts +29 -29
- package/samples/recipes/record-detail-layout/src/feature.ts +21 -2
- package/samples/recipes/seed-migration/scripts/smoke.ts +20 -20
- package/samples/recipes/seed-migration/seeds/2026-01-01-initial-tenants.ts +11 -11
- package/samples/recipes/seed-migration/seeds/2026-02-01-fix-admin-roles.ts +13 -13
- package/samples/recipes/user-data-rights/src/feature.ts +13 -13
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// Emitter
|
|
2
|
-
// framework-runtime,
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// Playwright
|
|
1
|
+
// Emitter for e2e/.e2e-data.json. Runs under bun, loads the full
|
|
2
|
+
// framework-runtime, builds the registry and writes the generateE2ESpec()
|
|
3
|
+
// output as JSON. Playwright's globalSetup calls this script before
|
|
4
|
+
// every run as a subprocess — so framework-runtime NEVER lands in the
|
|
5
|
+
// Playwright worker (where it collides with Playwright's expect).
|
|
6
6
|
|
|
7
7
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
8
8
|
import { dirname, resolve } from "node:path";
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
//
|
|
2
|
-
// (server
|
|
3
|
-
// `e2e/_helpers/login.ts
|
|
1
|
+
// Pure constants — no framework import. Read both by seed.ts
|
|
2
|
+
// (server side, idempotent admin creation) and by the E2E helper
|
|
3
|
+
// `e2e/_helpers/login.ts`.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// `@cosmicdrift/kumiko-testing/helpers` (
|
|
7
|
-
// `@cosmicdrift/kumiko-bundled-features/.../testing` (
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
5
|
+
// Why separate: e2e specs run in the Playwright worker, which cannot tolerate anything from
|
|
6
|
+
// `@cosmicdrift/kumiko-testing/helpers` (pulls in `vitest`) or
|
|
7
|
+
// `@cosmicdrift/kumiko-bundled-features/.../testing` (pulls that in too) —
|
|
8
|
+
// Vitest's expect redefines Object.prototype symbols and collides
|
|
9
|
+
// with Playwright's expect. This file stays import-chain-empty and is the
|
|
10
|
+
// only safe shared source for the login strings.
|
|
11
11
|
|
|
12
12
|
export const ADMIN_EMAIL = "admin@kumiko.dev";
|
|
13
13
|
export const ADMIN_PASSWORD = "kumiko-admin";
|
|
14
14
|
|
|
15
|
-
// Tenant
|
|
16
|
-
// (plain string
|
|
17
|
-
//
|
|
18
|
-
// `as TenantId
|
|
15
|
+
// Tenant IDs mirrored between server.ts (TenantId cast) and client.tsx
|
|
16
|
+
// (plain string for tenantName mapping). Kept centrally here as plain strings
|
|
17
|
+
// since this file stays framework-free — server.ts does the
|
|
18
|
+
// `as TenantId` cast locally.
|
|
19
19
|
export const DEV_TENANT_ID = "00000000-0000-4000-8000-000000000001";
|
|
20
20
|
export const BETA_TENANT_ID = "00000000-0000-4000-8000-000000000002";
|
|
21
21
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Browser
|
|
2
|
-
//
|
|
1
|
+
// Browser entry. Only collects the ClientFeatures (auth + tasks) and
|
|
2
|
+
// hands shell + clientFeatures to createKumikoApp.
|
|
3
3
|
|
|
4
4
|
import { emailPasswordClient } from "@cosmicdrift/kumiko-bundled-features/auth-email-password/web";
|
|
5
5
|
import { billingFoundationClient } from "@cosmicdrift/kumiko-bundled-features/billing-foundation/web";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// @runtime dev
|
|
2
2
|
//
|
|
3
|
-
// Dev
|
|
4
|
-
// (config/user/tenant/auth)
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Dev server for ui-walkthrough. runDevApp mixes in the standard features
|
|
4
|
+
// (config/user/tenant/auth) automatically when `auth` is set and
|
|
5
|
+
// calls seedAdmin in onAfterSetup. The schema lands in the browser as a
|
|
6
|
+
// window.__KUMIKO_SCHEMA__ injection.
|
|
7
7
|
//
|
|
8
|
-
// Auth
|
|
9
|
-
//
|
|
10
|
-
// in
|
|
8
|
+
// Auth mode active: the client must log in via the login screen,
|
|
9
|
+
// no more auto-mint JWT. Persistent DB mode via KUMIKO_DEV_DB_NAME
|
|
10
|
+
// in the environment.
|
|
11
11
|
|
|
12
12
|
import { createUnsubscribeRoutes } from "@cosmicdrift/kumiko-bundled-features/delivery";
|
|
13
13
|
import { runDevApp } from "@cosmicdrift/kumiko-dev-server";
|
|
@@ -27,17 +27,17 @@ import { seedRental } from "./seed-rental";
|
|
|
27
27
|
import { seedTemplates } from "./seed-templates";
|
|
28
28
|
import { seedVehicles } from "./seed-vehicles";
|
|
29
29
|
|
|
30
|
-
//
|
|
31
|
-
// TenantSwitcher
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
30
|
+
// Two fixed tenants — the admin is a member of both so the
|
|
31
|
+
// TenantSwitcher is visible in the sample (renders only with >1 tenant).
|
|
32
|
+
// Different roles per tenant prove tenant-isolated
|
|
33
|
+
// memberships. TenantId cast local at the use site (auth-constants.ts
|
|
34
|
+
// stays framework-free for the E2E helper path).
|
|
35
35
|
|
|
36
36
|
await runDevApp({
|
|
37
37
|
features: [...APP_FEATURES],
|
|
38
38
|
seeds: [seedTasks, seedRental, seedVehicles, seedTemplates, seedPlanTerms],
|
|
39
|
-
// PORT env
|
|
40
|
-
//
|
|
39
|
+
// PORT env var override for Playwright e2e runs (config points to 4174);
|
|
40
|
+
// otherwise local default 4173.
|
|
41
41
|
port: Number.parseInt(process.env["PORT"] ?? "4173", 10),
|
|
42
42
|
// Logo and attachment uploads of the mail editor need a file store.
|
|
43
43
|
files: { storageProvider: createInMemoryFileProvider() },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// AppShell
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// AppShell with brand and user menu in the sidebar footer. Tenant, language and
|
|
2
|
+
// theme choice live in the user menu. Tenant name mapping stays in the shell —
|
|
3
|
+
// app-specific logic, not a framework concept.
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
TenantMenuItems,
|
|
@@ -33,11 +33,11 @@ await runProdApp({
|
|
|
33
33
|
// every bundled feature mounted. Real apps wire createPgKmsAdapter(...).
|
|
34
34
|
kms: new InMemoryKmsAdapter(),
|
|
35
35
|
blindIndexKey: Buffer.alloc(32, 7).toString("base64"),
|
|
36
|
-
// migrations default ("./kumiko/migrations") —
|
|
37
|
-
//
|
|
38
|
-
// auth.admin
|
|
39
|
-
// config + user + tenant + auth-email-password. Boot
|
|
40
|
-
//
|
|
36
|
+
// migrations default ("./kumiko/migrations") — boot mode exits before the
|
|
37
|
+
// schema drift gate, the path here is only the runProdApp default.
|
|
38
|
+
// auth.admin triggers composeFeatures(includeBundled:true) — auto-mounts
|
|
39
|
+
// config + user + tenant + auth-email-password. Boot mode exits
|
|
40
|
+
// before admin seeding runs, the value is only a stub for the types.
|
|
41
41
|
auth: {
|
|
42
42
|
admin: {
|
|
43
43
|
email: "smoke@use-all-bundled.local",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"name": "admin-shell",
|
|
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()`.",
|
|
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 (the tenant one can be dropped with `includeTenantOverview: false`), 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()`.",
|
|
39
39
|
"toggleableDefault": null,
|
|
40
40
|
"requires": [
|
|
41
41
|
"user",
|
|
@@ -452,6 +452,10 @@
|
|
|
452
452
|
"exposesApis": [],
|
|
453
453
|
"usesApis": [],
|
|
454
454
|
"extensionsUsed": [
|
|
455
|
+
{
|
|
456
|
+
"extensionName": "emailAppTransport",
|
|
457
|
+
"entityName": "app"
|
|
458
|
+
},
|
|
455
459
|
{
|
|
456
460
|
"extensionName": "deliveryChannel",
|
|
457
461
|
"entityName": "email"
|
|
@@ -1390,7 +1394,7 @@
|
|
|
1390
1394
|
},
|
|
1391
1395
|
{
|
|
1392
1396
|
"name": "inbound-mail-foundation",
|
|
1393
|
-
"description": "Plugin host for inbound e-mail (inbox federation) — provider plugins (inbound-provider-imap, later M365 Graph / Gmail REST) register at the `inboundMailProvider` extension point with verify/fetch and optional oauth/watch (live push). The foundation owns three event-sourced streams (mail-account lifecycle, inbound-message with exactly-once ingest via deterministic aggregate ids, mail-thread rollup) and their projections `read_mail_accounts`/`read_inbound_messages`/`read_mail_threads`; PII fields are envelope-encrypted per tenant subject key before every append (crypto-shredding on tenant destroy). Wire `createInboundMailConnectRoutes` (OAuth connect + anonymous callback outside /api) and `createInboundMailSupervisor` (IDLE watch with backoff + reconciliation poll) in bin/server.ts. Consume `inbound-mail-foundation:event:inbound-message-received` from app features to attach business processes.",
|
|
1397
|
+
"description": "Plugin host for inbound e-mail (inbox federation) — provider plugins (inbound-provider-imap, later M365 Graph / Gmail REST) register at the `inboundMailProvider` extension point with verify/fetch and optional oauth/watch (live push) and send. `sendMailFromAccount(ctx, { accountId, message })` sends from a connected mailbox through its provider (From = the mailbox address, no fallback to the app sender) and answers typed failures (not configured, login rejected, server unreachable, rejected, invalid message); app write handlers call it, it is no endpoint of its own. The foundation owns three event-sourced streams (mail-account lifecycle, inbound-message with exactly-once ingest via deterministic aggregate ids, mail-thread rollup) and their projections `read_mail_accounts`/`read_inbound_messages`/`read_mail_threads`; PII fields are envelope-encrypted per tenant subject key before every append (crypto-shredding on tenant destroy). Wire `createInboundMailConnectRoutes` (OAuth connect + anonymous callback outside /api) and `createInboundMailSupervisor` (IDLE watch with backoff + reconciliation poll) in bin/server.ts. Consume `inbound-mail-foundation:event:inbound-message-received` from app features to attach business processes.",
|
|
1394
1398
|
"toggleableDefault": null,
|
|
1395
1399
|
"adoptsBundledLists": true,
|
|
1396
1400
|
"requires": [
|
|
@@ -1430,7 +1434,7 @@
|
|
|
1430
1434
|
},
|
|
1431
1435
|
{
|
|
1432
1436
|
"name": "inbound-provider-imap",
|
|
1433
|
-
"description": "Registers the `\"imap\"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor.
|
|
1437
|
+
"description": "Registers the `\"imap\"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor. Tenant admins connect a mailbox through the \"Connect mailbox\" form on the mail accounts list (`connect-mailbox` checks the IMAP login and the SMTP login of the outgoing server first, then creates the account and its credential secret in one transaction); programmatic setups store the per-account connection JSON (host/port/secure/user/password, plus smtpHost/smtpPort for sending) in the account credential secret slot before the first sync. Implements the provider `send`: `sendMailFromAccount` sends over the SMTP server of the mailbox itself (implicit TLS, same login) with the mailbox address as From and stores a copy in its sent folder.",
|
|
1434
1438
|
"toggleableDefault": null,
|
|
1435
1439
|
"requires": [
|
|
1436
1440
|
"inbound-mail-foundation",
|
|
@@ -1448,7 +1452,9 @@
|
|
|
1448
1452
|
],
|
|
1449
1453
|
"configKeys": [],
|
|
1450
1454
|
"secrets": [],
|
|
1451
|
-
"writeHandlers": [
|
|
1455
|
+
"writeHandlers": [
|
|
1456
|
+
"inbound-provider-imap:write:connect-mailbox"
|
|
1457
|
+
],
|
|
1452
1458
|
"uiHints": {
|
|
1453
1459
|
"displayLabel": "Inbound Mail · IMAP",
|
|
1454
1460
|
"category": "notifications",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// @runtime dev
|
|
2
|
-
// App
|
|
3
|
-
//
|
|
4
|
-
// dynamic
|
|
2
|
+
// App schema for the `kumiko-schema` CLI (generate | validate). Composes the
|
|
3
|
+
// app features once and derives both CLI inputs. The CLI imports via
|
|
4
|
+
// dynamic import.
|
|
5
5
|
//
|
|
6
|
-
// **Convention:**
|
|
7
|
-
// - `ENTITY_METAS: readonly EntityTableMeta[]` (
|
|
8
|
-
// - `FEATURES: readonly FeatureDefinition[]` (optional —
|
|
9
|
-
// `kumiko-schema validate
|
|
6
|
+
// **Convention:** this file exports
|
|
7
|
+
// - `ENTITY_METAS: readonly EntityTableMeta[]` (required — generate + validate)
|
|
8
|
+
// - `FEATURES: readonly FeatureDefinition[]` (optional — activates
|
|
9
|
+
// the validateBoot layer of `kumiko-schema validate`; without it that layer is skipped)
|
|
10
10
|
|
|
11
11
|
import { collectTableMetas, type EntityTableMeta } from "@cosmicdrift/kumiko-framework/db";
|
|
12
12
|
import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
// biome-ignore-all lint/suspicious/noConsole: CLI
|
|
2
|
+
// biome-ignore-all lint/suspicious/noConsole: CLI script, console is the feature.
|
|
3
3
|
//
|
|
4
|
-
// Coverage lint. Diffs
|
|
5
|
-
// use-all-bundled
|
|
6
|
-
//
|
|
4
|
+
// Coverage lint. Diffs the top-level exports of bundled-features against the features that
|
|
5
|
+
// use-all-bundled mounts (FEATURES from kumiko/schema.ts: APP_FEATURES plus the auth/signup
|
|
6
|
+
// features added by composeFeatures). Catches three drifts:
|
|
7
7
|
//
|
|
8
|
-
// 1.
|
|
9
|
-
// 2.
|
|
10
|
-
// 3.
|
|
8
|
+
// 1. An export that is neither mounted nor listed in EXPECTED_HELD_BACK
|
|
9
|
+
// 2. An EXPECTED_HELD_BACK entry that is no longer an export
|
|
10
|
+
// 3. An EXPECTED_HELD_BACK entry that has since been mounted (stale)
|
|
11
11
|
//
|
|
12
12
|
// Usage:
|
|
13
13
|
// bun samples/apps/use-all-bundled/scripts/check-coverage.ts
|
|
14
|
-
// Exit 0
|
|
14
|
+
// Exit 0 if everything is in sync, exit 1 on drift.
|
|
15
15
|
|
|
16
16
|
import { readFileSync } from "node:fs";
|
|
17
17
|
import { resolve } from "node:path";
|
|
@@ -20,11 +20,11 @@ import { FEATURES } from "../kumiko/schema";
|
|
|
20
20
|
const ROOT = resolve(import.meta.dir, "..");
|
|
21
21
|
const FRAMEWORK_ROOT = resolve(ROOT, "..", "..", "..");
|
|
22
22
|
|
|
23
|
-
// Held-back exports:
|
|
24
|
-
//
|
|
23
|
+
// Held-back exports: exist in bundled-features, but cannot be mounted
|
|
24
|
+
// as a runtime feature in use-all-bundled.
|
|
25
25
|
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
26
|
+
// Only utilities without defineFeature (foundation-shared is pure helpers)
|
|
27
|
+
// and scaffold-only features. Mounted features do not belong here.
|
|
28
28
|
const EXPECTED_HELD_BACK = new Set([
|
|
29
29
|
"foundation-shared", // utilities (requireDefined/requireNonEmpty), kein feature
|
|
30
30
|
"page-render", // shared HTML render/cache helpers (legal/managed-pages), kein defineFeature
|
|
@@ -32,16 +32,16 @@ const EXPECTED_HELD_BACK = new Set([
|
|
|
32
32
|
]);
|
|
33
33
|
|
|
34
34
|
// Sub-paths in bundled-features's package.json exports (./tenant/seeding,
|
|
35
|
-
// ./auth-email-password/web, …)
|
|
36
|
-
//
|
|
37
|
-
// (
|
|
38
|
-
//
|
|
39
|
-
//
|
|
35
|
+
// ./auth-email-password/web, …) are not features, only utilities.
|
|
36
|
+
// We only care about top-level paths. Non-feature exports
|
|
37
|
+
// (root ".", package.json, asset extensions) are excluded so that a
|
|
38
|
+
// future ./styles.css or similar does not wrongly trigger a CI fail as an
|
|
39
|
+
// unreferenced feature.
|
|
40
40
|
function isFeatureExportPath(path: string): boolean {
|
|
41
41
|
if (!path.startsWith("./")) return false;
|
|
42
42
|
const segment = path.slice(2);
|
|
43
43
|
if (segment.length === 0) return false;
|
|
44
|
-
// Top-level only:
|
|
44
|
+
// Top-level only: no further "/" after the first segment.
|
|
45
45
|
if (segment.includes("/")) return false;
|
|
46
46
|
// Feature-Export-Pfade sind extension-frei (./audit, ./feature-toggles).
|
|
47
47
|
// Asset-/Manifest-Exports (./package.json, ./styles.css) haben einen "."
|
|
@@ -68,8 +68,8 @@ const mounted = new Set<string>(FEATURES.map((feature) => feature.name));
|
|
|
68
68
|
const unreferenced = [...exports].filter(
|
|
69
69
|
(name) => !mounted.has(name) && !EXPECTED_HELD_BACK.has(name),
|
|
70
70
|
);
|
|
71
|
-
//
|
|
72
|
-
//
|
|
71
|
+
// Without these checks the guard would have a blind spot in its own config: a
|
|
72
|
+
// renamed or removed feature would silently stay in the list, as would a mounted one.
|
|
73
73
|
const staleHeldBack = [...EXPECTED_HELD_BACK].filter((name) => !exports.has(name));
|
|
74
74
|
const mountedHeldBack = [...EXPECTED_HELD_BACK].filter((name) => mounted.has(name));
|
|
75
75
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
// (Playwright
|
|
3
|
-
// `@cosmicdrift/kumiko-testing/helpers`
|
|
4
|
-
//
|
|
1
|
+
// Pure constants — no framework import, so the E2E login helper
|
|
2
|
+
// (Playwright worker) can read them without pulling in the vitest import chain from
|
|
3
|
+
// `@cosmicdrift/kumiko-testing/helpers` (collides with
|
|
4
|
+
// Playwright's expect via Object.prototype symbols).
|
|
5
5
|
|
|
6
6
|
export const ADMIN_EMAIL = "admin@kumiko.dev";
|
|
7
7
|
export const ADMIN_PASSWORD = "kumiko-admin";
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
// APP_TRANSLATIONS overrides here.
|
|
7
7
|
//
|
|
8
8
|
// APP_TRANSLATIONS: die entity-backed Admin-Screens (tenant/user/managed-pages)
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
9
|
+
// APP_TRANSLATIONS: the entity-backed admin screens (tenant/user/managed-pages)
|
|
10
|
+
// have no /web plugin that would bring their column labels. They use the
|
|
11
|
+
// `<feature>:entity:<e>:field:*` convention and deliberately leave the labels
|
|
12
|
+
// to the app (see user/screens.ts). use-all-bundled IS that app.
|
|
13
13
|
// adminShellClient + tenant/audit/jobs/config: WorkspaceShell needs the
|
|
14
14
|
// admin-shell overview components and Settings-Hub i18n; mirror admin-console
|
|
15
15
|
// client registration for features that run-config already mounts server-side.
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// @runtime dev
|
|
2
2
|
//
|
|
3
|
-
// Dev
|
|
4
|
-
//
|
|
5
|
-
// composeFeatures(includeBundled)
|
|
6
|
-
//
|
|
7
|
-
// bundled
|
|
3
|
+
// Dev/screenshot server for the use-all-bundled sample. In auth mode runDevApp
|
|
4
|
+
// mixes in the 4 standard features (config/user/tenant/auth) automatically via
|
|
5
|
+
// composeFeatures(includeBundled) — exactly the 4 that APP_FEATURES deliberately
|
|
6
|
+
// omits — and seeds the admin in onAfterSetup. That way ONE app renders all
|
|
7
|
+
// bundled feature screens for the docs previews.
|
|
8
8
|
//
|
|
9
|
-
// globalRoles SystemAdmin:
|
|
10
|
-
// user-list, tier-admin, GDPR
|
|
11
|
-
//
|
|
9
|
+
// globalRoles SystemAdmin: unlocks the platform screens (tenant-list,
|
|
10
|
+
// user-list, tier-admin, GDPR inspector). anonymousAccess + extraContext.text
|
|
11
|
+
// content: the public legal-pages routes (/legal/*).
|
|
12
12
|
|
|
13
13
|
import { createTemplateResolverApi } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
|
|
14
14
|
import type { RunDevAppOptions } from "@cosmicdrift/kumiko-dev-server";
|
|
@@ -21,10 +21,10 @@ import { notesFeature } from "./notes-feature";
|
|
|
21
21
|
import { appScreensFeature } from "./screens-feature";
|
|
22
22
|
import { seedScreenshotData } from "./seed";
|
|
23
23
|
|
|
24
|
-
// tier-admin
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// per-
|
|
24
|
+
// tier-admin renders the honest empty state ("no TierMap configured") with the
|
|
25
|
+
// bare createTierEngineFeature() (from APP_FEATURES). A configured tierMap
|
|
26
|
+
// would activate the resolver on every write (incl. login) and needs
|
|
27
|
+
// per-tenant tier assignments — disproportionate for a preview screenshot.
|
|
28
28
|
|
|
29
29
|
export const devAppOptions = {
|
|
30
30
|
// notesFeature is dev-only (app-owned tag host) — see notes-feature.ts for why
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// @runtime dev
|
|
2
|
-
// Seed
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// Dev-only (
|
|
6
|
-
// (runDevApp)
|
|
2
|
+
// Seed data for the feature reference screenshots: so the entity lists
|
|
3
|
+
// do not render empty and the public legal routes have content. Runs
|
|
4
|
+
// after the admin (runDevApp seeds hook), idempotent via the seed helpers.
|
|
5
|
+
// Dev-only (imports the dev-only notes feature) — used only by server.ts
|
|
6
|
+
// (runDevApp) as the screenshot seed, never in the prod boot.
|
|
7
7
|
|
|
8
8
|
import { seedPage } from "@cosmicdrift/kumiko-bundled-features/managed-pages/seeding";
|
|
9
9
|
import { NotesHistoryHandlers } from "@cosmicdrift/kumiko-bundled-features/notes-history";
|
|
@@ -329,7 +329,7 @@ export const seedScreenshotData: SeedFn = async (stack) => {
|
|
|
329
329
|
const devTenant = DEV_TENANT_ID as TenantId;
|
|
330
330
|
const betaTenant = BETA_TENANT_ID as TenantId;
|
|
331
331
|
|
|
332
|
-
// managed-pages —
|
|
332
|
+
// managed-pages — two pages in the dev tenant for the page-list screen.
|
|
333
333
|
await seedPage(stack.db, {
|
|
334
334
|
tenantId: devTenant,
|
|
335
335
|
slug: "about",
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
// kumiko-feature-version: 1
|
|
2
2
|
//
|
|
3
|
-
// todos —
|
|
4
|
-
// rights
|
|
5
|
-
// (export, delete)
|
|
6
|
-
//
|
|
3
|
+
// todos — demo domain feature that integrates into user-data-
|
|
4
|
+
// rights via EXT_USER_DATA. An app author registers one
|
|
5
|
+
// (export, delete) hook per domain entity — that's it. Forget cron, export bundle and
|
|
6
|
+
// GDPR endpoints come entirely from user-data-rights.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
// - r.entity({ name: "todo", ...todoEntity }) → Drizzle
|
|
10
|
-
// - r.writeHandler({ name: "create", … }) →
|
|
11
|
-
// - r.queryHandler({ name: "list", … }) →
|
|
12
|
-
// - r.useExtension(EXT_USER_DATA, "todo") →
|
|
8
|
+
// This feature shows:
|
|
9
|
+
// - r.entity({ name: "todo", ...todoEntity }) → Drizzle table is built
|
|
10
|
+
// - r.writeHandler({ name: "create", … }) → user creates a todo
|
|
11
|
+
// - r.queryHandler({ name: "list", … }) → user sees their todos
|
|
12
|
+
// - r.useExtension(EXT_USER_DATA, "todo") → forget + export integration
|
|
13
13
|
//
|
|
14
|
-
//
|
|
15
|
-
// 1. user-data-rights.request-export.write
|
|
16
|
-
// 2.
|
|
17
|
-
// 3. todoExportHook
|
|
18
|
-
//
|
|
19
|
-
// 4.
|
|
20
|
-
//
|
|
14
|
+
// What happens when the user then calls request-export:
|
|
15
|
+
// 1. user-data-rights.request-export.write triggers a job
|
|
16
|
+
// 2. The worker iterates all EXT_USER_DATA providers (user, fileRef, todo)
|
|
17
|
+
// 3. todoExportHook reads all rows with author_id = userId from
|
|
18
|
+
// ALL of the user's tenants
|
|
19
|
+
// 4. The bundle is packed as a ZIP behind a signed magic link and sent by
|
|
20
|
+
// email
|
|
21
21
|
//
|
|
22
|
-
//
|
|
23
|
-
// 1. user-data-rights
|
|
24
|
-
// 2.
|
|
25
|
-
// 3. todoDeleteHook
|
|
26
|
-
// 4. user
|
|
22
|
+
// What happens when the user calls request-deletion:
|
|
23
|
+
// 1. user-data-rights sets status=DeletionRequested + grace
|
|
24
|
+
// 2. After it expires the run-forget-cleanup cron runs
|
|
25
|
+
// 3. todoDeleteHook DELETEs all rows with author_id = userId
|
|
26
|
+
// 4. The user is anonymized (display_name="(deleted)", email=null)
|
|
27
27
|
|
|
28
28
|
import { UserDataRightsScreens } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
29
29
|
import {
|
|
@@ -51,8 +51,8 @@ export const todoEntity = createEntity({
|
|
|
51
51
|
table: "store_todos",
|
|
52
52
|
idType: "uuid",
|
|
53
53
|
fields: {
|
|
54
|
-
// nullable:
|
|
55
|
-
// (
|
|
54
|
+
// nullable: on GDPR anonymize authorId is set to null
|
|
55
|
+
// (row stays, personal reference removed). Pattern matches fileRef.
|
|
56
56
|
authorId: createTextField({ personal: "ref" }),
|
|
57
57
|
title: createTextField({
|
|
58
58
|
personal: false,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// @runtime test
|
|
2
|
-
// Playwright
|
|
3
|
-
// server
|
|
4
|
-
//
|
|
5
|
-
// walkthrough
|
|
6
|
-
//
|
|
2
|
+
// Playwright config for the workspaces sample. Starts the real dev
|
|
3
|
+
// server as a webServer fixture (port from samples/e2e/e2e-ports.ts).
|
|
4
|
+
// The pattern is 1:1 as in the ui-
|
|
5
|
+
// walkthrough sample — if the pattern is needed again, an extraction
|
|
6
|
+
// is worthwhile.
|
|
7
7
|
|
|
8
8
|
import { defineAppE2eConfig, PLAYWRIGHT_DEMO_ENV } from "@cosmicdrift/kumiko-testing/e2e";
|
|
9
9
|
import { E2E_PORTS } from "../../e2e/e2e-ports";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Pure constants — no framework import. seed.ts needs them on
|
|
2
|
+
// the server, client.tsx may use them for display, later possibly
|
|
3
|
+
// also an E2E helper (see ui-walkthrough/auth-constants.ts).
|
|
4
4
|
|
|
5
5
|
export const ADMIN_EMAIL = "admin@kumiko.dev";
|
|
6
6
|
export const ADMIN_PASSWORD = "kumiko-admin";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// @runtime dev
|
|
2
2
|
//
|
|
3
|
-
// Dev
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Dev server for the workspaces sample. Auth mode active: the client
|
|
4
|
+
// must log in via the login screen. WorkspaceShell then filters
|
|
5
|
+
// by `user.roles` from the session — admin sees all three, other
|
|
6
|
+
// roles only theirs.
|
|
7
7
|
//
|
|
8
|
-
// runDevApp
|
|
9
|
-
//
|
|
10
|
-
// onAfterSetup.
|
|
11
|
-
//
|
|
12
|
-
// clientSchema
|
|
8
|
+
// runDevApp mixes in the standard features (config/user/tenant/auth)
|
|
9
|
+
// automatically when `auth` is set and calls seedAdmin in
|
|
10
|
+
// onAfterSetup. The client loads the schema itself via the
|
|
11
|
+
// authenticated GET /api/schema, no hand-written
|
|
12
|
+
// clientSchema mirror.
|
|
13
13
|
|
|
14
14
|
import { runDevApp } from "@cosmicdrift/kumiko-dev-server";
|
|
15
15
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
@@ -17,17 +17,17 @@ import { demoFeature } from "../features/demo";
|
|
|
17
17
|
import { driverFeature } from "../features/demo-driver";
|
|
18
18
|
import { ADMIN_EMAIL, ADMIN_PASSWORD } from "./auth-constants";
|
|
19
19
|
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// ui-walkthrough
|
|
20
|
+
// One dev tenant is enough — the workspaces filter by `roles` (not
|
|
21
|
+
// by tenant). To demo tenant switching, look at the
|
|
22
|
+
// ui-walkthrough sample.
|
|
23
23
|
const DEV_TENANT_ID = "00000000-0000-4000-8000-000000000010" as TenantId;
|
|
24
24
|
|
|
25
25
|
import { localeDe } from "@cosmicdrift/kumiko-locale-de";
|
|
26
26
|
|
|
27
27
|
await runDevApp({
|
|
28
28
|
features: [localeDe(), demoFeature, driverFeature],
|
|
29
|
-
// PORT env
|
|
30
|
-
//
|
|
29
|
+
// PORT env var override for Playwright e2e runs (config points to 4175);
|
|
30
|
+
// otherwise local default 4174.
|
|
31
31
|
port: Number.parseInt(process.env["PORT"] ?? "4174", 10),
|
|
32
32
|
clientEntry: "./src/app/client.tsx",
|
|
33
33
|
htmlPath: "./public/index.html",
|
|
@@ -37,8 +37,8 @@ await runDevApp({
|
|
|
37
37
|
email: ADMIN_EMAIL,
|
|
38
38
|
password: ADMIN_PASSWORD,
|
|
39
39
|
displayName: "Admin",
|
|
40
|
-
//
|
|
41
|
-
// driver).
|
|
40
|
+
// The admin role grants access to all three workspaces (admin/dispatch/
|
|
41
|
+
// driver). Real-world apps would define further roles + users.
|
|
42
42
|
memberships: [
|
|
43
43
|
{ tenantId: DEV_TENANT_ID, tenantKey: "dev", tenantName: "Dev Tenant", roles: ["Admin"] },
|
|
44
44
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// AppShell
|
|
2
|
-
//
|
|
1
|
+
// AppShell with WorkspaceShell instead of DefaultAppShell — multi-persona
|
|
2
|
+
// app with URL-driven workspace switch and nav tree filter per role.
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
DefaultTopbarActions,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Entity +
|
|
2
|
-
// r.entity/r.screen
|
|
3
|
-
// (clientSchema
|
|
4
|
-
//
|
|
1
|
+
// Entity + screen definitions. IS registered by the server in feature.ts via
|
|
2
|
+
// r.entity/r.screen; the browser-side mirror
|
|
3
|
+
// (clientSchema with navs/workspaces) is obsolete — the client loads the
|
|
4
|
+
// resolved AppSchema itself via the authenticated GET /api/schema.
|
|
5
5
|
|
|
6
6
|
import type {
|
|
7
7
|
EntityDefinition,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// Cross-
|
|
2
|
-
//
|
|
3
|
-
// r.nav.workspaces QNs
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// Cross-feature demo: demo-driver registers a nav that assigns
|
|
2
|
+
// itself to the driver workspace of `demo`. Proves that
|
|
3
|
+
// r.nav.workspaces resolves QNs across feature boundaries — useful
|
|
4
|
+
// for teams that have their own package per persona and dock onto a
|
|
5
|
+
// shared core.
|
|
6
6
|
|
|
7
7
|
import { defineFeature, type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
8
|
import type { TranslationValue } from "@cosmicdrift/kumiko-framework/ui-types";
|