@cosmicdrift/kumiko-bundled-features 0.15.0 → 0.16.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.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>",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ComplianceProfileOverride } from "@cosmicdrift/kumiko-framework/compliance";
|
|
2
|
+
import { parseJsonSafe } from "@cosmicdrift/kumiko-framework/utils";
|
|
3
|
+
|
|
4
|
+
export function parseComplianceProfileOverride(
|
|
5
|
+
raw: string | null,
|
|
6
|
+
tenantId: string,
|
|
7
|
+
callerLabel: string,
|
|
8
|
+
): ComplianceProfileOverride | undefined {
|
|
9
|
+
if (!raw || raw.trim() === "") return undefined;
|
|
10
|
+
const parsed = parseJsonSafe<ComplianceProfileOverride | null>(raw, null);
|
|
11
|
+
if (parsed === null) {
|
|
12
|
+
// biome-ignore lint/suspicious/noConsole: operator visibility for DB-corruption edge-case
|
|
13
|
+
console.warn(
|
|
14
|
+
`[${callerLabel}] tenant ${tenantId}: stored override is not valid JSON, ignoring.`,
|
|
15
|
+
);
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
return parsed;
|
|
19
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import {
|
|
3
3
|
type ComplianceProfileKey,
|
|
4
|
-
type ComplianceProfileOverride,
|
|
5
4
|
type EffectiveComplianceProfile,
|
|
6
5
|
resolveComplianceProfile,
|
|
7
6
|
} from "@cosmicdrift/kumiko-framework/compliance";
|
|
8
7
|
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
8
|
import { z } from "zod";
|
|
9
|
+
import { parseComplianceProfileOverride } from "../_internal/parse-override";
|
|
10
10
|
import { tenantComplianceProfileTable } from "../schema/profile-selection";
|
|
11
11
|
|
|
12
12
|
// Liefert das effektive Compliance-Profile fuer den aktuellen Tenant.
|
|
@@ -29,33 +29,14 @@ export const forTenantQuery = defineQueryHandler({
|
|
|
29
29
|
return resolveComplianceProfile({});
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const override =
|
|
32
|
+
const override = parseComplianceProfileOverride(
|
|
33
|
+
row.override,
|
|
34
|
+
query.user.tenantId,
|
|
35
|
+
"compliance-profiles:for-tenant",
|
|
36
|
+
);
|
|
33
37
|
return resolveComplianceProfile({
|
|
34
38
|
selection: row.profileKey as ComplianceProfileKey, // @cast-boundary engine-payload
|
|
35
39
|
override,
|
|
36
40
|
});
|
|
37
41
|
},
|
|
38
42
|
});
|
|
39
|
-
|
|
40
|
-
function parseOverride(
|
|
41
|
-
raw: string | null,
|
|
42
|
-
tenantId: string,
|
|
43
|
-
): ComplianceProfileOverride | undefined {
|
|
44
|
-
if (!raw || raw.trim() === "") return undefined;
|
|
45
|
-
try {
|
|
46
|
-
const parsed: unknown = JSON.parse(raw);
|
|
47
|
-
return parsed as ComplianceProfileOverride; // @cast-boundary engine-payload
|
|
48
|
-
} catch (e: unknown) {
|
|
49
|
-
const reason = e instanceof Error ? e.message : String(e);
|
|
50
|
-
// Defensiv: ungültiges JSON wird als "kein Override" behandelt. Der
|
|
51
|
-
// set-profile-Handler validiert Zod das Override schon — invalides
|
|
52
|
-
// JSON in der DB ist also nur möglich bei manueller DB-Manipulation
|
|
53
|
-
// oder Migration-Bug. Resolver-Caller darf trotzdem nicht crashen.
|
|
54
|
-
// Operator-Sichtbarkeit via console.warn — Telemetry-Hook spaeter.
|
|
55
|
-
// biome-ignore lint/suspicious/noConsole: operator visibility for DB-corruption edge-case
|
|
56
|
-
console.warn(
|
|
57
|
-
`[compliance-profiles:for-tenant] tenant ${tenantId}: stored override is not valid JSON, falling back to base profile. Reason: ${reason}`,
|
|
58
|
-
);
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
12
12
|
import {
|
|
13
13
|
type ComplianceProfileKey,
|
|
14
|
-
type ComplianceProfileOverride,
|
|
15
14
|
type EffectiveComplianceProfile,
|
|
16
15
|
resolveComplianceProfile,
|
|
17
16
|
} from "@cosmicdrift/kumiko-framework/compliance";
|
|
18
17
|
import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
|
|
19
18
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
19
|
+
import { parseComplianceProfileOverride } from "./_internal/parse-override";
|
|
20
20
|
import { tenantComplianceProfileTable } from "./schema/profile-selection";
|
|
21
21
|
|
|
22
22
|
export interface ResolveProfileForTenantArgs {
|
|
@@ -35,27 +35,13 @@ export async function resolveProfileForTenant(
|
|
|
35
35
|
return resolveComplianceProfile({});
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const override =
|
|
38
|
+
const override = parseComplianceProfileOverride(
|
|
39
|
+
row.override,
|
|
40
|
+
args.tenantId,
|
|
41
|
+
"compliance-profiles:resolve-for-tenant",
|
|
42
|
+
);
|
|
39
43
|
return resolveComplianceProfile({
|
|
40
44
|
selection: row.profileKey as ComplianceProfileKey, // @cast-boundary engine-payload
|
|
41
45
|
override,
|
|
42
46
|
});
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
function parseOverride(
|
|
46
|
-
raw: string | null,
|
|
47
|
-
tenantId: string,
|
|
48
|
-
): ComplianceProfileOverride | undefined {
|
|
49
|
-
if (!raw || raw.trim() === "") return undefined;
|
|
50
|
-
try {
|
|
51
|
-
const parsed: unknown = JSON.parse(raw);
|
|
52
|
-
return parsed as ComplianceProfileOverride; // @cast-boundary engine-payload
|
|
53
|
-
} catch (e: unknown) {
|
|
54
|
-
const reason = e instanceof Error ? e.message : String(e);
|
|
55
|
-
// biome-ignore lint/suspicious/noConsole: operator visibility for DB-corruption edge-case
|
|
56
|
-
console.warn(
|
|
57
|
-
`[compliance-profiles:resolve-for-tenant] tenant ${tenantId}: stored override is not valid JSON, ignoring. Reason: ${reason}`,
|
|
58
|
-
);
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
}
|
package/src/delivery/feature.ts
CHANGED
|
@@ -6,12 +6,19 @@ import { deliveryAttemptSchema } from "./events";
|
|
|
6
6
|
import { logQuery } from "./handlers/log.query";
|
|
7
7
|
import { preferencesQuery } from "./handlers/preferences.query";
|
|
8
8
|
import { setPreferenceWrite } from "./handlers/set-preference.write";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
deliveryAttemptsTable,
|
|
11
|
+
deliveryAttemptsTableMeta,
|
|
12
|
+
notificationPreferenceEntity,
|
|
13
|
+
} from "./tables";
|
|
10
14
|
|
|
11
15
|
export function createDeliveryFeature(): FeatureDefinition {
|
|
12
16
|
return defineFeature("delivery", (r) => {
|
|
13
17
|
r.systemScope();
|
|
14
18
|
r.entity("notification-preference", notificationPreferenceEntity);
|
|
19
|
+
r.unmanagedTable(deliveryAttemptsTableMeta, {
|
|
20
|
+
reason: "read_side.delivery_attempt_log",
|
|
21
|
+
});
|
|
15
22
|
|
|
16
23
|
// Events-only projection source: "deliveryAttempt" is the aggregate-
|
|
17
24
|
// type on the events-table, but there's no r.entity for it — each
|
package/src/jobs/feature.ts
CHANGED
|
@@ -19,11 +19,14 @@ import {
|
|
|
19
19
|
JOB_RUN_FAILED_EVENT,
|
|
20
20
|
JOB_RUN_STARTED_EVENT,
|
|
21
21
|
} from "./job-run-logger";
|
|
22
|
-
import { jobRunLogsTable, jobRunsTable } from "./job-run-table";
|
|
22
|
+
import { jobRunLogsTable, jobRunLogsTableMeta, jobRunsTable } from "./job-run-table";
|
|
23
23
|
|
|
24
24
|
export function createJobsFeature(): FeatureDefinition {
|
|
25
25
|
return defineFeature("jobs", (r) => {
|
|
26
26
|
r.systemScope();
|
|
27
|
+
r.unmanagedTable(jobRunLogsTableMeta, {
|
|
28
|
+
reason: "read_side.job_run_logs",
|
|
29
|
+
});
|
|
27
30
|
// Events-only aggregate: "jobRun" has no r.entity registration, because
|
|
28
31
|
// the entire lifecycle is driven by BullMQ-callback → r.defineEvent
|
|
29
32
|
// (no executor, no CRUD). The boot-validator accepts the two
|