@cosmicdrift/kumiko-bundled-features 0.208.2 → 0.209.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 (36) hide show
  1. package/package.json +8 -8
  2. package/src/compliance-profiles/__tests__/profile-picker.boot.test.ts +10 -2
  3. package/src/compliance-profiles/__tests__/profile-picker.security.integration.test.ts +50 -0
  4. package/src/compliance-profiles/changes.json +8 -1
  5. package/src/compliance-profiles/constants.ts +5 -0
  6. package/src/compliance-profiles/feature.ts +28 -3
  7. package/src/compliance-profiles/i18n.ts +25 -0
  8. package/src/compliance-profiles/web/client-plugin.tsx +7 -4
  9. package/src/compliance-profiles/web/compliance-profile-catalog.tsx +55 -0
  10. package/src/compliance-profiles/web/i18n.ts +1 -7
  11. package/src/compliance-profiles/web/index.ts +1 -1
  12. package/src/delivery/__tests__/delivery-log-query.integration.test.ts +132 -0
  13. package/src/delivery/__tests__/delivery-pii-kms.integration.test.ts +5 -5
  14. package/src/delivery/__tests__/delivery-screens.boot.test.ts +2 -2
  15. package/src/delivery/__tests__/delivery.integration.test.ts +1 -1
  16. package/src/delivery/changes.json +6 -0
  17. package/src/delivery/constants.ts +1 -0
  18. package/src/delivery/feature.ts +28 -3
  19. package/src/delivery/handlers/log.query.ts +115 -18
  20. package/src/delivery/i18n.ts +4 -0
  21. package/src/delivery/public-names.ts +5 -0
  22. package/src/delivery/web/client-plugin.tsx +6 -7
  23. package/src/delivery/web/delivery-status-cell.tsx +26 -0
  24. package/src/delivery/web/index.ts +1 -1
  25. package/src/sessions/__tests__/session-last-seen.integration.test.ts +165 -0
  26. package/src/sessions/changes.json +6 -0
  27. package/src/sessions/constants.ts +4 -0
  28. package/src/sessions/feature.ts +17 -1
  29. package/src/sessions/schema/user-session.ts +5 -0
  30. package/src/sessions/session-callbacks.ts +20 -1
  31. package/src/sessions/session-checker-fail-open.test.ts +38 -0
  32. package/src/tenant-settings/__tests__/config.test.ts +19 -0
  33. package/src/tenant-settings/config.ts +5 -6
  34. package/src/compliance-profiles/web/compliance-profile-screen.tsx +0 -152
  35. package/src/delivery/web/delivery-log-screen.tsx +0 -103
  36. package/src/delivery/web/i18n.ts +0 -15
@@ -1,152 +0,0 @@
1
- // @runtime client
2
- import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
3
- import { FormScreenShell } from "@cosmicdrift/kumiko-renderer-web";
4
- import { type ReactNode, useCallback, useEffect, useState } from "react";
5
- import { ComplianceProfileHandlers, ComplianceProfileQueries } from "../constants";
6
-
7
- type ProfileSummary = {
8
- readonly key: string;
9
- readonly region: string;
10
- readonly label: string;
11
- readonly authorityContact: string;
12
- };
13
-
14
- type ListProfilesResponse = {
15
- readonly profiles: readonly ProfileSummary[];
16
- };
17
-
18
- type CurrentProfileResponse = {
19
- readonly key: string;
20
- readonly label: string;
21
- readonly region: string;
22
- readonly warning?: string;
23
- };
24
-
25
- type State =
26
- | { readonly kind: "loading" }
27
- | { readonly kind: "error"; readonly message: string }
28
- | {
29
- readonly kind: "ready";
30
- readonly profiles: readonly ProfileSummary[];
31
- readonly current: CurrentProfileResponse | null;
32
- };
33
-
34
- export function ComplianceProfileScreen(): ReactNode {
35
- const t = useTranslation();
36
- const { Banner, Button, Card, Field, Form, Heading, Input, Text } = usePrimitives();
37
- const dispatcher = useDispatcher();
38
- const [state, setState] = useState<State>({ kind: "loading" });
39
- const [selected, setSelected] = useState("");
40
- const [saving, setSaving] = useState(false);
41
- const [actionError, setActionError] = useState<string | null>(null);
42
-
43
- const load = useCallback(async (): Promise<void> => {
44
- setState({ kind: "loading" });
45
- const [profilesRes, currentRes] = await Promise.all([
46
- dispatcher.query<ListProfilesResponse>(ComplianceProfileQueries.listProfiles, {}),
47
- dispatcher.query<CurrentProfileResponse>(ComplianceProfileQueries.forTenant, {}),
48
- ]);
49
- if (!profilesRes.isSuccess) {
50
- setState({ kind: "error", message: profilesRes.error.message });
51
- return;
52
- }
53
- if (!currentRes.isSuccess) {
54
- setState({ kind: "error", message: currentRes.error.message });
55
- return;
56
- }
57
- setSelected(currentRes.data.key);
58
- setState({ kind: "ready", profiles: profilesRes.data.profiles, current: currentRes.data });
59
- }, [dispatcher]);
60
-
61
- useEffect(() => {
62
- void load();
63
- }, [load]);
64
-
65
- const onSave = (): void => {
66
- void (async (): Promise<void> => {
67
- if (selected === "") return;
68
- setActionError(null);
69
- setSaving(true);
70
- const res = await dispatcher.write(ComplianceProfileHandlers.setProfile, {
71
- profileKey: selected,
72
- });
73
- setSaving(false);
74
- if (!res.isSuccess) {
75
- setActionError(res.error.message);
76
- return;
77
- }
78
- await load();
79
- })();
80
- };
81
-
82
- if (state.kind === "loading") {
83
- return (
84
- <FormScreenShell testId="compliance-profile-screen">
85
- <Text variant="small">{t("compliance.profile.loading")}</Text>
86
- </FormScreenShell>
87
- );
88
- }
89
-
90
- if (state.kind === "error") {
91
- return (
92
- <FormScreenShell testId="compliance-profile-screen">
93
- <Banner variant="error">{state.message}</Banner>
94
- </FormScreenShell>
95
- );
96
- }
97
-
98
- const profileOptions = state.profiles.map((profile) => ({
99
- value: profile.key,
100
- label: `${profile.label} (${profile.key})`,
101
- }));
102
-
103
- return (
104
- <FormScreenShell testId="compliance-profile-screen" className="flex flex-col gap-6">
105
- <Heading variant="page">{t("compliance.profile.title")}</Heading>
106
-
107
- {state.current !== null && (
108
- <Banner variant="info" testId="compliance-current-profile">
109
- {t("compliance.profile.current")}: {state.current.label} ({state.current.key})
110
- </Banner>
111
- )}
112
-
113
- <Form
114
- onSubmit={onSave}
115
- actions={
116
- <Button
117
- type="submit"
118
- variant="primary"
119
- disabled={saving || selected === ""}
120
- loading={saving}
121
- testId="compliance-profile-save"
122
- >
123
- {saving ? t("compliance.profile.saving") : t("compliance.profile.save")}
124
- </Button>
125
- }
126
- >
127
- <Field id="compliance-profile-select" label={t("compliance.profile.select")} required>
128
- <Input
129
- kind="select"
130
- id="compliance-profile-select"
131
- name="compliance-profile-select"
132
- value={selected}
133
- onChange={setSelected}
134
- options={profileOptions}
135
- required
136
- />
137
- </Field>
138
- {actionError !== null && <Banner variant="error">{actionError}</Banner>}
139
- </Form>
140
-
141
- <Card slots={{ title: t("compliance.profile.catalog") }}>
142
- <ul className="flex flex-col gap-2 text-sm">
143
- {state.profiles.map((profile) => (
144
- <li key={profile.key} data-profile-key={profile.key}>
145
- <strong>{profile.label}</strong> — {profile.region} — {profile.authorityContact}
146
- </li>
147
- ))}
148
- </ul>
149
- </Card>
150
- </FormScreenShell>
151
- );
152
- }
@@ -1,103 +0,0 @@
1
- // @runtime client
2
- import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
3
- import { FormScreenShell } from "@cosmicdrift/kumiko-renderer-web";
4
- import { type ReactNode, useCallback, useEffect, useState } from "react";
5
- import { DeliveryQueries } from "../public-names";
6
-
7
- type DeliveryRow = {
8
- readonly id: string;
9
- readonly notificationType: string;
10
- readonly channel: string;
11
- readonly recipientAddress: string | null;
12
- readonly status: string;
13
- readonly error: string | null;
14
- };
15
-
16
- type DeliveryLogResponse = {
17
- readonly rows: readonly DeliveryRow[];
18
- };
19
-
20
- type State =
21
- | { readonly kind: "loading" }
22
- | { readonly kind: "error"; readonly message: string }
23
- | { readonly kind: "ready"; readonly rows: readonly DeliveryRow[] };
24
-
25
- export function DeliveryLogScreen(): ReactNode {
26
- const t = useTranslation();
27
- const { Banner, Card, DataTable, Heading, Text } = usePrimitives();
28
- const dispatcher = useDispatcher();
29
- const [state, setState] = useState<State>({ kind: "loading" });
30
-
31
- const load = useCallback(async (): Promise<void> => {
32
- setState({ kind: "loading" });
33
- const res = await dispatcher.query<DeliveryLogResponse>(DeliveryQueries.log, { limit: 50 });
34
- if (!res.isSuccess) {
35
- setState({ kind: "error", message: res.error.message });
36
- return;
37
- }
38
- setState({ kind: "ready", rows: res.data.rows });
39
- }, [dispatcher]);
40
-
41
- useEffect(() => {
42
- void load();
43
- }, [load]);
44
-
45
- if (state.kind === "loading") {
46
- return (
47
- <FormScreenShell testId="delivery-log-screen">
48
- <Text variant="small">{t("delivery.log.loading")}</Text>
49
- </FormScreenShell>
50
- );
51
- }
52
-
53
- if (state.kind === "error") {
54
- return (
55
- <FormScreenShell testId="delivery-log-screen">
56
- <Banner variant="error">{state.message}</Banner>
57
- </FormScreenShell>
58
- );
59
- }
60
-
61
- return (
62
- <FormScreenShell testId="delivery-log-screen" maxWidth="4xl" className="flex flex-col gap-6">
63
- <Heading variant="page">{t("delivery.log.title")}</Heading>
64
-
65
- <Card options={{ padded: false }}>
66
- <DataTable
67
- testId="delivery-log-table"
68
- columns={[
69
- { field: "type", label: t("delivery.log.col.type"), type: "string", sortable: false },
70
- {
71
- field: "channel",
72
- label: t("delivery.log.col.channel"),
73
- type: "string",
74
- sortable: false,
75
- },
76
- {
77
- field: "recipient",
78
- label: t("delivery.log.col.recipient"),
79
- type: "string",
80
- sortable: false,
81
- },
82
- {
83
- field: "status",
84
- label: t("delivery.log.col.status"),
85
- type: "string",
86
- sortable: false,
87
- },
88
- ]}
89
- rows={state.rows.map((row) => ({
90
- id: row.id,
91
- values: {
92
- type: row.notificationType,
93
- channel: row.channel,
94
- recipient: row.recipientAddress ?? "—",
95
- status: row.error ? `${row.status} (${row.error})` : row.status,
96
- },
97
- }))}
98
- emptyState={<Text variant="small">{t("delivery.log.empty")}</Text>}
99
- />
100
- </Card>
101
- </FormScreenShell>
102
- );
103
- }
@@ -1,15 +0,0 @@
1
- // @runtime client
2
- import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
3
-
4
- export const defaultTranslations: TranslationsByLocale = {
5
- en: {
6
- "delivery.log.title": "Delivery log",
7
- "delivery.log.loading": "Loading delivery attempts…",
8
- "delivery.log.empty": "No delivery attempts.",
9
- "delivery.log.col.type": "Type",
10
- "delivery.log.col.channel": "Channel",
11
- "delivery.log.col.recipient": "Recipient",
12
- "delivery.log.col.status": "Status",
13
- "delivery:nav.deliveryLog": "Delivery",
14
- },
15
- };