@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
|
@@ -33,36 +33,6 @@ export declare const kanbanCardConfigSchema: z.ZodObject<{
|
|
|
33
33
|
}, z.core.$strip>>>;
|
|
34
34
|
}, z.core.$strip>;
|
|
35
35
|
export type KanbanCardConfig = z.infer<typeof kanbanCardConfigSchema>;
|
|
36
|
-
export declare const seedViewConfigSchema: z.ZodObject<{
|
|
37
|
-
kanban: z.ZodOptional<z.ZodObject<{
|
|
38
|
-
axisBranchId: z.ZodNullable<z.ZodString>;
|
|
39
|
-
sort: z.ZodNullable<z.ZodObject<{
|
|
40
|
-
branchId: z.ZodString;
|
|
41
|
-
dir: z.ZodEnum<{
|
|
42
|
-
ASC: "ASC";
|
|
43
|
-
DESC: "DESC";
|
|
44
|
-
}>;
|
|
45
|
-
}, z.core.$strip>>;
|
|
46
|
-
hiddenColumnValues: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
47
|
-
collapsedColumnValues: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
48
|
-
}, z.core.$strip>>;
|
|
49
|
-
card: z.ZodOptional<z.ZodObject<{
|
|
50
|
-
version: z.ZodLiteral<1>;
|
|
51
|
-
media: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
52
|
-
branchId: z.ZodString;
|
|
53
|
-
}, z.core.$strip>>>;
|
|
54
|
-
header: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
55
|
-
branchId: z.ZodString;
|
|
56
|
-
}, z.core.$strip>>>;
|
|
57
|
-
subtitle: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
58
|
-
branchId: z.ZodString;
|
|
59
|
-
}, z.core.$strip>>>;
|
|
60
|
-
metadata: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
61
|
-
branchId: z.ZodString;
|
|
62
|
-
}, z.core.$strip>>>;
|
|
63
|
-
}, z.core.$strip>>;
|
|
64
|
-
}, z.core.$loose>;
|
|
65
|
-
export type SeedViewConfig = z.infer<typeof seedViewConfigSchema>;
|
|
66
36
|
/** Reference to a Seed branch by its stable id (e.g. 'br_03').
|
|
67
37
|
* Aliases can be renamed — ids cannot. When the id does not match any
|
|
68
38
|
* branch on the Seed at read time, the field is silently stripped (auto-cleanup). */
|
|
@@ -108,6 +78,12 @@ export declare function isFullWidthBranch(branch: Branch): boolean;
|
|
|
108
78
|
export declare function isSeoBranch(branch: Branch): boolean;
|
|
109
79
|
export declare const METADATA_SLOT_CAP = 6;
|
|
110
80
|
export declare function isCardEligibleBranch(branch: Branch): boolean;
|
|
81
|
+
/** Gallery cover: a single-file branch that accepts images (a multi-file/asset-list branch has no single cover). */
|
|
82
|
+
export declare function isImageMediaBranch(branch: Branch): boolean;
|
|
83
|
+
export interface ValidateCardConfigOptions {
|
|
84
|
+
/** Gallery cards only render an image cover: a non-image `media` slot is dropped. */
|
|
85
|
+
mediaImageOnly?: boolean;
|
|
86
|
+
}
|
|
111
87
|
export type ValidateCardConfigResult = {
|
|
112
88
|
ok: true;
|
|
113
89
|
cleaned: KanbanCardConfig;
|
|
@@ -116,7 +92,9 @@ export type ValidateCardConfigResult = {
|
|
|
116
92
|
errors: string[];
|
|
117
93
|
cleaned: KanbanCardConfig;
|
|
118
94
|
};
|
|
119
|
-
export declare function validateCardConfigAgainstSeed(config: KanbanCardConfig, seed: Seed): ValidateCardConfigResult;
|
|
95
|
+
export declare function validateCardConfigAgainstSeed(config: KanbanCardConfig, seed: Seed, options?: ValidateCardConfigOptions): ValidateCardConfigResult;
|
|
96
|
+
/** Max serialized size of a form layout. Keeps the `seed_layouts` row far below D1's per-row limit. */
|
|
97
|
+
export declare const MAX_LAYOUT_BYTES: number;
|
|
120
98
|
export declare const layoutFieldSchema: z.ZodObject<{
|
|
121
99
|
branchId: z.ZodString;
|
|
122
100
|
}, z.core.$strip>;
|
|
@@ -176,6 +154,12 @@ export declare const formLayoutSchema: z.ZodObject<{
|
|
|
176
154
|
}, z.core.$strip>>;
|
|
177
155
|
}, z.core.$strip>>;
|
|
178
156
|
}, z.core.$strip>;
|
|
157
|
+
/**
|
|
158
|
+
* Builds the default editor layout for a Seed with no custom `layout`: full-width branches
|
|
159
|
+
* (richtext, json, galleries) each get their own dedicated section, the remaining branches are
|
|
160
|
+
* packed three per section in seed order, and a single main non-gallery image file branch
|
|
161
|
+
* (`fileOptions.accept === 'image'`) leads the Data tab alone in its own full-width section.
|
|
162
|
+
*/
|
|
179
163
|
export declare function generateDefaultLayout(seed: Seed, opts?: {
|
|
180
164
|
newId: () => string;
|
|
181
165
|
}): FormLayout;
|
|
@@ -188,4 +172,11 @@ export type ValidateLayoutResult = {
|
|
|
188
172
|
cleaned: FormLayout;
|
|
189
173
|
};
|
|
190
174
|
export declare function validateLayoutAgainstSeed(layout: FormLayout, seed: Seed): ValidateLayoutResult;
|
|
175
|
+
/**
|
|
176
|
+
* Makes a stored layout safe to serve after the Seed changed. A layout that breaks the
|
|
177
|
+
* full-width rules falls back to the generated default; otherwise layoutable branches the
|
|
178
|
+
* layout never placed (added to the Seed later) are appended as trailing sections of the
|
|
179
|
+
* first tab, so the editor can always render and fill them.
|
|
180
|
+
*/
|
|
181
|
+
export declare function reconcileLayoutWithSeed(layout: FormLayout, seed: Seed): FormLayout;
|
|
191
182
|
//# sourceMappingURL=seed-layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed-layout.d.ts","sourceRoot":"","sources":["../../src/dashboard-layout/seed-layout.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAOtD,eAAO,MAAM,sBAAsB;;;;;;;;;;;iBAKjC,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAMrE,eAAO,MAAM,mBAAmB;;iBAE9B,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE/D,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;iBAUjC,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"seed-layout.d.ts","sourceRoot":"","sources":["../../src/dashboard-layout/seed-layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { findBranchById } from '../engine/seed-registry.js';
|
|
4
|
+
import { findBranchById } from '../engine/seeds/seed-registry.js';
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
|
-
//
|
|
6
|
+
// Kanban view config — embedded in ContentViewConfig.kanban (seed_views)
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
8
|
export const kanbanViewConfigSchema = z.object({
|
|
9
9
|
axisBranchId: z.string().nullable(),
|
|
@@ -12,7 +12,7 @@ export const kanbanViewConfigSchema = z.object({
|
|
|
12
12
|
collapsedColumnValues: z.array(z.string()).optional(),
|
|
13
13
|
});
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
|
-
// Kanban card layout
|
|
15
|
+
// Kanban card layout — embedded in ContentViewConfig.card (seed_views)
|
|
16
16
|
// ---------------------------------------------------------------------------
|
|
17
17
|
export const cardSlotFieldSchema = z.object({
|
|
18
18
|
branchId: z.string().regex(/^br_[A-Za-z0-9]+$/),
|
|
@@ -28,10 +28,6 @@ export const kanbanCardConfigSchema = z.object({
|
|
|
28
28
|
/** 2-column grid. Hard cap enforced by validator (see METADATA_SLOT_CAP). */
|
|
29
29
|
metadata: z.array(cardSlotFieldSchema).max(6).default([]),
|
|
30
30
|
});
|
|
31
|
-
export const seedViewConfigSchema = z.object({
|
|
32
|
-
kanban: kanbanViewConfigSchema.optional(),
|
|
33
|
-
card: kanbanCardConfigSchema.optional(),
|
|
34
|
-
}).passthrough();
|
|
35
31
|
// ---------------------------------------------------------------------------
|
|
36
32
|
// Branch-type rules used by both the default generator and the validator.
|
|
37
33
|
// ---------------------------------------------------------------------------
|
|
@@ -42,6 +38,12 @@ export function isGalleryBranch(branch) {
|
|
|
42
38
|
return branch.type === 'file'
|
|
43
39
|
&& (branch.multiple === true || branch.format === 'asset-list');
|
|
44
40
|
}
|
|
41
|
+
/** True for a single-file image branch: the candidate cover of the default editor layout. */
|
|
42
|
+
function isCoverImageBranch(branch) {
|
|
43
|
+
return branch.type === 'file'
|
|
44
|
+
&& !isGalleryBranch(branch)
|
|
45
|
+
&& branch.fileOptions?.accept === 'image';
|
|
46
|
+
}
|
|
45
47
|
/** Branch types currently unsupported in the Layout Builder. */
|
|
46
48
|
export const UNSUPPORTED_BRANCH_TYPES = new Set([]);
|
|
47
49
|
/** Aliases that are NEVER included in the editor form (handled by other UI). */
|
|
@@ -80,7 +82,14 @@ export function isCardEligibleBranch(branch) {
|
|
|
80
82
|
return false;
|
|
81
83
|
return true;
|
|
82
84
|
}
|
|
83
|
-
|
|
85
|
+
/** Gallery cover: a single-file branch that accepts images (a multi-file/asset-list branch has no single cover). */
|
|
86
|
+
export function isImageMediaBranch(branch) {
|
|
87
|
+
return isCardEligibleBranch(branch)
|
|
88
|
+
&& branch.type === 'file'
|
|
89
|
+
&& !isGalleryBranch(branch)
|
|
90
|
+
&& branch.fileOptions?.accept === 'image';
|
|
91
|
+
}
|
|
92
|
+
export function validateCardConfigAgainstSeed(config, seed, options = {}) {
|
|
84
93
|
const errors = [];
|
|
85
94
|
const seen = new Set();
|
|
86
95
|
const keepSingle = (f) => {
|
|
@@ -96,7 +105,9 @@ export function validateCardConfigAgainstSeed(config, seed) {
|
|
|
96
105
|
seen.add(f.branchId);
|
|
97
106
|
return { branchId: f.branchId };
|
|
98
107
|
};
|
|
99
|
-
const
|
|
108
|
+
const mediaBranch = config.media ? findBranchById(seed, config.media.branchId) : null;
|
|
109
|
+
const mediaAllowed = !options.mediaImageOnly || (mediaBranch !== null && isImageMediaBranch(mediaBranch));
|
|
110
|
+
const media = mediaAllowed ? keepSingle(config.media) : null;
|
|
100
111
|
const header = keepSingle(config.header);
|
|
101
112
|
const subtitle = keepSingle(config.subtitle);
|
|
102
113
|
const metadata = [];
|
|
@@ -121,27 +132,37 @@ export function validateCardConfigAgainstSeed(config, seed) {
|
|
|
121
132
|
// ---------------------------------------------------------------------------
|
|
122
133
|
// Zod schema for shape validation
|
|
123
134
|
// ---------------------------------------------------------------------------
|
|
135
|
+
/** Max serialized size of a form layout. Keeps the `seed_layouts` row far below D1's per-row limit. */
|
|
136
|
+
export const MAX_LAYOUT_BYTES = 256 * 1024;
|
|
137
|
+
const LAYOUT_ID_MAX = 64;
|
|
138
|
+
const LAYOUT_LABEL_MAX = 120;
|
|
139
|
+
const MAX_SECTIONS_PER_TAB = 50;
|
|
140
|
+
const MAX_FIELDS_PER_COLUMN = 100;
|
|
124
141
|
export const layoutFieldSchema = z.object({ branchId: z.string().regex(/^br_[A-Za-z0-9]+$/) });
|
|
125
142
|
export const layoutColumnSchema = z.object({
|
|
126
|
-
id: z.string().min(1),
|
|
127
|
-
fields: z.array(layoutFieldSchema),
|
|
143
|
+
id: z.string().min(1).max(LAYOUT_ID_MAX),
|
|
144
|
+
fields: z.array(layoutFieldSchema).max(MAX_FIELDS_PER_COLUMN),
|
|
128
145
|
});
|
|
129
146
|
export const layoutSectionSchema = z.object({
|
|
130
|
-
id: z.string().min(1),
|
|
131
|
-
label: z.string().optional(),
|
|
147
|
+
id: z.string().min(1).max(LAYOUT_ID_MAX),
|
|
148
|
+
label: z.string().max(LAYOUT_LABEL_MAX).optional(),
|
|
132
149
|
hideLabel: z.boolean().optional(),
|
|
133
150
|
hideBorder: z.boolean().optional(),
|
|
134
151
|
collapsible: z.boolean().optional(),
|
|
135
152
|
columns: z.array(layoutColumnSchema).min(1).max(4),
|
|
136
153
|
});
|
|
137
154
|
export const layoutTabSchema = z.object({
|
|
138
|
-
id: z.string().min(1),
|
|
155
|
+
id: z.string().min(1).max(LAYOUT_ID_MAX),
|
|
139
156
|
label: z.string().min(1).max(60),
|
|
140
|
-
sections: z.array(layoutSectionSchema).min(1),
|
|
157
|
+
sections: z.array(layoutSectionSchema).min(1).max(MAX_SECTIONS_PER_TAB),
|
|
141
158
|
});
|
|
142
|
-
export const formLayoutSchema = z
|
|
159
|
+
export const formLayoutSchema = z
|
|
160
|
+
.object({
|
|
143
161
|
version: z.literal(1),
|
|
144
162
|
tabs: z.array(layoutTabSchema).min(1).max(8),
|
|
163
|
+
})
|
|
164
|
+
.refine((layout) => new TextEncoder().encode(JSON.stringify(layout)).length <= MAX_LAYOUT_BYTES, {
|
|
165
|
+
message: `Layout exceeds the ${MAX_LAYOUT_BYTES / 1024} KB size limit.`,
|
|
145
166
|
});
|
|
146
167
|
// ---------------------------------------------------------------------------
|
|
147
168
|
// Default layout generator
|
|
@@ -180,15 +201,40 @@ function buildSectionsForBranches(branches, newId) {
|
|
|
180
201
|
}
|
|
181
202
|
return sections;
|
|
182
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Builds the default editor layout for a Seed with no custom `layout`: full-width branches
|
|
206
|
+
* (richtext, json, galleries) each get their own dedicated section, the remaining branches are
|
|
207
|
+
* packed three per section in seed order, and a single main non-gallery image file branch
|
|
208
|
+
* (`fileOptions.accept === 'image'`) leads the Data tab alone in its own full-width section.
|
|
209
|
+
*/
|
|
183
210
|
export function generateDefaultLayout(seed, opts) {
|
|
184
211
|
const newId = opts?.newId ?? defaultIdFactory;
|
|
185
212
|
const layoutable = seed.branches.filter(isLayoutableBranch);
|
|
186
213
|
const seo = layoutable.filter(isSeoBranch);
|
|
187
214
|
const main = layoutable.filter((b) => !isSeoBranch(b));
|
|
215
|
+
const coverCandidates = main.filter(isCoverImageBranch);
|
|
216
|
+
const cover = coverCandidates.length === 1 ? coverCandidates[0] : null;
|
|
217
|
+
const dataTabId = newId();
|
|
218
|
+
let dataSections;
|
|
219
|
+
if (cover) {
|
|
220
|
+
const coverSection = {
|
|
221
|
+
id: newId(),
|
|
222
|
+
label: cover.label,
|
|
223
|
+
hideLabel: true,
|
|
224
|
+
columns: [{ id: newId(), fields: [{ branchId: cover.id }] }],
|
|
225
|
+
};
|
|
226
|
+
const rest = main.filter((b) => b.id !== cover.id);
|
|
227
|
+
dataSections = rest.length === 0
|
|
228
|
+
? [coverSection]
|
|
229
|
+
: [coverSection, ...buildSectionsForBranches(rest, newId)];
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
dataSections = buildSectionsForBranches(main, newId);
|
|
233
|
+
}
|
|
188
234
|
const dataTab = {
|
|
189
|
-
id:
|
|
235
|
+
id: dataTabId,
|
|
190
236
|
label: 'Data',
|
|
191
|
-
sections:
|
|
237
|
+
sections: dataSections,
|
|
192
238
|
};
|
|
193
239
|
const seoTab = {
|
|
194
240
|
id: newId(),
|
|
@@ -267,3 +313,32 @@ export function validateLayoutAgainstSeed(layout, seed) {
|
|
|
267
313
|
return { ok: false, errors, cleaned };
|
|
268
314
|
return { ok: true, cleaned };
|
|
269
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Makes a stored layout safe to serve after the Seed changed. A layout that breaks the
|
|
318
|
+
* full-width rules falls back to the generated default; otherwise layoutable branches the
|
|
319
|
+
* layout never placed (added to the Seed later) are appended as trailing sections of the
|
|
320
|
+
* first tab, so the editor can always render and fill them.
|
|
321
|
+
*/
|
|
322
|
+
export function reconcileLayoutWithSeed(layout, seed) {
|
|
323
|
+
const result = validateLayoutAgainstSeed(layout, seed);
|
|
324
|
+
if (!result.ok)
|
|
325
|
+
return generateDefaultLayout(seed);
|
|
326
|
+
const placed = new Set();
|
|
327
|
+
for (const tab of result.cleaned.tabs) {
|
|
328
|
+
for (const section of tab.sections) {
|
|
329
|
+
for (const column of section.columns) {
|
|
330
|
+
for (const field of column.fields)
|
|
331
|
+
placed.add(field.branchId);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const unplaced = seed.branches.filter((b) => isLayoutableBranch(b) && !placed.has(b.id));
|
|
336
|
+
if (unplaced.length === 0)
|
|
337
|
+
return result.cleaned;
|
|
338
|
+
const [firstTab, ...otherTabs] = result.cleaned.tabs;
|
|
339
|
+
const extended = {
|
|
340
|
+
...firstTab,
|
|
341
|
+
sections: [...firstTab.sections, ...buildSectionsForBranches(unplaced, defaultIdFactory)],
|
|
342
|
+
};
|
|
343
|
+
return { ...result.cleaned, tabs: [extended, ...otherTabs] };
|
|
344
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FormLayout
|
|
1
|
+
import type { FormLayout } from './seed-layout.js';
|
|
2
2
|
export interface SeedLayoutRecord {
|
|
3
3
|
slug: string;
|
|
4
4
|
layout: FormLayout;
|
|
@@ -14,9 +14,5 @@ export interface ISeedLayoutRepository {
|
|
|
14
14
|
upsert(slug: string, layout: FormLayout, updatedBy: string): Promise<void>;
|
|
15
15
|
/** Remove the stored row — used by the "Reset" action. */
|
|
16
16
|
remove(slug: string): Promise<void>;
|
|
17
|
-
/** Return the per-view config blob for a seed, or null if none was stored. */
|
|
18
|
-
getViewConfig(slug: string): Promise<SeedViewConfig | null>;
|
|
19
|
-
/** Upsert the per-view config for a seed. */
|
|
20
|
-
setViewConfig(slug: string, config: SeedViewConfig, updatedBy: string): Promise<void>;
|
|
21
17
|
}
|
|
22
18
|
//# sourceMappingURL=seed-layout.repository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed-layout.repository.d.ts","sourceRoot":"","sources":["../../src/dashboard-layout/seed-layout.repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"seed-layout.repository.d.ts","sourceRoot":"","sources":["../../src/dashboard-layout/seed-layout.repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IACnD,oFAAoF;IACpF,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAA;IAC/C,mDAAmD;IACnD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,0DAA0D;IAC1D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC"}
|
package/dist/engine/ddl/ddl.d.ts
CHANGED
|
@@ -15,6 +15,13 @@ export declare const SYSTEM_COLUMNS: Set<string>;
|
|
|
15
15
|
* @returns The table name.
|
|
16
16
|
*/
|
|
17
17
|
export declare function tableName(seed: Seed): string;
|
|
18
|
+
/**
|
|
19
|
+
* Returns the draft SQL table name for a given Seed.
|
|
20
|
+
*
|
|
21
|
+
* @param seed The seed definition.
|
|
22
|
+
* @returns The draft table name.
|
|
23
|
+
*/
|
|
24
|
+
export declare function draftTableName(seed: Seed): string;
|
|
18
25
|
/**
|
|
19
26
|
* Returns the FTS (Full-Text Search) virtual table name for a given Seed.
|
|
20
27
|
*
|
|
@@ -184,6 +191,17 @@ export declare function generateDropTable(seed: Seed): string[];
|
|
|
184
191
|
* @returns An array of SQL statements.
|
|
185
192
|
*/
|
|
186
193
|
export declare function generateDropColumn(seed: Seed, alias: string): string[];
|
|
194
|
+
/**
|
|
195
|
+
* Returns the SQL statements that drop an orphan column: one left in the physical table after its
|
|
196
|
+
* branch was removed from the definition. Removes the conventional filter indexes first, since
|
|
197
|
+
* SQLite refuses to drop an indexed column.
|
|
198
|
+
*
|
|
199
|
+
* @param seed The seed definition (the column must not belong to it).
|
|
200
|
+
* @param column The orphan column name.
|
|
201
|
+
* @param inDraftTable Whether the draft table also holds the column.
|
|
202
|
+
* @returns An array of SQL statements.
|
|
203
|
+
*/
|
|
204
|
+
export declare function generateDropOrphanColumn(seed: Seed, column: string, inDraftTable: boolean): string[];
|
|
187
205
|
/**
|
|
188
206
|
* Returns the `RENAME COLUMN` SQL statements for renaming a field's alias.
|
|
189
207
|
* For a multi-relation branch, renames the junction table (+ drafts junction table) instead.
|
|
@@ -203,6 +221,19 @@ export declare function generateRenameColumn(seed: Seed, from: string, to: strin
|
|
|
203
221
|
* @returns An array of SQL statements.
|
|
204
222
|
*/
|
|
205
223
|
export declare function generateRetypeColumn(seed: Seed, branch: Branch): string[];
|
|
224
|
+
/**
|
|
225
|
+
* Returns `SELECT COUNT(*)` statements counting rows whose current value would be silently altered
|
|
226
|
+
* (zeroed or truncated) by the `CAST` in {@link generateRetypeColumn}. Empty when the target type
|
|
227
|
+
* is lossless for any input (`TEXT`).
|
|
228
|
+
*
|
|
229
|
+
* A text value is convertible only if it is a complete JSON number; `CAST` alone accepts trailing garbage.
|
|
230
|
+
*
|
|
231
|
+
* @param seed The seed definition.
|
|
232
|
+
* @param branch The target branch definition (carrying the new type).
|
|
233
|
+
* @throws {Error} If called on a multi-relation branch.
|
|
234
|
+
* @returns An array of SQL statements, each yielding a single `count` column.
|
|
235
|
+
*/
|
|
236
|
+
export declare function generateRetypeIncompatibleCount(seed: Seed, branch: Branch): string[];
|
|
206
237
|
/**
|
|
207
238
|
* Additive statements that turn soft delete on for a table that already exists.
|
|
208
239
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/ddl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EACJ,MAAM,EAOP,MAAM,aAAa,CAAC;AAIrB;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGrD;AA6BD;;GAEG;AACH,eAAO,MAAM,cAAc,aAA8E,CAAA;AAGzG;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE5C;
|
|
1
|
+
{"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/ddl.ts"],"names":[],"mappings":"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"}
|
package/dist/engine/ddl/ddl.js
CHANGED
|
@@ -41,7 +41,7 @@ export function tableName(seed) {
|
|
|
41
41
|
* @param seed The seed definition.
|
|
42
42
|
* @returns The draft table name.
|
|
43
43
|
*/
|
|
44
|
-
function draftTableName(seed) {
|
|
44
|
+
export function draftTableName(seed) {
|
|
45
45
|
return `content_${seed.slug}_drafts`;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
@@ -221,6 +221,37 @@ export function generateAddColumn(seed, branch) {
|
|
|
221
221
|
export function generateAddDraftSnapshotColumn(seed) {
|
|
222
222
|
return `ALTER TABLE content_${seed.slug}_drafts ADD COLUMN live_snapshot_at INTEGER;`;
|
|
223
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Lists the indexes a branch column carries (value index + blind index), as name/column pairs.
|
|
226
|
+
* Single source for both index creation and column teardown.
|
|
227
|
+
*/
|
|
228
|
+
function branchIndexes(seed, branch) {
|
|
229
|
+
if (branch.type === 'relation' && branch.multiple === true)
|
|
230
|
+
return [];
|
|
231
|
+
const isRelation = branch.type === 'relation';
|
|
232
|
+
if (!isRelation && !resolvePolicies(branch).filter)
|
|
233
|
+
return [];
|
|
234
|
+
const indexes = [];
|
|
235
|
+
if (['text', 'number', 'date', 'boolean', 'relation'].includes(branch.type)) {
|
|
236
|
+
indexes.push({ name: `idx_${seed.slug}_${branch.alias}`, column: branch.alias });
|
|
237
|
+
}
|
|
238
|
+
if (hasBlindIndex(branch)) {
|
|
239
|
+
indexes.push({ name: `idx_${seed.slug}_${branch.alias}_bidx`, column: `${branch.alias}_bidx` });
|
|
240
|
+
}
|
|
241
|
+
return indexes;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Statements that detach a column from everything SQLite refuses to drop it from:
|
|
245
|
+
* its indexes and, for searchable branches, the FTS table + triggers (rebuilt by `planFtsRebuild`).
|
|
246
|
+
*/
|
|
247
|
+
function generateColumnTeardown(seed, branch) {
|
|
248
|
+
const slug = seed.slug;
|
|
249
|
+
const stmts = branchIndexes(seed, branch).map(i => `DROP INDEX IF EXISTS ${i.name};`);
|
|
250
|
+
if (indexableSearchBranches(seed).some(b => b.alias === branch.alias)) {
|
|
251
|
+
stmts.push(`DROP TRIGGER IF EXISTS fts_${slug}_insert;`, `DROP TRIGGER IF EXISTS fts_${slug}_update;`, `DROP TRIGGER IF EXISTS fts_${slug}_delete;`, `DROP TABLE IF EXISTS ${ftsTableName(seed)};`);
|
|
252
|
+
}
|
|
253
|
+
return stmts;
|
|
254
|
+
}
|
|
224
255
|
/**
|
|
225
256
|
* Generates SQL index statements for system fields (status, created_at)
|
|
226
257
|
* and indexable branch columns.
|
|
@@ -236,16 +267,8 @@ export function generateIndexes(seed) {
|
|
|
236
267
|
`CREATE INDEX IF NOT EXISTS idx_${slug}_created_at ON ${table}(created_at);`,
|
|
237
268
|
];
|
|
238
269
|
for (const branch of seed.branches) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const isRelation = branch.type === 'relation';
|
|
242
|
-
if (!isRelation && !resolvePolicies(branch).filter)
|
|
243
|
-
continue;
|
|
244
|
-
if (['text', 'number', 'date', 'boolean', 'relation'].includes(branch.type)) {
|
|
245
|
-
indexes.push(`CREATE INDEX IF NOT EXISTS idx_${slug}_${branch.alias} ON ${table}(${branch.alias});`);
|
|
246
|
-
}
|
|
247
|
-
if (hasBlindIndex(branch)) {
|
|
248
|
-
indexes.push(`CREATE INDEX IF NOT EXISTS idx_${slug}_${branch.alias}_bidx ON ${table}(${branch.alias}_bidx);`);
|
|
270
|
+
for (const { name, column } of branchIndexes(seed, branch)) {
|
|
271
|
+
indexes.push(`CREATE INDEX IF NOT EXISTS ${name} ON ${table}(${column});`);
|
|
249
272
|
}
|
|
250
273
|
}
|
|
251
274
|
if (seed.softDelete) {
|
|
@@ -494,12 +517,33 @@ export function generateDropColumn(seed, alias) {
|
|
|
494
517
|
`DROP TABLE IF EXISTS ${jt};`,
|
|
495
518
|
];
|
|
496
519
|
}
|
|
497
|
-
const stmts =
|
|
520
|
+
const stmts = branch ? generateColumnTeardown(seed, branch) : [];
|
|
521
|
+
stmts.push(`ALTER TABLE ${tableName(seed)} DROP COLUMN ${alias};`);
|
|
498
522
|
if (branch && seed.allowDrafts) {
|
|
499
523
|
stmts.push(`ALTER TABLE ${draftTableName(seed)} DROP COLUMN ${alias};`);
|
|
500
524
|
}
|
|
501
525
|
return stmts;
|
|
502
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* Returns the SQL statements that drop an orphan column: one left in the physical table after its
|
|
529
|
+
* branch was removed from the definition. Removes the conventional filter indexes first, since
|
|
530
|
+
* SQLite refuses to drop an indexed column.
|
|
531
|
+
*
|
|
532
|
+
* @param seed The seed definition (the column must not belong to it).
|
|
533
|
+
* @param column The orphan column name.
|
|
534
|
+
* @param inDraftTable Whether the draft table also holds the column.
|
|
535
|
+
* @returns An array of SQL statements.
|
|
536
|
+
*/
|
|
537
|
+
export function generateDropOrphanColumn(seed, column, inDraftTable) {
|
|
538
|
+
const stmts = [
|
|
539
|
+
`DROP INDEX IF EXISTS idx_${seed.slug}_${column};`,
|
|
540
|
+
`DROP INDEX IF EXISTS idx_${seed.slug}_${column}_bidx;`,
|
|
541
|
+
`ALTER TABLE ${tableName(seed)} DROP COLUMN ${column};`,
|
|
542
|
+
];
|
|
543
|
+
if (inDraftTable)
|
|
544
|
+
stmts.push(`ALTER TABLE ${draftTableName(seed)} DROP COLUMN ${column};`);
|
|
545
|
+
return stmts;
|
|
546
|
+
}
|
|
503
547
|
/**
|
|
504
548
|
* Returns the `RENAME COLUMN` SQL statements for renaming a field's alias.
|
|
505
549
|
* For a multi-relation branch, renames the junction table (+ drafts junction table) instead.
|
|
@@ -547,9 +591,44 @@ export function generateRetypeColumn(seed, branch) {
|
|
|
547
591
|
`ALTER TABLE ${table} DROP COLUMN ${alias};`,
|
|
548
592
|
`ALTER TABLE ${table} RENAME COLUMN ${tmp} TO ${alias};`,
|
|
549
593
|
];
|
|
550
|
-
const
|
|
594
|
+
const current = seed.branches.find(b => b.alias === alias);
|
|
595
|
+
const stmts = current ? generateColumnTeardown(seed, current) : [];
|
|
596
|
+
stmts.push(...rebuild(tableName(seed)));
|
|
551
597
|
if (seed.allowDrafts)
|
|
552
598
|
stmts.push(...rebuild(draftTableName(seed)));
|
|
599
|
+
for (const { name, column } of branchIndexes(seed, branch)) {
|
|
600
|
+
stmts.push(`CREATE INDEX IF NOT EXISTS ${name} ON ${tableName(seed)}(${column});`);
|
|
601
|
+
}
|
|
602
|
+
return stmts;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Returns `SELECT COUNT(*)` statements counting rows whose current value would be silently altered
|
|
606
|
+
* (zeroed or truncated) by the `CAST` in {@link generateRetypeColumn}. Empty when the target type
|
|
607
|
+
* is lossless for any input (`TEXT`).
|
|
608
|
+
*
|
|
609
|
+
* A text value is convertible only if it is a complete JSON number; `CAST` alone accepts trailing garbage.
|
|
610
|
+
*
|
|
611
|
+
* @param seed The seed definition.
|
|
612
|
+
* @param branch The target branch definition (carrying the new type).
|
|
613
|
+
* @throws {Error} If called on a multi-relation branch.
|
|
614
|
+
* @returns An array of SQL statements, each yielding a single `count` column.
|
|
615
|
+
*/
|
|
616
|
+
export function generateRetypeIncompatibleCount(seed, branch) {
|
|
617
|
+
if (branch.type === 'relation' && branch.multiple === true) {
|
|
618
|
+
throw new Error(`Branch "${branch.alias}" is a multi-relation and has no column to retype`);
|
|
619
|
+
}
|
|
620
|
+
const { sqlType } = BRANCH_TYPE_SQL[branch.type];
|
|
621
|
+
if (sqlType === 'TEXT')
|
|
622
|
+
return [];
|
|
623
|
+
const col = branch.alias;
|
|
624
|
+
const jsonNumber = (types) => `(typeof(${col}) = 'text' AND CASE WHEN json_valid(${col}) THEN json_type(${col}) IN (${types}) ELSE 0 END)`;
|
|
625
|
+
const convertible = sqlType === 'REAL'
|
|
626
|
+
? `typeof(${col}) IN ('integer', 'real') OR ${jsonNumber("'integer', 'real'")}`
|
|
627
|
+
: `typeof(${col}) = 'integer' OR (typeof(${col}) = 'real' AND ${col} = CAST(${col} AS INTEGER)) OR ${jsonNumber("'integer'")}`;
|
|
628
|
+
const count = (table) => `SELECT COUNT(*) AS count FROM ${table} WHERE ${col} IS NOT NULL AND NOT (${convertible});`;
|
|
629
|
+
const stmts = [count(tableName(seed))];
|
|
630
|
+
if (seed.allowDrafts)
|
|
631
|
+
stmts.push(count(draftTableName(seed)));
|
|
553
632
|
return stmts;
|
|
554
633
|
}
|
|
555
634
|
/**
|
|
@@ -18,6 +18,9 @@ export interface ISchemaMutator {
|
|
|
18
18
|
* type-change column rebuild, full type drop). The caller assembles the
|
|
19
19
|
* statements; the impl validates identifiers and runs them as one D1 batch. */
|
|
20
20
|
execDestructive(statements: string[]): Promise<void>;
|
|
21
|
+
/** Runs read-only `SELECT COUNT(*) AS count` statements as one batch and returns the summed count.
|
|
22
|
+
* Used to pre-check data compatibility before a lossy destructive operation. */
|
|
23
|
+
sumCounts(statements: string[]): Promise<number>;
|
|
21
24
|
/** Reads all rows from a table for the specified columns only.
|
|
22
25
|
* Used before DROP TABLE to collect R2 keys for media cleanup.
|
|
23
26
|
* All identifiers are validated against `^[A-Za-z0-9_]+$`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-mutator.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/schema-mutator.ts"],"names":[],"mappings":"AAGA;;yFAEyF;AACzF,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;IACtD;;8EAE0E;IAC1E,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAS5C,sCAAsC;IACtC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,kDAAkD;IAClD,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxD,0DAA0D;IAC1D,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpE;;oFAEgF;IAChF,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEpD;;mEAE+D;IAC/D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;CAChF"}
|
|
1
|
+
{"version":3,"file":"schema-mutator.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/schema-mutator.ts"],"names":[],"mappings":"AAGA;;yFAEyF;AACzF,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;IACtD;;8EAE0E;IAC1E,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAS5C,sCAAsC;IACtC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,kDAAkD;IAClD,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxD,0DAA0D;IAC1D,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpE;;oFAEgF;IAChF,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEpD;qFACiF;IACjF,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAEhD;;mEAE+D;IAC/D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;CAChF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Seed } from '../types.js';
|
|
2
|
+
/** Blocks writes from requests that loaded a seed immediately before its purge began. */
|
|
3
|
+
export declare function generateSeedPurgeGuards(seed: Seed): {
|
|
4
|
+
create: string[];
|
|
5
|
+
drop: string[];
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=seed-purge-guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-purge-guards.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/seed-purge-guards.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,yFAAyF;AACzF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAcxF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
/** Blocks writes from requests that loaded a seed immediately before its purge began. */
|
|
4
|
+
export function generateSeedPurgeGuards(seed) {
|
|
5
|
+
if (!/^[a-z0-9_]+$/.test(seed.slug))
|
|
6
|
+
throw new Error(`Unsafe seed slug: ${seed.slug}`);
|
|
7
|
+
const tables = [`content_${seed.slug}`, ...(seed.allowDrafts ? [`content_${seed.slug}_drafts`] : [])];
|
|
8
|
+
const operations = ['INSERT', 'UPDATE', 'DELETE'];
|
|
9
|
+
const create = [];
|
|
10
|
+
const drop = [];
|
|
11
|
+
for (const table of tables) {
|
|
12
|
+
for (const operation of operations) {
|
|
13
|
+
const name = `purge_guard_${table}_${operation.toLowerCase()}`;
|
|
14
|
+
create.push(`CREATE TRIGGER ${name} BEFORE ${operation} ON ${table} BEGIN SELECT RAISE(ABORT, 'seed_purge_in_progress'); END;`);
|
|
15
|
+
drop.push(`DROP TRIGGER IF EXISTS ${name};`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { create, drop };
|
|
19
|
+
}
|
package/dist/engine/engine.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export * from './ddl.js';
|
|
2
|
-
export * from './query.js';
|
|
3
|
-
export * from './serialize.js';
|
|
1
|
+
export * from './ddl/ddl.js';
|
|
2
|
+
export * from './query/query.js';
|
|
3
|
+
export * from './query/serialize.js';
|
|
4
|
+
export * from './query/active-clause.js';
|
|
4
5
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"AACA,cAAc,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA"}
|
package/dist/engine/engine.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
export * from './ddl.js';
|
|
3
|
-
export * from './query.js';
|
|
4
|
-
export * from './serialize.js';
|
|
2
|
+
export * from './ddl/ddl.js';
|
|
3
|
+
export * from './query/query.js';
|
|
4
|
+
export * from './query/serialize.js';
|
|
5
|
+
export * from './query/active-clause.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module engine/relation-audit
|
|
3
|
+
* Finds relation branches whose physical storage no longer matches the deployed definition.
|
|
4
|
+
*
|
|
5
|
+
* Releases before the additive relation gate could persist a changed `multiple`, `targetSeed` or
|
|
6
|
+
* `onDelete` without migrating the FK column, the `rel_<slug>_<alias>` junction table or the FK
|
|
7
|
+
* policy. The gate prevents new mismatches; this audit identifies databases that already have one.
|
|
8
|
+
*
|
|
9
|
+
* Read-only by contract: only `PRAGMA` and `SELECT COUNT(*)` statements are issued, through the
|
|
10
|
+
* injected executor. Nothing is repaired and no row is ever touched.
|
|
11
|
+
*/
|
|
12
|
+
import type { Seed } from '../types.js';
|
|
13
|
+
import { type SchemaQueryExecutor } from './introspection.js';
|
|
14
|
+
/** What is wrong with the storage of one relation branch. */
|
|
15
|
+
export type RelationStorageIssue =
|
|
16
|
+
/** Definition says single (or multiple) but the data lives in the other shape. */
|
|
17
|
+
'wrong_storage'
|
|
18
|
+
/** Neither the FK column nor the junction table exists. */
|
|
19
|
+
| 'missing_storage'
|
|
20
|
+
/** The FK points at a different table than `targetSeed`. */
|
|
21
|
+
| 'fk_target_mismatch'
|
|
22
|
+
/** The FK `ON DELETE` rule differs from the effective `onDelete`. */
|
|
23
|
+
| 'fk_on_delete_mismatch';
|
|
24
|
+
export interface RelationStorageFinding {
|
|
25
|
+
seed: string;
|
|
26
|
+
alias: string;
|
|
27
|
+
issue: RelationStorageIssue;
|
|
28
|
+
/** What the deployed definition requires, e.g. `junction rel_posts_tags`. */
|
|
29
|
+
expected: string;
|
|
30
|
+
/** What the database holds. */
|
|
31
|
+
actual: string;
|
|
32
|
+
/**
|
|
33
|
+
* Rows or values sitting in storage the definition no longer points at. Always 0 for
|
|
34
|
+
* `missing_storage` and the FK findings: those carry no stranded values by themselves.
|
|
35
|
+
*/
|
|
36
|
+
strandedRows: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Compares every relation branch of the given (active) seeds against the physical tables.
|
|
40
|
+
*
|
|
41
|
+
* Seeds whose `content_<slug>` table is missing are skipped: that is plain schema drift and is
|
|
42
|
+
* reported by the schema diff, not a relation-storage mismatch. Findings are ordered by seed, then
|
|
43
|
+
* branch order, so the report is deterministic.
|
|
44
|
+
*/
|
|
45
|
+
export declare function auditRelationStorage(executor: SchemaQueryExecutor, seeds: Seed[]): Promise<RelationStorageFinding[]>;
|
|
46
|
+
//# sourceMappingURL=relation-audit.d.ts.map
|