@beechcms/core 0.8.1 → 0.9.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/dist/antivirus/noop-antivirus.provider.d.ts.map +1 -1
- package/dist/antivirus/virustotal-antivirus.provider.d.ts.map +1 -1
- package/dist/auth/account-email.d.ts +3 -0
- package/dist/auth/account-email.d.ts.map +1 -0
- package/dist/auth/account-email.js +9 -0
- package/dist/auth/password-reset-token.repository.d.ts +13 -2
- package/dist/auth/password-reset-token.repository.d.ts.map +1 -1
- package/dist/auth/user.repository.d.ts +69 -4
- package/dist/auth/user.repository.d.ts.map +1 -1
- package/dist/common/canonical-json.d.ts +2 -1
- package/dist/common/canonical-json.d.ts.map +1 -1
- package/dist/common/canonical-json.js +5 -3
- package/dist/content/content-scan.repository.d.ts +1 -1
- package/dist/content/content.repository.d.ts +156 -5
- package/dist/content/content.repository.d.ts.map +1 -1
- package/dist/content/content.repository.js +62 -0
- package/dist/content/seed-media-purge.repository.d.ts +34 -0
- package/dist/content/seed-media-purge.repository.d.ts.map +1 -0
- package/dist/content/seed.repository.d.ts +14 -0
- package/dist/content/seed.repository.d.ts.map +1 -1
- package/dist/dashboard-layout/content-view.d.ts +757 -0
- package/dist/dashboard-layout/content-view.d.ts.map +1 -0
- package/dist/dashboard-layout/content-view.js +285 -0
- package/dist/dashboard-layout/content-view.repository.d.ts +39 -0
- package/dist/dashboard-layout/content-view.repository.d.ts.map +1 -0
- package/dist/dashboard-layout/dashboard-layout.d.ts +5 -0
- package/dist/dashboard-layout/dashboard-layout.d.ts.map +1 -1
- package/dist/dashboard-layout/dashboard-layout.js +17 -9
- package/dist/dashboard-layout/kanban/kanban.d.ts +32 -18
- package/dist/dashboard-layout/kanban/kanban.d.ts.map +1 -1
- package/dist/dashboard-layout/kanban/kanban.js +45 -21
- package/dist/dashboard-layout/seed-layout.d.ts +22 -31
- package/dist/dashboard-layout/seed-layout.d.ts.map +1 -1
- package/dist/dashboard-layout/seed-layout.js +93 -18
- package/dist/dashboard-layout/seed-layout.repository.d.ts +1 -5
- package/dist/dashboard-layout/seed-layout.repository.d.ts.map +1 -1
- package/dist/engine/ddl/ddl.d.ts +31 -0
- package/dist/engine/ddl/ddl.d.ts.map +1 -1
- package/dist/engine/ddl/ddl.js +92 -13
- package/dist/engine/ddl/schema-mutator.d.ts +3 -0
- package/dist/engine/ddl/schema-mutator.d.ts.map +1 -1
- package/dist/engine/ddl/seed-purge-guards.d.ts +7 -0
- package/dist/engine/ddl/seed-purge-guards.d.ts.map +1 -0
- package/dist/engine/ddl/seed-purge-guards.js +19 -0
- package/dist/engine/engine.d.ts +4 -3
- package/dist/engine/engine.d.ts.map +1 -1
- package/dist/engine/engine.js +4 -3
- package/dist/engine/introspection/relation-audit.d.ts +46 -0
- package/dist/engine/introspection/relation-audit.d.ts.map +1 -0
- package/dist/engine/introspection/relation-audit.js +103 -0
- package/dist/engine/introspection/schema-fingerprint.d.ts +2 -1
- package/dist/engine/introspection/schema-fingerprint.d.ts.map +1 -1
- package/dist/engine/introspection/schema-fingerprint.js +8 -3
- package/dist/engine/privacy/policies.d.ts +1 -1
- package/dist/engine/privacy/policies.d.ts.map +1 -1
- package/dist/engine/privacy/policies.js +12 -6
- package/dist/engine/privacy/privacy.service.d.ts +13 -0
- package/dist/engine/privacy/privacy.service.d.ts.map +1 -1
- package/dist/engine/privacy/privacy.service.js +24 -0
- package/dist/engine/query/active-clause.d.ts +19 -0
- package/dist/engine/query/active-clause.d.ts.map +1 -0
- package/dist/engine/query/active-clause.js +27 -0
- package/dist/engine/query/query.d.ts +14 -1
- package/dist/engine/query/query.d.ts.map +1 -1
- package/dist/engine/query/query.js +105 -13
- package/dist/engine/seeds/candidate-ids.d.ts +14 -0
- package/dist/engine/seeds/candidate-ids.d.ts.map +1 -0
- package/dist/engine/seeds/candidate-ids.js +40 -0
- package/dist/engine/seeds/seed-definition-diff.d.ts +38 -0
- package/dist/engine/seeds/seed-definition-diff.d.ts.map +1 -0
- package/dist/engine/seeds/seed-definition-diff.js +51 -0
- package/dist/engine/seeds/seed-registry.d.ts +17 -0
- package/dist/engine/seeds/seed-registry.d.ts.map +1 -1
- package/dist/engine/seeds/seed-registry.js +27 -0
- package/dist/engine/seeds/seed-types-generator.d.ts.map +1 -1
- package/dist/engine/seeds/seed-types-generator.js +4 -5
- package/dist/engine/seeds/seed-validation.d.ts +5 -0
- package/dist/engine/seeds/seed-validation.d.ts.map +1 -1
- package/dist/engine/seeds/seed-validation.js +39 -19
- package/dist/engine/seeds/tag-migration.d.ts +73 -0
- package/dist/engine/seeds/tag-migration.d.ts.map +1 -0
- package/dist/engine/seeds/tag-migration.js +212 -0
- package/dist/engine/seeds/tag-options.d.ts +15 -0
- package/dist/engine/seeds/tag-options.d.ts.map +1 -0
- package/dist/engine/seeds/tag-options.js +111 -0
- package/dist/engine/seeds/tag-value.d.ts +31 -0
- package/dist/engine/seeds/tag-value.d.ts.map +1 -0
- package/dist/engine/seeds/tag-value.js +51 -0
- package/dist/engine/types.d.ts +59 -7
- package/dist/engine/types.d.ts.map +1 -1
- package/dist/engine/validation/cache.d.ts.map +1 -1
- package/dist/engine/validation/cache.js +20 -4
- package/dist/engine/validation/index.d.ts +12 -1
- package/dist/engine/validation/index.d.ts.map +1 -1
- package/dist/engine/validation/index.js +29 -33
- package/dist/engine/validation/primitives.d.ts +12 -0
- package/dist/engine/validation/primitives.d.ts.map +1 -1
- package/dist/engine/validation/primitives.js +22 -0
- package/dist/engine/validation/richtext-sanitizer.d.ts +9 -1
- package/dist/engine/validation/richtext-sanitizer.d.ts.map +1 -1
- package/dist/engine/validation/richtext-sanitizer.js +36 -7
- package/dist/engine/validation/schema-builders.d.ts +16 -0
- package/dist/engine/validation/schema-builders.d.ts.map +1 -1
- package/dist/engine/validation/schema-builders.js +125 -18
- package/dist/index.d.ts +34 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -11
- package/dist/media/file-types.d.ts +12 -0
- package/dist/media/file-types.d.ts.map +1 -1
- package/dist/media/file-types.js +24 -4
- package/dist/media/magic-bytes.d.ts.map +1 -1
- package/dist/media/magic-bytes.js +19 -9
- package/dist/media/media-transform.d.ts +8 -4
- package/dist/media/media-transform.d.ts.map +1 -1
- package/dist/media/media-transform.js +10 -6
- package/dist/media/media.repository.d.ts +5 -0
- package/dist/media/media.repository.d.ts.map +1 -1
- package/dist/notifications/notification-service.d.ts +1 -1
- package/dist/notifications/notification.repository.d.ts +11 -2
- package/dist/notifications/notification.repository.d.ts.map +1 -1
- package/dist/oauth/authorization-code.repository.d.ts +10 -5
- package/dist/oauth/authorization-code.repository.d.ts.map +1 -1
- package/dist/oauth/pkce.d.ts +1 -1
- package/dist/oauth/role-guard.d.ts +30 -11
- package/dist/oauth/role-guard.d.ts.map +1 -1
- package/dist/oauth/role-guard.js +27 -5
- package/dist/oauth/scopes.d.ts +1 -1
- package/dist/oauth/scopes.d.ts.map +1 -1
- package/dist/oauth/token.repository.d.ts +2 -0
- package/dist/oauth/token.repository.d.ts.map +1 -1
- package/dist/queue/queue.interface.d.ts +9 -1
- package/dist/queue/queue.interface.d.ts.map +1 -1
- package/dist/queue/queue.stub.d.ts +1 -1
- package/dist/queue/queue.stub.d.ts.map +1 -1
- package/dist/queue/queue.stub.js +2 -3
- package/dist/queue/scheduler.stub.d.ts.map +1 -1
- package/dist/rate-limit/token-bucket-rate-limiter.d.ts +7 -0
- package/dist/rate-limit/token-bucket-rate-limiter.d.ts.map +1 -1
- package/dist/rate-limit/token-bucket-rate-limiter.js +66 -0
- package/dist/rbac/invitation.repository.d.ts +28 -10
- package/dist/rbac/invitation.repository.d.ts.map +1 -1
- package/dist/rbac/types.d.ts +40 -28
- package/dist/rbac/types.d.ts.map +1 -1
- package/dist/rbac/types.js +2 -1
- package/dist/schema/manifest-seeds.js +3 -3
- package/dist/search/search.repository.d.ts +5 -4
- package/dist/search/search.repository.d.ts.map +1 -1
- package/dist/search/vector-extractor.d.ts.map +1 -1
- package/dist/search/vector-extractor.js +23 -2
- package/dist/search/vector.repository.d.ts +2 -1
- package/dist/search/vector.repository.d.ts.map +1 -1
- package/dist/security/time-trap-token.repository.d.ts +5 -3
- package/dist/security/time-trap-token.repository.d.ts.map +1 -1
- package/dist/settings/site-settings.repository.d.ts +8 -0
- package/dist/settings/site-settings.repository.d.ts.map +1 -1
- package/dist/transfer/flat-seed.d.ts.map +1 -1
- package/dist/transfer/flat-seed.js +6 -1
- package/dist/transfer/row-mapping.d.ts.map +1 -1
- package/dist/transfer/row-mapping.js +9 -2
- package/package.json +9 -4
- package/dist/.tsbuildinfo +0 -1
- package/dist/automations-grammar-words.d.ts +0 -2
- package/dist/automations-grammar-words.d.ts.map +0 -1
- package/dist/automations-grammar-words.js +0 -8
- package/dist/automations.repository.interface.d.ts +0 -19
- package/dist/automations.repository.interface.d.ts.map +0 -1
- package/dist/automations.runner.interface.d.ts +0 -10
- package/dist/automations.runner.interface.d.ts.map +0 -1
- package/dist/automations.runner.stub.d.ts +0 -5
- package/dist/automations.runner.stub.d.ts.map +0 -1
- package/dist/automations.runner.stub.js +0 -7
- package/dist/automations.types.d.ts +0 -75
- package/dist/automations.types.d.ts.map +0 -1
- package/dist/automations.types.js +0 -3
- package/dist/clock.d.ts +0 -25
- package/dist/clock.d.ts.map +0 -1
- package/dist/clock.js +0 -11
- package/dist/content-scan.repository.d.ts +0 -9
- package/dist/content-scan.repository.d.ts.map +0 -1
- package/dist/content-scan.repository.js +0 -3
- package/dist/content.repository.d.ts +0 -247
- package/dist/content.repository.d.ts.map +0 -1
- package/dist/content.repository.js +0 -59
- package/dist/dashboard-layout/kanban/kanban-position.repository.d.ts +0 -19
- package/dist/dashboard-layout/kanban/kanban-position.repository.d.ts.map +0 -1
- package/dist/dashboard-layout/kanban/kanban-position.repository.js +0 -3
- package/dist/dashboard-layout.d.ts +0 -154
- package/dist/dashboard-layout.d.ts.map +0 -1
- package/dist/dashboard-layout.js +0 -186
- package/dist/dashboard-layout.repository.d.ts +0 -18
- package/dist/dashboard-layout.repository.d.ts.map +0 -1
- package/dist/dashboard-layout.repository.js +0 -3
- package/dist/dashboard-permissions.d.ts +0 -3
- package/dist/dashboard-permissions.d.ts.map +0 -1
- package/dist/dashboard-permissions.js +0 -11
- package/dist/dashboard-scopes.d.ts +0 -12
- package/dist/dashboard-scopes.d.ts.map +0 -1
- package/dist/dashboard-scopes.js +0 -30
- package/dist/define-seed.d.ts +0 -3
- package/dist/define-seed.d.ts.map +0 -1
- package/dist/define-seed.js +0 -5
- package/dist/demo-data.repository.d.ts +0 -5
- package/dist/demo-data.repository.d.ts.map +0 -1
- package/dist/demo-data.repository.js +0 -3
- package/dist/email.provider.d.ts +0 -32
- package/dist/email.provider.d.ts.map +0 -1
- package/dist/email.provider.js +0 -4
- package/dist/engine/ddl/seed-ddl-destructive.d.ts +0 -40
- package/dist/engine/ddl/seed-ddl-destructive.d.ts.map +0 -1
- package/dist/engine/ddl/seed-ddl-destructive.js +0 -149
- package/dist/engine/ddl.d.ts +0 -193
- package/dist/engine/ddl.d.ts.map +0 -1
- package/dist/engine/ddl.js +0 -518
- package/dist/engine/define-seed.d.ts +0 -3
- package/dist/engine/define-seed.d.ts.map +0 -1
- package/dist/engine/define-seed.js +0 -5
- package/dist/engine/introspection.d.ts +0 -101
- package/dist/engine/introspection.d.ts.map +0 -1
- package/dist/engine/introspection.js +0 -127
- package/dist/engine/localization.d.ts +0 -127
- package/dist/engine/localization.d.ts.map +0 -1
- package/dist/engine/localization.js +0 -212
- package/dist/engine/policies.d.ts +0 -58
- package/dist/engine/policies.d.ts.map +0 -1
- package/dist/engine/policies.js +0 -168
- package/dist/engine/privacy.service.d.ts +0 -65
- package/dist/engine/privacy.service.d.ts.map +0 -1
- package/dist/engine/privacy.service.js +0 -114
- package/dist/engine/query.d.ts +0 -23
- package/dist/engine/query.d.ts.map +0 -1
- package/dist/engine/query.js +0 -236
- package/dist/engine/relations.d.ts +0 -28
- package/dist/engine/relations.d.ts.map +0 -1
- package/dist/engine/relations.js +0 -25
- package/dist/engine/schema-fingerprint.d.ts +0 -73
- package/dist/engine/schema-fingerprint.d.ts.map +0 -1
- package/dist/engine/schema-fingerprint.js +0 -97
- package/dist/engine/schema-mutator.d.ts +0 -26
- package/dist/engine/schema-mutator.d.ts.map +0 -1
- package/dist/engine/schema-mutator.js +0 -3
- package/dist/engine/seed-ddl-destructive.d.ts +0 -40
- package/dist/engine/seed-ddl-destructive.d.ts.map +0 -1
- package/dist/engine/seed-ddl-destructive.js +0 -149
- package/dist/engine/seed-ddl.d.ts +0 -40
- package/dist/engine/seed-ddl.d.ts.map +0 -1
- package/dist/engine/seed-ddl.js +0 -100
- package/dist/engine/seed-registry.d.ts +0 -71
- package/dist/engine/seed-registry.d.ts.map +0 -1
- package/dist/engine/seed-registry.js +0 -167
- package/dist/engine/seed-types-generator.d.ts +0 -10
- package/dist/engine/seed-types-generator.d.ts.map +0 -1
- package/dist/engine/seed-types-generator.js +0 -89
- package/dist/engine/seed-validation.d.ts +0 -30
- package/dist/engine/seed-validation.d.ts.map +0 -1
- package/dist/engine/seed-validation.js +0 -319
- package/dist/engine/seeds.d.ts +0 -20
- package/dist/engine/seeds.d.ts.map +0 -1
- package/dist/engine/seeds.js +0 -21
- package/dist/engine/serialize.d.ts +0 -20
- package/dist/engine/serialize.d.ts.map +0 -1
- package/dist/engine/serialize.js +0 -160
- package/dist/engine.d.ts +0 -144
- package/dist/engine.d.ts.map +0 -1
- package/dist/engine.js +0 -741
- package/dist/file-types.d.ts +0 -13
- package/dist/file-types.d.ts.map +0 -1
- package/dist/file-types.js +0 -85
- package/dist/hooks.d.ts +0 -29
- package/dist/hooks.d.ts.map +0 -1
- package/dist/hooks.js +0 -3
- package/dist/id-generator.d.ts +0 -26
- package/dist/id-generator.d.ts.map +0 -1
- package/dist/id-generator.js +0 -12
- package/dist/idempotency.repository.d.ts +0 -13
- package/dist/idempotency.repository.d.ts.map +0 -1
- package/dist/idempotency.repository.js +0 -3
- package/dist/kanban-position.repository.d.ts +0 -19
- package/dist/kanban-position.repository.d.ts.map +0 -1
- package/dist/kanban-position.repository.js +0 -3
- package/dist/kanban.d.ts +0 -75
- package/dist/kanban.d.ts.map +0 -1
- package/dist/kanban.js +0 -82
- package/dist/layout-permissions.d.ts +0 -3
- package/dist/layout-permissions.d.ts.map +0 -1
- package/dist/layout-permissions.js +0 -11
- package/dist/media.repository.d.ts +0 -61
- package/dist/media.repository.d.ts.map +0 -1
- package/dist/media.repository.js +0 -3
- package/dist/policies.d.ts +0 -10
- package/dist/policies.d.ts.map +0 -1
- package/dist/policies.js +0 -33
- package/dist/queue.interface.d.ts +0 -39
- package/dist/queue.interface.d.ts.map +0 -1
- package/dist/queue.interface.js +0 -3
- package/dist/queue.stub.d.ts +0 -6
- package/dist/queue.stub.d.ts.map +0 -1
- package/dist/queue.stub.js +0 -8
- package/dist/relations.d.ts +0 -28
- package/dist/relations.d.ts.map +0 -1
- package/dist/relations.js +0 -25
- package/dist/richtext-render.d.ts +0 -11
- package/dist/richtext-render.d.ts.map +0 -1
- package/dist/richtext-render.js +0 -87
- package/dist/richtext.d.ts +0 -11
- package/dist/richtext.d.ts.map +0 -1
- package/dist/richtext.js +0 -13
- package/dist/scheduler.interface.d.ts +0 -4
- package/dist/scheduler.interface.d.ts.map +0 -1
- package/dist/scheduler.interface.js +0 -3
- package/dist/scheduler.stub.d.ts +0 -5
- package/dist/scheduler.stub.d.ts.map +0 -1
- package/dist/scheduler.stub.js +0 -7
- package/dist/schema-mutator.d.ts +0 -26
- package/dist/schema-mutator.d.ts.map +0 -1
- package/dist/schema-mutator.js +0 -3
- package/dist/seed-ddl-destructive.d.ts +0 -40
- package/dist/seed-ddl-destructive.d.ts.map +0 -1
- package/dist/seed-ddl-destructive.js +0 -149
- package/dist/seed-ddl.d.ts +0 -40
- package/dist/seed-ddl.d.ts.map +0 -1
- package/dist/seed-ddl.js +0 -100
- package/dist/seed-layout.d.ts +0 -145
- package/dist/seed-layout.d.ts.map +0 -1
- package/dist/seed-layout.js +0 -192
- package/dist/seed-layout.repository.d.ts +0 -22
- package/dist/seed-layout.repository.d.ts.map +0 -1
- package/dist/seed-layout.repository.js +0 -3
- package/dist/seed-registry.d.ts +0 -71
- package/dist/seed-registry.d.ts.map +0 -1
- package/dist/seed-registry.js +0 -143
- package/dist/seed-types-generator.d.ts +0 -10
- package/dist/seed-types-generator.d.ts.map +0 -1
- package/dist/seed-types-generator.js +0 -86
- package/dist/seed-validation.d.ts +0 -23
- package/dist/seed-validation.d.ts.map +0 -1
- package/dist/seed-validation.js +0 -224
- package/dist/seed.repository.d.ts +0 -37
- package/dist/seed.repository.d.ts.map +0 -1
- package/dist/seed.repository.js +0 -3
- package/dist/seeds.d.ts +0 -20
- package/dist/seeds.d.ts.map +0 -1
- package/dist/seeds.js +0 -21
- package/dist/site-settings.repository.d.ts +0 -16
- package/dist/site-settings.repository.d.ts.map +0 -1
- package/dist/site-settings.repository.js +0 -3
- package/dist/slug-utils.d.ts +0 -18
- package/dist/slug-utils.d.ts.map +0 -1
- package/dist/slug-utils.js +0 -32
- package/dist/storage.d.ts +0 -46
- package/dist/storage.d.ts.map +0 -1
- package/dist/storage.js +0 -3
- package/dist/types.d.ts +0 -243
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -3
- package/dist/validation.d.ts +0 -50
- package/dist/validation.d.ts.map +0 -1
- package/dist/validation.js +0 -660
- package/dist/webhook-validation.d.ts +0 -3
- package/dist/webhook-validation.d.ts.map +0 -1
- package/dist/webhook-validation.js +0 -6
- /package/dist/{automations.repository.interface.js → content/seed-media-purge.repository.js} +0 -0
- /package/dist/{automations.runner.interface.js → dashboard-layout/content-view.repository.js} +0 -0
package/dist/dashboard-layout.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,11 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/dashboard-scopes.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
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
|
-
}
|
package/dist/define-seed.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/define-seed.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/email.provider.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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/email.provider.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { Seed, BranchType } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Ordered DROP TABLE statements for a full hard-delete of a seed's tables.
|
|
4
|
-
* Order: junction drafts → junctions → FTS triggers → FTS table → drafts → main table.
|
|
5
|
-
* All statements use IF EXISTS (idempotent).
|
|
6
|
-
*/
|
|
7
|
-
export declare function generateDropTable(seed: Seed): string[];
|
|
8
|
-
/**
|
|
9
|
-
* DROP COLUMN statements for a single branch (by alias).
|
|
10
|
-
* For multi-relation branches: drops the junction tables (no column on parent).
|
|
11
|
-
* For regular branches: drops from main table + drafts table (if allowDrafts).
|
|
12
|
-
* Does NOT include FTS handling — callers must prepend ftsTriggerDrops() and
|
|
13
|
-
* append planFtsRebuild() when the branch is searchable.
|
|
14
|
-
*/
|
|
15
|
-
export declare function generateDropColumn(seed: Seed, alias: string): string[];
|
|
16
|
-
/**
|
|
17
|
-
* RENAME COLUMN statements for a branch alias change.
|
|
18
|
-
* Updates main table + drafts (if allowDrafts).
|
|
19
|
-
* Does NOT handle FTS — callers must rebuild FTS separately (SQLite auto-updates
|
|
20
|
-
* trigger bodies on RENAME but the FTS virtual-table columns keep the old name).
|
|
21
|
-
*/
|
|
22
|
-
export declare function generateRenameColumn(seed: Seed, fromAlias: string, toAlias: string): string[];
|
|
23
|
-
/**
|
|
24
|
-
* Full FTS rebuild: drop triggers + FTS table, then recreate them, then backfill.
|
|
25
|
-
* Returns an empty array if the seed has no searchable branches.
|
|
26
|
-
* The drop steps use IF EXISTS so this is safe to call even if FTS was already dropped.
|
|
27
|
-
*/
|
|
28
|
-
export declare function planFtsRebuild(seed: Seed): string[];
|
|
29
|
-
export interface RetypeColumnPlan {
|
|
30
|
-
statements: string[];
|
|
31
|
-
ftsRebuildNeeded: boolean;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Generates statements to change a branch's SQL storage type using the
|
|
35
|
-
* add-new-column / copy / drop-old / rename approach.
|
|
36
|
-
* Includes FTS rebuild statements when the branch is (or becomes) searchable.
|
|
37
|
-
* `updatedSeed` must already reflect the new type on the renamed branch.
|
|
38
|
-
*/
|
|
39
|
-
export declare function planRetypeColumn(seed: Seed, alias: string, newType: BranchType, updatedSeed: Seed): RetypeColumnPlan;
|
|
40
|
-
//# sourceMappingURL=seed-ddl-destructive.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"seed-ddl-destructive.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/seed-ddl-destructive.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAU,UAAU,EAAE,MAAM,aAAa,CAAA;AAkC3D;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAgBtD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBtE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ7F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAiBnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,UAAU,EACnB,WAAW,EAAE,IAAI,GAChB,gBAAgB,CAyClB"}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
-
import { junctionTableName, generateFtsTable, generateFtsTriggers } from './ddl.js';
|
|
4
|
-
const BRANCH_SQL_TYPE = {
|
|
5
|
-
text: 'TEXT',
|
|
6
|
-
number: 'REAL',
|
|
7
|
-
boolean: 'INTEGER',
|
|
8
|
-
date: 'INTEGER',
|
|
9
|
-
json: 'TEXT',
|
|
10
|
-
richtext: 'TEXT',
|
|
11
|
-
file: 'TEXT',
|
|
12
|
-
tags: 'TEXT',
|
|
13
|
-
relation: 'TEXT',
|
|
14
|
-
repeater: 'TEXT',
|
|
15
|
-
};
|
|
16
|
-
/** Branch types that receive a B-tree index in generateIndexes (used by retype to drop/recreate). */
|
|
17
|
-
const INDEXABLE_TYPES = new Set(['text', 'number', 'date', 'boolean', 'relation']);
|
|
18
|
-
function searchBranches(seed) {
|
|
19
|
-
return seed.branches.filter(b => (b.type === 'text' || b.type === 'richtext') && b.policies?.search !== false);
|
|
20
|
-
}
|
|
21
|
-
function ftsTriggerDrops(slug) {
|
|
22
|
-
return [
|
|
23
|
-
`DROP TRIGGER IF EXISTS fts_${slug}_insert;`,
|
|
24
|
-
`DROP TRIGGER IF EXISTS fts_${slug}_update;`,
|
|
25
|
-
`DROP TRIGGER IF EXISTS fts_${slug}_delete;`,
|
|
26
|
-
`DROP TABLE IF EXISTS fts_${slug};`,
|
|
27
|
-
];
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Ordered DROP TABLE statements for a full hard-delete of a seed's tables.
|
|
31
|
-
* Order: junction drafts → junctions → FTS triggers → FTS table → drafts → main table.
|
|
32
|
-
* All statements use IF EXISTS (idempotent).
|
|
33
|
-
*/
|
|
34
|
-
export function generateDropTable(seed) {
|
|
35
|
-
const stmts = [];
|
|
36
|
-
const { slug } = seed;
|
|
37
|
-
for (const branch of seed.branches) {
|
|
38
|
-
if (branch.type !== 'relation' || branch.multiple !== true)
|
|
39
|
-
continue;
|
|
40
|
-
const jt = junctionTableName(slug, branch.alias);
|
|
41
|
-
stmts.push(`DROP TABLE IF EXISTS ${jt}_drafts;`);
|
|
42
|
-
stmts.push(`DROP TABLE IF EXISTS ${jt};`);
|
|
43
|
-
}
|
|
44
|
-
stmts.push(...ftsTriggerDrops(slug));
|
|
45
|
-
stmts.push(`DROP TABLE IF EXISTS content_${slug}_drafts;`);
|
|
46
|
-
stmts.push(`DROP TABLE IF EXISTS content_${slug};`);
|
|
47
|
-
return stmts;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* DROP COLUMN statements for a single branch (by alias).
|
|
51
|
-
* For multi-relation branches: drops the junction tables (no column on parent).
|
|
52
|
-
* For regular branches: drops from main table + drafts table (if allowDrafts).
|
|
53
|
-
* Does NOT include FTS handling — callers must prepend ftsTriggerDrops() and
|
|
54
|
-
* append planFtsRebuild() when the branch is searchable.
|
|
55
|
-
*/
|
|
56
|
-
export function generateDropColumn(seed, alias) {
|
|
57
|
-
const stmts = [];
|
|
58
|
-
const { slug } = seed;
|
|
59
|
-
const branch = seed.branches.find(b => b.alias === alias);
|
|
60
|
-
if (!branch)
|
|
61
|
-
throw new Error(`Branch '${alias}' not found in seed '${slug}'`);
|
|
62
|
-
if (branch.type === 'relation' && branch.multiple === true) {
|
|
63
|
-
const jt = junctionTableName(slug, alias);
|
|
64
|
-
if (seed.allowDrafts)
|
|
65
|
-
stmts.push(`DROP TABLE IF EXISTS ${jt}_drafts;`);
|
|
66
|
-
stmts.push(`DROP TABLE IF EXISTS ${jt};`);
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
stmts.push(`ALTER TABLE content_${slug} DROP COLUMN ${alias};`);
|
|
70
|
-
if (seed.allowDrafts)
|
|
71
|
-
stmts.push(`ALTER TABLE content_${slug}_drafts DROP COLUMN ${alias};`);
|
|
72
|
-
}
|
|
73
|
-
return stmts;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* RENAME COLUMN statements for a branch alias change.
|
|
77
|
-
* Updates main table + drafts (if allowDrafts).
|
|
78
|
-
* Does NOT handle FTS — callers must rebuild FTS separately (SQLite auto-updates
|
|
79
|
-
* trigger bodies on RENAME but the FTS virtual-table columns keep the old name).
|
|
80
|
-
*/
|
|
81
|
-
export function generateRenameColumn(seed, fromAlias, toAlias) {
|
|
82
|
-
const stmts = [];
|
|
83
|
-
const { slug } = seed;
|
|
84
|
-
stmts.push(`ALTER TABLE content_${slug} RENAME COLUMN ${fromAlias} TO ${toAlias};`);
|
|
85
|
-
if (seed.allowDrafts) {
|
|
86
|
-
stmts.push(`ALTER TABLE content_${slug}_drafts RENAME COLUMN ${fromAlias} TO ${toAlias};`);
|
|
87
|
-
}
|
|
88
|
-
return stmts;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Full FTS rebuild: drop triggers + FTS table, then recreate them, then backfill.
|
|
92
|
-
* Returns an empty array if the seed has no searchable branches.
|
|
93
|
-
* The drop steps use IF EXISTS so this is safe to call even if FTS was already dropped.
|
|
94
|
-
*/
|
|
95
|
-
export function planFtsRebuild(seed) {
|
|
96
|
-
const rtBranches = searchBranches(seed);
|
|
97
|
-
if (rtBranches.length === 0)
|
|
98
|
-
return [];
|
|
99
|
-
const { slug } = seed;
|
|
100
|
-
const stmts = [...ftsTriggerDrops(slug)];
|
|
101
|
-
const ftsTable = generateFtsTable(seed);
|
|
102
|
-
if (ftsTable)
|
|
103
|
-
stmts.push(ftsTable);
|
|
104
|
-
stmts.push(...generateFtsTriggers(seed));
|
|
105
|
-
const cols = rtBranches.map(b => b.alias);
|
|
106
|
-
stmts.push(`INSERT INTO fts_${slug}(entry_id, ${cols.join(', ')}) SELECT id, ${cols.join(', ')} FROM content_${slug};`);
|
|
107
|
-
return stmts;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Generates statements to change a branch's SQL storage type using the
|
|
111
|
-
* add-new-column / copy / drop-old / rename approach.
|
|
112
|
-
* Includes FTS rebuild statements when the branch is (or becomes) searchable.
|
|
113
|
-
* `updatedSeed` must already reflect the new type on the renamed branch.
|
|
114
|
-
*/
|
|
115
|
-
export function planRetypeColumn(seed, alias, newType, updatedSeed) {
|
|
116
|
-
const branch = seed.branches.find(b => b.alias === alias);
|
|
117
|
-
if (!branch)
|
|
118
|
-
throw new Error(`Branch '${alias}' not found in seed '${seed.slug}'`);
|
|
119
|
-
const { slug } = seed;
|
|
120
|
-
const newSqlType = BRANCH_SQL_TYPE[newType];
|
|
121
|
-
const tmpAlias = `${alias}_migrate`;
|
|
122
|
-
const stmts = [];
|
|
123
|
-
// Always drop FTS first to avoid "column referenced in trigger" errors on DROP COLUMN.
|
|
124
|
-
stmts.push(...ftsTriggerDrops(slug));
|
|
125
|
-
// Drop the branch index if it exists on the old column (required before DROP COLUMN).
|
|
126
|
-
if (INDEXABLE_TYPES.has(branch.type) && branch.policies?.filter !== false) {
|
|
127
|
-
stmts.push(`DROP INDEX IF EXISTS idx_${slug}_${alias};`);
|
|
128
|
-
}
|
|
129
|
-
// Main table: add migration column, copy data, drop old, rename.
|
|
130
|
-
stmts.push(`ALTER TABLE content_${slug} ADD COLUMN ${tmpAlias} ${newSqlType};`);
|
|
131
|
-
stmts.push(`UPDATE content_${slug} SET ${tmpAlias} = CAST(${alias} AS ${newSqlType});`);
|
|
132
|
-
stmts.push(`ALTER TABLE content_${slug} DROP COLUMN ${alias};`);
|
|
133
|
-
stmts.push(`ALTER TABLE content_${slug} RENAME COLUMN ${tmpAlias} TO ${alias};`);
|
|
134
|
-
// Recreate index for the renamed column if the new type warrants it.
|
|
135
|
-
if (INDEXABLE_TYPES.has(newType) && branch.policies?.filter !== false) {
|
|
136
|
-
stmts.push(`CREATE INDEX IF NOT EXISTS idx_${slug}_${alias} ON content_${slug}(${alias});`);
|
|
137
|
-
}
|
|
138
|
-
// Drafts table (no indexes to worry about).
|
|
139
|
-
if (seed.allowDrafts) {
|
|
140
|
-
stmts.push(`ALTER TABLE content_${slug}_drafts ADD COLUMN ${tmpAlias} ${newSqlType};`);
|
|
141
|
-
stmts.push(`UPDATE content_${slug}_drafts SET ${tmpAlias} = CAST(${alias} AS ${newSqlType});`);
|
|
142
|
-
stmts.push(`ALTER TABLE content_${slug}_drafts DROP COLUMN ${alias};`);
|
|
143
|
-
stmts.push(`ALTER TABLE content_${slug}_drafts RENAME COLUMN ${tmpAlias} TO ${alias};`);
|
|
144
|
-
}
|
|
145
|
-
// Rebuild FTS if the seed has searchable branches in the updated definition.
|
|
146
|
-
const rebuild = planFtsRebuild(updatedSeed);
|
|
147
|
-
stmts.push(...rebuild);
|
|
148
|
-
return { statements: stmts, ftsRebuildNeeded: rebuild.length > 0 };
|
|
149
|
-
}
|