@beechcms/core 0.9.6 → 0.9.7
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/LICENSE +21 -0
- package/dist/auth/login-request.d.ts +16 -0
- package/dist/auth/login-request.d.ts.map +1 -0
- package/dist/auth/login-request.js +22 -0
- package/dist/automations-grammar-words.d.ts +2 -0
- package/dist/automations-grammar-words.d.ts.map +1 -0
- package/dist/automations-grammar-words.js +8 -0
- package/dist/automations.repository.interface.d.ts +19 -0
- package/dist/automations.repository.interface.d.ts.map +1 -0
- package/dist/automations.repository.interface.js +3 -0
- package/dist/automations.runner.interface.d.ts +10 -0
- package/dist/automations.runner.interface.d.ts.map +1 -0
- package/dist/automations.runner.interface.js +3 -0
- package/dist/automations.runner.stub.d.ts +5 -0
- package/dist/automations.runner.stub.d.ts.map +1 -0
- package/dist/automations.runner.stub.js +7 -0
- package/dist/automations.types.d.ts +75 -0
- package/dist/automations.types.d.ts.map +1 -0
- package/dist/automations.types.js +3 -0
- package/dist/clock.d.ts +25 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +11 -0
- package/dist/content-scan.repository.d.ts +9 -0
- package/dist/content-scan.repository.d.ts.map +1 -0
- package/dist/content-scan.repository.js +3 -0
- package/dist/content.repository.d.ts +247 -0
- package/dist/content.repository.d.ts.map +1 -0
- package/dist/content.repository.js +59 -0
- package/dist/dashboard-layout/content-view.d.ts +4 -4
- package/dist/dashboard-layout/relation-avatar.d.ts +12 -0
- package/dist/dashboard-layout/relation-avatar.d.ts.map +1 -0
- package/dist/dashboard-layout/relation-avatar.js +18 -0
- package/dist/dashboard-layout.d.ts +154 -0
- package/dist/dashboard-layout.d.ts.map +1 -0
- package/dist/dashboard-layout.js +186 -0
- package/dist/dashboard-layout.repository.d.ts +18 -0
- package/dist/dashboard-layout.repository.d.ts.map +1 -0
- package/dist/dashboard-layout.repository.js +3 -0
- package/dist/dashboard-permissions.d.ts +3 -0
- package/dist/dashboard-permissions.d.ts.map +1 -0
- package/dist/dashboard-permissions.js +11 -0
- package/dist/dashboard-scopes.d.ts +12 -0
- package/dist/dashboard-scopes.d.ts.map +1 -0
- package/dist/dashboard-scopes.js +30 -0
- package/dist/define-seed.d.ts +3 -0
- package/dist/define-seed.d.ts.map +1 -0
- package/dist/define-seed.js +5 -0
- package/dist/demo-data.repository.d.ts +5 -0
- package/dist/demo-data.repository.d.ts.map +1 -0
- package/dist/demo-data.repository.js +3 -0
- package/dist/email.provider.d.ts +32 -0
- package/dist/email.provider.d.ts.map +1 -0
- package/dist/email.provider.js +4 -0
- package/dist/engine/ddl.d.ts +0 -23
- package/dist/engine/ddl.d.ts.map +1 -1
- package/dist/engine/ddl.js +3 -59
- package/dist/engine/localization.d.ts +127 -0
- package/dist/engine/localization.d.ts.map +1 -0
- package/dist/engine/localization.js +212 -0
- package/dist/engine/privacy.service.d.ts.map +1 -1
- package/dist/engine/query/search-support.d.ts +32 -0
- package/dist/engine/query/search-support.d.ts.map +1 -0
- package/dist/engine/query/search-support.js +34 -0
- package/dist/engine/query.d.ts.map +1 -1
- package/dist/engine/query.js +0 -12
- package/dist/engine/schema-fingerprint.d.ts +2 -0
- package/dist/engine/schema-fingerprint.d.ts.map +1 -1
- package/dist/engine/schema-fingerprint.js +2 -0
- package/dist/engine/seed-ddl.d.ts +1 -4
- package/dist/engine/seed-ddl.d.ts.map +1 -1
- package/dist/engine/seed-ddl.js +2 -17
- package/dist/engine/seed-registry.d.ts.map +1 -1
- package/dist/engine/seed-types-generator.d.ts +2 -17
- package/dist/engine/seed-types-generator.d.ts.map +1 -1
- package/dist/engine/seed-types-generator.js +3 -31
- package/dist/engine/seed-validation.d.ts.map +1 -1
- package/dist/engine/seed-validation.js +0 -10
- package/dist/engine.d.ts +144 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +741 -0
- package/dist/file-types.d.ts +13 -0
- package/dist/file-types.d.ts.map +1 -0
- package/dist/file-types.js +85 -0
- package/dist/hooks.d.ts +29 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +3 -0
- package/dist/id-generator.d.ts +26 -0
- package/dist/id-generator.d.ts.map +1 -0
- package/dist/id-generator.js +12 -0
- package/dist/idempotency.repository.d.ts +13 -0
- package/dist/idempotency.repository.d.ts.map +1 -0
- package/dist/idempotency.repository.js +3 -0
- package/dist/kanban-position.repository.d.ts +19 -0
- package/dist/kanban-position.repository.d.ts.map +1 -0
- package/dist/kanban-position.repository.js +3 -0
- package/dist/kanban.d.ts +75 -0
- package/dist/kanban.d.ts.map +1 -0
- package/dist/kanban.js +82 -0
- package/dist/layout-permissions.d.ts +3 -0
- package/dist/layout-permissions.d.ts.map +1 -0
- package/dist/layout-permissions.js +11 -0
- package/dist/media.repository.d.ts +61 -0
- package/dist/media.repository.d.ts.map +1 -0
- package/dist/media.repository.js +3 -0
- package/dist/notifications/notification-service.d.ts +2 -2
- package/dist/policies.d.ts +10 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +33 -0
- package/dist/queue.interface.d.ts +39 -0
- package/dist/queue.interface.d.ts.map +1 -0
- package/dist/queue.interface.js +3 -0
- package/dist/queue.stub.d.ts +6 -0
- package/dist/queue.stub.d.ts.map +1 -0
- package/dist/queue.stub.js +8 -0
- package/dist/relations.d.ts +28 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/relations.js +25 -0
- package/dist/richtext-render.d.ts +11 -0
- package/dist/richtext-render.d.ts.map +1 -0
- package/dist/richtext-render.js +87 -0
- package/dist/richtext.d.ts +11 -0
- package/dist/richtext.d.ts.map +1 -0
- package/dist/richtext.js +13 -0
- package/dist/scheduler.interface.d.ts +4 -0
- package/dist/scheduler.interface.d.ts.map +1 -0
- package/dist/scheduler.interface.js +3 -0
- package/dist/scheduler.stub.d.ts +5 -0
- package/dist/scheduler.stub.d.ts.map +1 -0
- package/dist/scheduler.stub.js +7 -0
- package/dist/schema-mutator.d.ts +26 -0
- package/dist/schema-mutator.d.ts.map +1 -0
- package/dist/schema-mutator.js +3 -0
- package/dist/seed-ddl-destructive.d.ts +40 -0
- package/dist/seed-ddl-destructive.d.ts.map +1 -0
- package/dist/seed-ddl-destructive.js +149 -0
- package/dist/seed-ddl.d.ts +40 -0
- package/dist/seed-ddl.d.ts.map +1 -0
- package/dist/seed-ddl.js +100 -0
- package/dist/seed-layout.d.ts +145 -0
- package/dist/seed-layout.d.ts.map +1 -0
- package/dist/seed-layout.js +192 -0
- package/dist/seed-layout.repository.d.ts +22 -0
- package/dist/seed-layout.repository.d.ts.map +1 -0
- package/dist/seed-layout.repository.js +3 -0
- package/dist/seed-registry.d.ts +71 -0
- package/dist/seed-registry.d.ts.map +1 -0
- package/dist/seed-registry.js +143 -0
- package/dist/seed-types-generator.d.ts +1 -1
- package/dist/seed-types-generator.d.ts.map +1 -1
- package/dist/seed-validation.d.ts +23 -0
- package/dist/seed-validation.d.ts.map +1 -0
- package/dist/seed-validation.js +224 -0
- package/dist/seed.repository.d.ts +37 -0
- package/dist/seed.repository.d.ts.map +1 -0
- package/dist/seed.repository.js +3 -0
- package/dist/seeds.d.ts +20 -0
- package/dist/seeds.d.ts.map +1 -0
- package/dist/seeds.js +21 -0
- package/dist/site-settings.repository.d.ts +16 -0
- package/dist/site-settings.repository.d.ts.map +1 -0
- package/dist/site-settings.repository.js +3 -0
- package/dist/slug-utils.d.ts +18 -0
- package/dist/slug-utils.d.ts.map +1 -0
- package/dist/slug-utils.js +32 -0
- package/dist/storage.d.ts +46 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +3 -0
- package/dist/types.d.ts +243 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/validation.d.ts +50 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +660 -0
- package/dist/webhook-validation.d.ts +3 -0
- package/dist/webhook-validation.d.ts.map +1 -0
- package/dist/webhook-validation.js +6 -0
- package/package.json +1 -1
- package/dist/content/content-lock.repository.d.ts +0 -63
- package/dist/content/content-lock.repository.d.ts.map +0 -1
- package/dist/content/content-lock.repository.js +0 -15
|
@@ -125,8 +125,8 @@ export declare const viewConditionalFormatSchema: z.ZodObject<{
|
|
|
125
125
|
value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
|
|
126
126
|
}, z.core.$strip>>;
|
|
127
127
|
tone: z.ZodEnum<{
|
|
128
|
-
info: "info";
|
|
129
128
|
success: "success";
|
|
129
|
+
info: "info";
|
|
130
130
|
warning: "warning";
|
|
131
131
|
neutral: "neutral";
|
|
132
132
|
danger: "danger";
|
|
@@ -275,8 +275,8 @@ export declare const contentViewConfigSchema: z.ZodObject<{
|
|
|
275
275
|
value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
|
|
276
276
|
}, z.core.$strip>>;
|
|
277
277
|
tone: z.ZodEnum<{
|
|
278
|
-
info: "info";
|
|
279
278
|
success: "success";
|
|
279
|
+
info: "info";
|
|
280
280
|
warning: "warning";
|
|
281
281
|
neutral: "neutral";
|
|
282
282
|
danger: "danger";
|
|
@@ -457,8 +457,8 @@ export declare const createContentViewInputSchema: z.ZodObject<{
|
|
|
457
457
|
value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
|
|
458
458
|
}, z.core.$strip>>;
|
|
459
459
|
tone: z.ZodEnum<{
|
|
460
|
-
info: "info";
|
|
461
460
|
success: "success";
|
|
461
|
+
info: "info";
|
|
462
462
|
warning: "warning";
|
|
463
463
|
neutral: "neutral";
|
|
464
464
|
danger: "danger";
|
|
@@ -629,8 +629,8 @@ export declare const updateContentViewInputSchema: z.ZodObject<{
|
|
|
629
629
|
value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
|
|
630
630
|
}, z.core.$strip>>;
|
|
631
631
|
tone: z.ZodEnum<{
|
|
632
|
-
info: "info";
|
|
633
632
|
success: "success";
|
|
633
|
+
info: "info";
|
|
634
634
|
warning: "warning";
|
|
635
635
|
neutral: "neutral";
|
|
636
636
|
danger: "danger";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Branch } from '../engine/types.js';
|
|
2
|
+
import type { SeedLookup } from '../engine/query/search-support.js';
|
|
3
|
+
/**
|
|
4
|
+
* The target-seed branch that supplies a relation's avatar image, or `null` when the relation has no
|
|
5
|
+
* avatar configured or the configuration no longer resolves (target gone, field renamed, retyped,
|
|
6
|
+
* hidden). Callers treat `null` as "no avatar" — a stale `avatarSource` degrades, it never throws.
|
|
7
|
+
*
|
|
8
|
+
* @param branch The relation branch carrying `avatarSource`.
|
|
9
|
+
* @param lookup Resolves the relation target.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveRelationAvatar(branch: Branch, lookup: SeedLookup): Branch | null;
|
|
12
|
+
//# sourceMappingURL=relation-avatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation-avatar.d.ts","sourceRoot":"","sources":["../../src/dashboard-layout/relation-avatar.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAGnE;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAKvF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
import { isImageMediaBranch } from './seed-layout.js';
|
|
4
|
+
/**
|
|
5
|
+
* The target-seed branch that supplies a relation's avatar image, or `null` when the relation has no
|
|
6
|
+
* avatar configured or the configuration no longer resolves (target gone, field renamed, retyped,
|
|
7
|
+
* hidden). Callers treat `null` as "no avatar" — a stale `avatarSource` degrades, it never throws.
|
|
8
|
+
*
|
|
9
|
+
* @param branch The relation branch carrying `avatarSource`.
|
|
10
|
+
* @param lookup Resolves the relation target.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveRelationAvatar(branch, lookup) {
|
|
13
|
+
if (branch.type !== 'relation' || !branch.avatarSource || !branch.targetSeed)
|
|
14
|
+
return null;
|
|
15
|
+
const target = lookup(branch.targetSeed);
|
|
16
|
+
const source = target?.branches.find((b) => b.alias === branch.avatarSource);
|
|
17
|
+
return source && isImageMediaBranch(source) ? source : null;
|
|
18
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Seed } from './types.js';
|
|
3
|
+
/** A placed widget. `type` is namespaced ('core/stat', '@acme/weather').
|
|
4
|
+
* `config` is opaque to core/API except for the optional `seedSlug` key,
|
|
5
|
+
* which enables auto-cleanup when the referenced seed disappears. */
|
|
6
|
+
export interface DashboardWidgetInstance {
|
|
7
|
+
id: string;
|
|
8
|
+
type: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
config: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export interface DashboardColumn {
|
|
13
|
+
id: string;
|
|
14
|
+
widgets: DashboardWidgetInstance[];
|
|
15
|
+
}
|
|
16
|
+
export interface DashboardSection {
|
|
17
|
+
id: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
hideLabel?: boolean;
|
|
20
|
+
collapsible?: boolean;
|
|
21
|
+
/** 1–4 columns. Enforced by validator. */
|
|
22
|
+
columns: DashboardColumn[];
|
|
23
|
+
/** Optional spans on a 12-unit grid, parallel to `columns`, must sum to 12.
|
|
24
|
+
* Absent = equal split. */
|
|
25
|
+
columnSpans?: number[];
|
|
26
|
+
}
|
|
27
|
+
export interface DashboardPageLayout {
|
|
28
|
+
id: string;
|
|
29
|
+
/** URL identity (?page=<slug>). Unique within the layout. */
|
|
30
|
+
slug: string;
|
|
31
|
+
label: string;
|
|
32
|
+
/** Lucide icon name, same convention as DashboardSeedConfig.icon. */
|
|
33
|
+
icon?: string;
|
|
34
|
+
sections: DashboardSection[];
|
|
35
|
+
}
|
|
36
|
+
export interface DashboardLayout {
|
|
37
|
+
/** Format version — bump when introducing breaking changes. */
|
|
38
|
+
version: 1;
|
|
39
|
+
pages: DashboardPageLayout[];
|
|
40
|
+
}
|
|
41
|
+
/** Namespaced widget type — lowercase npm-name-compatible.
|
|
42
|
+
* Built-ins use the 'core/' prefix; custom widgets '@scope/name'. */
|
|
43
|
+
export declare const WIDGET_TYPE_REGEX: RegExp;
|
|
44
|
+
/** Max serialized size of a single widget `config`
|
|
45
|
+
* (`JSON.stringify(widget.config).length`) — guards D1 row bloat. */
|
|
46
|
+
export declare const MAX_WIDGET_CONFIG_BYTES = 8192;
|
|
47
|
+
export declare const dashboardWidgetInstanceSchema: z.ZodObject<{
|
|
48
|
+
id: z.ZodString;
|
|
49
|
+
type: z.ZodString;
|
|
50
|
+
title: z.ZodOptional<z.ZodString>;
|
|
51
|
+
config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export declare const dashboardColumnSchema: z.ZodObject<{
|
|
54
|
+
id: z.ZodString;
|
|
55
|
+
widgets: z.ZodArray<z.ZodObject<{
|
|
56
|
+
id: z.ZodString;
|
|
57
|
+
type: z.ZodString;
|
|
58
|
+
title: z.ZodOptional<z.ZodString>;
|
|
59
|
+
config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
60
|
+
}, z.core.$strip>>;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
export declare const dashboardSectionSchema: z.ZodObject<{
|
|
63
|
+
id: z.ZodString;
|
|
64
|
+
label: z.ZodOptional<z.ZodString>;
|
|
65
|
+
hideLabel: z.ZodOptional<z.ZodBoolean>;
|
|
66
|
+
collapsible: z.ZodOptional<z.ZodBoolean>;
|
|
67
|
+
columns: z.ZodArray<z.ZodObject<{
|
|
68
|
+
id: z.ZodString;
|
|
69
|
+
widgets: z.ZodArray<z.ZodObject<{
|
|
70
|
+
id: z.ZodString;
|
|
71
|
+
type: z.ZodString;
|
|
72
|
+
title: z.ZodOptional<z.ZodString>;
|
|
73
|
+
config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
74
|
+
}, z.core.$strip>>;
|
|
75
|
+
}, z.core.$strip>>;
|
|
76
|
+
columnSpans: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
77
|
+
}, z.core.$strip>;
|
|
78
|
+
export declare const dashboardPageSchema: z.ZodObject<{
|
|
79
|
+
id: z.ZodString;
|
|
80
|
+
slug: z.ZodString;
|
|
81
|
+
label: z.ZodString;
|
|
82
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
83
|
+
sections: z.ZodArray<z.ZodObject<{
|
|
84
|
+
id: z.ZodString;
|
|
85
|
+
label: z.ZodOptional<z.ZodString>;
|
|
86
|
+
hideLabel: z.ZodOptional<z.ZodBoolean>;
|
|
87
|
+
collapsible: z.ZodOptional<z.ZodBoolean>;
|
|
88
|
+
columns: z.ZodArray<z.ZodObject<{
|
|
89
|
+
id: z.ZodString;
|
|
90
|
+
widgets: z.ZodArray<z.ZodObject<{
|
|
91
|
+
id: z.ZodString;
|
|
92
|
+
type: z.ZodString;
|
|
93
|
+
title: z.ZodOptional<z.ZodString>;
|
|
94
|
+
config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
95
|
+
}, z.core.$strip>>;
|
|
96
|
+
}, z.core.$strip>>;
|
|
97
|
+
columnSpans: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
98
|
+
}, z.core.$strip>>;
|
|
99
|
+
}, z.core.$strip>;
|
|
100
|
+
export declare const dashboardLayoutSchema: z.ZodObject<{
|
|
101
|
+
version: z.ZodLiteral<1>;
|
|
102
|
+
pages: z.ZodArray<z.ZodObject<{
|
|
103
|
+
id: z.ZodString;
|
|
104
|
+
slug: z.ZodString;
|
|
105
|
+
label: z.ZodString;
|
|
106
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
107
|
+
sections: z.ZodArray<z.ZodObject<{
|
|
108
|
+
id: z.ZodString;
|
|
109
|
+
label: z.ZodOptional<z.ZodString>;
|
|
110
|
+
hideLabel: z.ZodOptional<z.ZodBoolean>;
|
|
111
|
+
collapsible: z.ZodOptional<z.ZodBoolean>;
|
|
112
|
+
columns: z.ZodArray<z.ZodObject<{
|
|
113
|
+
id: z.ZodString;
|
|
114
|
+
widgets: z.ZodArray<z.ZodObject<{
|
|
115
|
+
id: z.ZodString;
|
|
116
|
+
type: z.ZodString;
|
|
117
|
+
title: z.ZodOptional<z.ZodString>;
|
|
118
|
+
config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
119
|
+
}, z.core.$strip>>;
|
|
120
|
+
}, z.core.$strip>>;
|
|
121
|
+
columnSpans: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
122
|
+
}, z.core.$strip>>;
|
|
123
|
+
}, z.core.$strip>>;
|
|
124
|
+
}, z.core.$strip>;
|
|
125
|
+
/** Structural port of the legacy hardcoded dashboard config into a single
|
|
126
|
+
* 'Overview' page. Widgets fetch their own data: configs carry only the
|
|
127
|
+
* variant and (where relevant) the default seed binding. */
|
|
128
|
+
export declare function generateDefaultDashboardLayout(seeds: Seed[], opts?: {
|
|
129
|
+
newId: () => string;
|
|
130
|
+
}): DashboardLayout;
|
|
131
|
+
export interface DashboardLayoutContext {
|
|
132
|
+
/** Slugs of currently registered seeds (from ISeedRegistry.all()). */
|
|
133
|
+
seedSlugs: ReadonlySet<string>;
|
|
134
|
+
/** Optional: widget types known to the caller (frontend registry).
|
|
135
|
+
* When provided, unknown types produce WARNINGS, never strips. */
|
|
136
|
+
knownWidgetTypes?: ReadonlySet<string>;
|
|
137
|
+
}
|
|
138
|
+
export type ValidateDashboardLayoutResult = {
|
|
139
|
+
ok: true;
|
|
140
|
+
cleaned: DashboardLayout;
|
|
141
|
+
warnings: string[];
|
|
142
|
+
} | {
|
|
143
|
+
ok: false;
|
|
144
|
+
errors: string[];
|
|
145
|
+
cleaned: DashboardLayout;
|
|
146
|
+
warnings: string[];
|
|
147
|
+
};
|
|
148
|
+
/** Semantic validation on top of the Zod shape check (the caller's job).
|
|
149
|
+
* Widgets bound to a seed that no longer exists are silently stripped
|
|
150
|
+
* (auto-cleanup, recorded as a warning). Unknown widget types only warn —
|
|
151
|
+
* custom widgets are invisible to the Worker and must never be stripped.
|
|
152
|
+
* `cleaned` is always returned, errors or not. */
|
|
153
|
+
export declare function validateDashboardLayout(layout: DashboardLayout, ctx: DashboardLayoutContext): ValidateDashboardLayoutResult;
|
|
154
|
+
//# sourceMappingURL=dashboard-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-layout.d.ts","sourceRoot":"","sources":["../src/dashboard-layout.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAMtC;;sEAEsE;AACtE,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,uBAAuB,EAAE,CAAA;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,0CAA0C;IAC1C,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B;gCAC4B;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,OAAO,EAAE,CAAC,CAAA;IACV,KAAK,EAAE,mBAAmB,EAAE,CAAA;CAC7B;AAMD;sEACsE;AACtE,eAAO,MAAM,iBAAiB,QAA6B,CAAA;AAE3D;sEACsE;AACtE,eAAO,MAAM,uBAAuB,OAAO,CAAA;AAM3C,eAAO,MAAM,6BAA6B;;;;;iBAKxC,CAAA;AACF,eAAO,MAAM,qBAAqB;;;;;;;;iBAGhC,CAAA;AACF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;iBAOjC,CAAA;AACF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;iBAM9B,CAAA;AACF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;iBAGhC,CAAA;AAQF;;6DAE6D;AAC7D,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,MAAM,CAAA;CAAE,GAC7B,eAAe,CA2EjB;AAMD,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC9B;uEACmE;IACnE,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CACvC;AAED,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAEjF;;;;mDAImD;AACnD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,EACvB,GAAG,EAAE,sBAAsB,GAC1B,6BAA6B,CA2E/B"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Shared rules used by both the Zod schemas and the semantic validator.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/** Namespaced widget type — lowercase npm-name-compatible.
|
|
8
|
+
* Built-ins use the 'core/' prefix; custom widgets '@scope/name'. */
|
|
9
|
+
export const WIDGET_TYPE_REGEX = /^[a-z0-9@][a-z0-9@/_-]*$/;
|
|
10
|
+
/** Max serialized size of a single widget `config`
|
|
11
|
+
* (`JSON.stringify(widget.config).length`) — guards D1 row bloat. */
|
|
12
|
+
export const MAX_WIDGET_CONFIG_BYTES = 8192;
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Zod schemas for shape validation
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
export const dashboardWidgetInstanceSchema = z.object({
|
|
17
|
+
id: z.string().min(1),
|
|
18
|
+
type: z.string().regex(WIDGET_TYPE_REGEX),
|
|
19
|
+
title: z.string().max(80).optional(),
|
|
20
|
+
config: z.record(z.string(), z.unknown()),
|
|
21
|
+
});
|
|
22
|
+
export const dashboardColumnSchema = z.object({
|
|
23
|
+
id: z.string().min(1),
|
|
24
|
+
widgets: z.array(dashboardWidgetInstanceSchema),
|
|
25
|
+
});
|
|
26
|
+
export const dashboardSectionSchema = z.object({
|
|
27
|
+
id: z.string().min(1),
|
|
28
|
+
label: z.string().max(60).optional(),
|
|
29
|
+
hideLabel: z.boolean().optional(),
|
|
30
|
+
collapsible: z.boolean().optional(),
|
|
31
|
+
columns: z.array(dashboardColumnSchema).min(1).max(4),
|
|
32
|
+
columnSpans: z.array(z.number().int().min(1).max(12)).optional(),
|
|
33
|
+
});
|
|
34
|
+
export const dashboardPageSchema = z.object({
|
|
35
|
+
id: z.string().min(1),
|
|
36
|
+
slug: z.string().regex(/^[a-z0-9][a-z0-9-]*$/).max(40),
|
|
37
|
+
label: z.string().min(1).max(60),
|
|
38
|
+
icon: z.string().max(40).optional(),
|
|
39
|
+
sections: z.array(dashboardSectionSchema).min(1),
|
|
40
|
+
});
|
|
41
|
+
export const dashboardLayoutSchema = z.object({
|
|
42
|
+
version: z.literal(1),
|
|
43
|
+
pages: z.array(dashboardPageSchema).min(1).max(8),
|
|
44
|
+
});
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Default dashboard layout generator
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
const defaultIdFactory = () => crypto.randomUUID();
|
|
49
|
+
/** Structural port of the legacy hardcoded dashboard config into a single
|
|
50
|
+
* 'Overview' page. Widgets fetch their own data: configs carry only the
|
|
51
|
+
* variant and (where relevant) the default seed binding. */
|
|
52
|
+
export function generateDefaultDashboardLayout(seeds, opts) {
|
|
53
|
+
const newId = opts?.newId ?? defaultIdFactory;
|
|
54
|
+
const widget = (type, config) => ({ id: newId(), type, config });
|
|
55
|
+
const singleWidgetColumn = (w) => ({
|
|
56
|
+
id: newId(),
|
|
57
|
+
widgets: [w],
|
|
58
|
+
});
|
|
59
|
+
const sections = [];
|
|
60
|
+
// Setup checklist, full width.
|
|
61
|
+
sections.push({
|
|
62
|
+
id: newId(),
|
|
63
|
+
hideLabel: true,
|
|
64
|
+
columns: [singleWidgetColumn(widget('core/setup-checklist', { variant: 'full' }))],
|
|
65
|
+
});
|
|
66
|
+
// Status row: equal columns; quick-draft needs at least one seed to target.
|
|
67
|
+
const statusWidgets = [
|
|
68
|
+
widget('core/site-status', { variant: 'badge' }),
|
|
69
|
+
widget('core/storage', { variant: 'gauge' }),
|
|
70
|
+
widget('core/publication-stats', { variant: 'trio' }),
|
|
71
|
+
];
|
|
72
|
+
if (seeds.length > 0) {
|
|
73
|
+
statusWidgets.push(widget('core/quick-draft', { variant: 'minimal' }));
|
|
74
|
+
}
|
|
75
|
+
sections.push({
|
|
76
|
+
id: newId(),
|
|
77
|
+
hideLabel: true,
|
|
78
|
+
columns: statusWidgets.map(singleWidgetColumn),
|
|
79
|
+
});
|
|
80
|
+
if (seeds.length > 0) {
|
|
81
|
+
const seedSlug = seeds.find((s) => s.slug === 'articoli')?.slug ?? seeds[0].slug;
|
|
82
|
+
// Content row: recent content | pending drafts.
|
|
83
|
+
sections.push({
|
|
84
|
+
id: newId(),
|
|
85
|
+
hideLabel: true,
|
|
86
|
+
columns: [
|
|
87
|
+
singleWidgetColumn(widget('core/recent-content', { seedSlug, variant: 'list' })),
|
|
88
|
+
singleWidgetColumn(widget('core/pending-drafts', { seedSlug, variant: 'list' })),
|
|
89
|
+
],
|
|
90
|
+
columnSpans: [6, 6],
|
|
91
|
+
});
|
|
92
|
+
// Media & activity row: media gallery | activity feed.
|
|
93
|
+
sections.push({
|
|
94
|
+
id: newId(),
|
|
95
|
+
hideLabel: true,
|
|
96
|
+
columns: [
|
|
97
|
+
singleWidgetColumn(widget('core/media-gallery', { seedSlug, variant: 'grid' })),
|
|
98
|
+
singleWidgetColumn(widget('core/activity-feed', { seedSlug, variant: 'feed' })),
|
|
99
|
+
],
|
|
100
|
+
columnSpans: [6, 6],
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
version: 1,
|
|
105
|
+
pages: [
|
|
106
|
+
{
|
|
107
|
+
id: newId(),
|
|
108
|
+
slug: 'overview',
|
|
109
|
+
label: 'Overview',
|
|
110
|
+
icon: 'LayoutDashboard',
|
|
111
|
+
sections,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** Semantic validation on top of the Zod shape check (the caller's job).
|
|
117
|
+
* Widgets bound to a seed that no longer exists are silently stripped
|
|
118
|
+
* (auto-cleanup, recorded as a warning). Unknown widget types only warn —
|
|
119
|
+
* custom widgets are invisible to the Worker and must never be stripped.
|
|
120
|
+
* `cleaned` is always returned, errors or not. */
|
|
121
|
+
export function validateDashboardLayout(layout, ctx) {
|
|
122
|
+
const errors = [];
|
|
123
|
+
const warnings = [];
|
|
124
|
+
// Auto-cleanup: drop widgets whose config.seedSlug references a missing seed.
|
|
125
|
+
const cleanedPages = layout.pages.map((page) => ({
|
|
126
|
+
...page,
|
|
127
|
+
sections: page.sections.map((section) => ({
|
|
128
|
+
...section,
|
|
129
|
+
columns: section.columns.map((col) => ({
|
|
130
|
+
...col,
|
|
131
|
+
widgets: (col.widgets ?? []).filter((w) => {
|
|
132
|
+
const seedSlug = (w.config ?? {})['seedSlug'];
|
|
133
|
+
if (typeof seedSlug === 'string' && !ctx.seedSlugs.has(seedSlug)) {
|
|
134
|
+
warnings.push(`Widget '${w.type}' (id=${w.id}) removed: seed '${seedSlug}' is not registered.`);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
}),
|
|
139
|
+
})),
|
|
140
|
+
})),
|
|
141
|
+
}));
|
|
142
|
+
// Semantic checks on the cleaned layout
|
|
143
|
+
const seenWidgetIds = new Set();
|
|
144
|
+
const seenPageSlugs = new Set();
|
|
145
|
+
for (const page of cleanedPages) {
|
|
146
|
+
if (seenPageSlugs.has(page.slug)) {
|
|
147
|
+
errors.push(`Page slug '${page.slug}' appears more than once in the layout.`);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
seenPageSlugs.add(page.slug);
|
|
151
|
+
}
|
|
152
|
+
for (const section of page.sections) {
|
|
153
|
+
if (section.columnSpans !== undefined) {
|
|
154
|
+
if (section.columnSpans.length !== section.columns.length) {
|
|
155
|
+
errors.push(`Section ${section.id}: columnSpans has ${section.columnSpans.length} entries for ${section.columns.length} columns.`);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const sum = section.columnSpans.reduce((acc, span) => acc + span, 0);
|
|
159
|
+
if (sum !== 12) {
|
|
160
|
+
errors.push(`Section ${section.id}: columnSpans must sum to 12, got ${sum}.`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
for (const col of section.columns) {
|
|
165
|
+
for (const w of col.widgets) {
|
|
166
|
+
if (seenWidgetIds.has(w.id)) {
|
|
167
|
+
errors.push(`Widget id '${w.id}' appears more than once in the layout.`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
seenWidgetIds.add(w.id);
|
|
171
|
+
}
|
|
172
|
+
if (JSON.stringify(w.config ?? {}).length > MAX_WIDGET_CONFIG_BYTES) {
|
|
173
|
+
errors.push(`Widget '${w.type}' (id=${w.id}): config exceeds ${MAX_WIDGET_CONFIG_BYTES} bytes when serialized.`);
|
|
174
|
+
}
|
|
175
|
+
if (ctx.knownWidgetTypes !== undefined && !ctx.knownWidgetTypes.has(w.type)) {
|
|
176
|
+
warnings.push(`Widget '${w.type}' (id=${w.id}) is not a known widget type.`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const cleaned = { ...layout, pages: cleanedPages };
|
|
183
|
+
if (errors.length > 0)
|
|
184
|
+
return { ok: false, errors, cleaned, warnings };
|
|
185
|
+
return { ok: true, cleaned, warnings };
|
|
186
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DashboardLayout } from './dashboard-layout.js';
|
|
2
|
+
export interface DashboardLayoutRecord {
|
|
3
|
+
scope: string;
|
|
4
|
+
layout: DashboardLayout;
|
|
5
|
+
updatedAt: number;
|
|
6
|
+
updatedBy: string;
|
|
7
|
+
}
|
|
8
|
+
export interface IDashboardLayoutRepository {
|
|
9
|
+
/** Stored layout for a scope, or null if none was ever saved. */
|
|
10
|
+
get(scope: string): Promise<DashboardLayoutRecord | null>;
|
|
11
|
+
/** Scopes that currently have a stored row — used by the Sprint 06 builder UI. */
|
|
12
|
+
listScopes(): Promise<string[]>;
|
|
13
|
+
/** Upsert. `updatedBy` is the writer's user id. */
|
|
14
|
+
upsert(scope: string, layout: DashboardLayout, updatedBy: string): Promise<void>;
|
|
15
|
+
/** Remove the stored row — the "Reset" action. */
|
|
16
|
+
remove(scope: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=dashboard-layout.repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-layout.repository.d.ts","sourceRoot":"","sources":["../src/dashboard-layout.repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAE5D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,eAAe,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,0BAA0B;IACzC,iEAAiE;IACjE,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAA;IACzD,kFAAkF;IAClF,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC/B,mDAAmD;IACnD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChF,kDAAkD;IAClD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-permissions.d.ts","sourceRoot":"","sources":["../src/dashboard-permissions.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,+BAA+B,EAAE,aAAa,CAAC,MAAM,CAAa,CAAA;AAE/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAGzE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
// NOTE: change this list to extend write-access to other roles
|
|
4
|
+
// (e.g. add 'editor', or introduce a fine-grained 'dashboard:edit' permission).
|
|
5
|
+
// Single source of truth — used by both API guards and dashboard buttons.
|
|
6
|
+
export const ROLES_ALLOWED_TO_EDIT_DASHBOARD = ['admin'];
|
|
7
|
+
export function canEditDashboard(role) {
|
|
8
|
+
if (!role)
|
|
9
|
+
return false;
|
|
10
|
+
return ROLES_ALLOWED_TO_EDIT_DASHBOARD.includes(role);
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Roles that may have their own dashboard layout. Single source of truth —
|
|
2
|
+
* extend this list if a new role is introduced. */
|
|
3
|
+
export declare const KNOWN_DASHBOARD_ROLES: ReadonlyArray<string>;
|
|
4
|
+
export declare const DEFAULT_DASHBOARD_SCOPE = "default";
|
|
5
|
+
/** Builds the per-role scope string, e.g. `roleScope('editor') === 'role:editor'`. */
|
|
6
|
+
export declare function roleScope(role: string): string;
|
|
7
|
+
/** Whether `scope` is one of the closed set: `'default' | 'role:<known role>'`. */
|
|
8
|
+
export declare function isValidDashboardScope(scope: string): boolean;
|
|
9
|
+
/** Read-resolution order for a caller's role: `['role:<role>', 'default']`,
|
|
10
|
+
* or just `['default']` for unknown/missing roles. */
|
|
11
|
+
export declare function resolveDashboardScopeChain(role: string | undefined | null): string[];
|
|
12
|
+
//# sourceMappingURL=dashboard-scopes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-scopes.d.ts","sourceRoot":"","sources":["../src/dashboard-scopes.ts"],"names":[],"mappings":"AAOA;oDACoD;AACpD,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,MAAM,CAAuB,CAAA;AAE/E,eAAO,MAAM,uBAAuB,YAAY,CAAA;AAEhD,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAK5D;AAED;uDACuD;AACvD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CAKpF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Dashboard layout scopes (Sprint 06: role-based dashboards)
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
/** Roles that may have their own dashboard layout. Single source of truth —
|
|
7
|
+
* extend this list if a new role is introduced. */
|
|
8
|
+
export const KNOWN_DASHBOARD_ROLES = ['admin', 'editor'];
|
|
9
|
+
export const DEFAULT_DASHBOARD_SCOPE = 'default';
|
|
10
|
+
/** Builds the per-role scope string, e.g. `roleScope('editor') === 'role:editor'`. */
|
|
11
|
+
export function roleScope(role) {
|
|
12
|
+
return `role:${role}`;
|
|
13
|
+
}
|
|
14
|
+
/** Whether `scope` is one of the closed set: `'default' | 'role:<known role>'`. */
|
|
15
|
+
export function isValidDashboardScope(scope) {
|
|
16
|
+
if (scope === DEFAULT_DASHBOARD_SCOPE)
|
|
17
|
+
return true;
|
|
18
|
+
const match = /^role:(.+)$/.exec(scope);
|
|
19
|
+
if (!match)
|
|
20
|
+
return false;
|
|
21
|
+
return KNOWN_DASHBOARD_ROLES.includes(match[1]);
|
|
22
|
+
}
|
|
23
|
+
/** Read-resolution order for a caller's role: `['role:<role>', 'default']`,
|
|
24
|
+
* or just `['default']` for unknown/missing roles. */
|
|
25
|
+
export function resolveDashboardScopeChain(role) {
|
|
26
|
+
if (role && KNOWN_DASHBOARD_ROLES.includes(role)) {
|
|
27
|
+
return [roleScope(role), DEFAULT_DASHBOARD_SCOPE];
|
|
28
|
+
}
|
|
29
|
+
return [DEFAULT_DASHBOARD_SCOPE];
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-seed.d.ts","sourceRoot":"","sources":["../src/define-seed.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAE3C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo-data.repository.d.ts","sourceRoot":"","sources":["../src/demo-data.repository.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,mBAAmB;IAClC,mEAAmE;IACnE,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The resolved email message that the provider receives and sends.
|
|
3
|
+
* Constructed by the service by combining call parameters with template builder output.
|
|
4
|
+
*/
|
|
5
|
+
export interface OutboundEmail {
|
|
6
|
+
/** Sender address in RFC 5321 format (e.g., "Beech CMS <noreply@beechcms.dev>"). */
|
|
7
|
+
from: string;
|
|
8
|
+
/** List of recipient addresses. Must contain at least one element. */
|
|
9
|
+
to: string[];
|
|
10
|
+
subject: string;
|
|
11
|
+
/** Complete HTML body. Must be a valid HTML document (see templates/shell.ts). */
|
|
12
|
+
html: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Formal contract for email sending providers.
|
|
16
|
+
*
|
|
17
|
+
* Every implementation (Resend, SMTP, …) must comply with this interface.
|
|
18
|
+
* It is the only point of coupling between the email module and any external service.
|
|
19
|
+
*
|
|
20
|
+
* To add a new provider: create a class in apps/api/src/shared/email/providers/
|
|
21
|
+
* that implements this interface, then wire it in email.service.ts.
|
|
22
|
+
*/
|
|
23
|
+
export interface EmailProvider {
|
|
24
|
+
/**
|
|
25
|
+
* Sends a single transactional email.
|
|
26
|
+
*
|
|
27
|
+
* @throws {Error} If the provider rejects the request. The caller is responsible
|
|
28
|
+
* for catching and handling this error appropriately.
|
|
29
|
+
*/
|
|
30
|
+
send(email: OutboundEmail): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=email.provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.provider.d.ts","sourceRoot":"","sources":["../src/email.provider.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,EAAE,EAAE,MAAM,EAAE,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1C"}
|
package/dist/engine/ddl.d.ts
CHANGED
|
@@ -68,19 +68,6 @@ export declare function generateDraftTable(seed: Seed): string | null;
|
|
|
68
68
|
* @returns The ALTER TABLE SQL statement.
|
|
69
69
|
*/
|
|
70
70
|
export declare function generateAddColumn(seed: Seed, branch: Branch): string;
|
|
71
|
-
/**
|
|
72
|
-
* Generates the `ALTER TABLE content_{slug}_drafts ADD COLUMN live_snapshot_at INTEGER` statement
|
|
73
|
-
* for a draft table provisioned before the column existed.
|
|
74
|
-
*
|
|
75
|
-
* System column, not a branch — `generateAddColumn` iterates `seed.branches` and can never emit it.
|
|
76
|
-
* NOT idempotent: `ADD COLUMN` fails when the column is already present and `ISchemaMutator.execDdl`
|
|
77
|
-
* aborts the whole batch on the first failing statement, so the caller MUST check the physical
|
|
78
|
-
* columns first (see `planExtendSeed`).
|
|
79
|
-
*
|
|
80
|
-
* @param seed The seed definition. Caller must have verified `seed.allowDrafts`.
|
|
81
|
-
* @returns The ALTER TABLE statement.
|
|
82
|
-
*/
|
|
83
|
-
export declare function generateAddDraftSnapshotColumn(seed: Seed): string;
|
|
84
71
|
/**
|
|
85
72
|
* Generates SQL index statements for system fields (status, created_at)
|
|
86
73
|
* and indexable branch columns.
|
|
@@ -203,14 +190,4 @@ export declare function generateRenameColumn(seed: Seed, from: string, to: strin
|
|
|
203
190
|
* @returns An array of SQL statements.
|
|
204
191
|
*/
|
|
205
192
|
export declare function generateRetypeColumn(seed: Seed, branch: Branch): string[];
|
|
206
|
-
/**
|
|
207
|
-
* Additive statements that turn soft delete on for a table that already exists.
|
|
208
|
-
*
|
|
209
|
-
* The partial unique index is emitted for correctness on tables that were CREATED with
|
|
210
|
-
* `softDelete: true`. On a pre-existing table the inline `slug … UNIQUE` survives as a
|
|
211
|
-
* sqlite_autoindex that SQLite cannot drop via ALTER; there the partial index is redundant
|
|
212
|
-
* and a trashed slug stays reserved until the table is rebuilt (see ROADMAP deferral).
|
|
213
|
-
* Returns [] when the seed does not opt in.
|
|
214
|
-
*/
|
|
215
|
-
export declare function generateEnableSoftDelete(seed: Seed): string[];
|
|
216
193
|
//# sourceMappingURL=ddl.d.ts.map
|
package/dist/engine/ddl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../src/engine/ddl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EACJ,MAAM,EAOP,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGrD;AA6BD;;GAEG;AACH,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../src/engine/ddl.ts"],"names":[],"mappings":"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"}
|