@cosmicdrift/kumiko-bundled-features 0.373.0 → 0.377.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account-security/constants.d.ts +1 -0
- package/dist/account-security/constants.js +1 -0
- package/dist/account-security/index.d.ts +1 -1
- package/dist/account-security/index.js +1 -1
- package/dist/admin-shell/web/client-plugin.d.ts +1 -1
- package/dist/audit/web/client-plugin.d.ts +1 -1
- package/dist/auth-email-password/i18n.js +1 -0
- package/dist/auth-email-password/mail-notifications.js +1 -1
- package/dist/auth-email-password/web/auth-client.js +1 -1
- package/dist/auth-email-password/web/auth-form-primitives.js +1 -1
- package/dist/auth-email-password/web/client-actions.d.ts +2 -0
- package/dist/auth-email-password/web/client-actions.js +23 -0
- package/dist/auth-email-password/web/client-plugin.d.ts +2 -1
- package/dist/auth-email-password/web/client-plugin.js +2 -0
- package/dist/auth-email-password/web/default-topbar-actions.js +1 -1
- package/dist/auth-email-password/web/index.js +1 -1
- package/dist/auth-email-password/web/session.js +1 -1
- package/dist/auth-email-password/web/tenant-menu-items.js +1 -1
- package/dist/auth-email-password/web/tenant-switcher.js +1 -1
- package/dist/auth-email-password/web/user-menu.js +1 -1
- package/dist/auth-foundation/env.d.ts +9 -0
- package/dist/auth-foundation/env.js +21 -0
- package/dist/auth-foundation/index.d.ts +1 -0
- package/dist/auth-foundation/index.js +1 -0
- package/dist/auth-mfa/schema/user-mfa.d.ts +6 -6
- package/dist/billing-foundation/consumer-protection/confirmation-mail.js +1 -1
- package/dist/billing-foundation/consumer-protection/termination-pages.js +1 -1
- package/dist/billing-foundation/contact-card.d.ts +2 -0
- package/dist/billing-foundation/contact-card.js +16 -0
- package/dist/billing-foundation/entities.d.ts +8 -8
- package/dist/billing-foundation/handlers/billing-plans.query.js +1 -1
- package/dist/billing-foundation/index.d.ts +1 -1
- package/dist/billing-foundation/plan-catalog.js +1 -0
- package/dist/billing-foundation/projection.d.ts +8 -8
- package/dist/billing-foundation/types.d.ts +11 -0
- package/dist/billing-foundation/validate-options.js +13 -0
- package/dist/billing-foundation/web/billing-contact-plan.d.ts +5 -0
- package/dist/billing-foundation/web/billing-contact-plan.js +17 -0
- package/dist/billing-foundation/web/billing-plans-panel.js +5 -13
- package/dist/billing-foundation/web/cancel-contract-dialog.js +2 -2
- package/dist/billing-foundation/web/checkout-consent-dialog.d.ts +1 -1
- package/dist/billing-foundation/web/checkout-consent-dialog.js +1 -0
- package/dist/billing-foundation/web/client-plugin.d.ts +1 -1
- package/dist/billing-foundation/web/localized-params.d.ts +1 -0
- package/dist/billing-foundation/web/localized-params.js +11 -0
- package/dist/cap-counter/entity.d.ts +1 -1
- package/dist/cap-overview/handlers/tenant-caps-list.query.d.ts +9 -4
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +14 -61
- package/dist/cap-overview/i18n.js +0 -2
- package/dist/cap-overview/web/cap-cards-panel.js +3 -3
- package/dist/cap-overview/web/client-plugin.d.ts +1 -1
- package/dist/channel-email/email-channel.d.ts +2 -1
- package/dist/compliance-profiles/web/client-plugin.d.ts +1 -1
- package/dist/config/feature.js +2 -2
- package/dist/config/table.d.ts +6 -6
- package/dist/custom-fields/entity.d.ts +4 -4
- package/dist/custom-fields/web/client-plugin.d.ts +1 -1
- package/dist/data-retention/schema/tenant-retention-override.d.ts +4 -4
- package/dist/delivery/tables.d.ts +6 -6
- package/dist/delivery/unsubscribe-page.js +1 -1
- package/dist/delivery/web/client-plugin.d.ts +1 -1
- package/dist/delivery/web/delivery-status-cell.js +1 -1
- package/dist/document-ingest-foundation/entity.d.ts +4 -4
- package/dist/feature-toggles/web/client-plugin.d.ts +1 -1
- package/dist/file-provider-s3/env-named-feature.d.ts +17 -0
- package/dist/file-provider-s3/env-named-feature.js +23 -0
- package/dist/file-provider-s3/env-schema.d.ts +7 -0
- package/dist/file-provider-s3/env-schema.js +15 -10
- package/dist/file-provider-s3/index.d.ts +1 -0
- package/dist/file-provider-s3/index.js +1 -0
- package/dist/folders/entity.d.ts +8 -8
- package/dist/folders/web/client-plugin.d.ts +1 -1
- package/dist/form-draft/entity.d.ts +2 -2
- package/dist/host-routing/constants.d.ts +2 -0
- package/dist/host-routing/constants.js +3 -0
- package/dist/host-routing/dispatch.d.ts +1 -1
- package/dist/host-routing/dispatch.js +35 -25
- package/dist/host-routing/feature.js +100 -27
- package/dist/host-routing/host.d.ts +9 -0
- package/dist/host-routing/host.js +24 -2
- package/dist/host-routing/index.d.ts +2 -1
- package/dist/host-routing/index.js +1 -0
- package/dist/host-routing/options.d.ts +14 -0
- package/dist/host-routing/redirects.d.ts +6 -0
- package/dist/host-routing/redirects.js +27 -0
- package/dist/host-routing/tenant-lookup.d.ts +7 -0
- package/dist/host-routing/tenant-lookup.js +39 -0
- package/dist/host-routing/validate-options.js +34 -1
- package/dist/inbound-mail-foundation/entities.d.ts +25 -25
- package/dist/inbound-mail-foundation/feature.js +7 -0
- package/dist/inbound-mail-foundation/i18n.d.ts +3 -0
- package/dist/inbound-mail-foundation/i18n.js +35 -0
- package/dist/inbound-mail-foundation/index.d.ts +1 -0
- package/dist/inbound-mail-foundation/index.js +1 -0
- package/dist/inbound-mail-foundation/projection.d.ts +20 -20
- package/dist/inbound-mail-foundation/screens.d.ts +7 -0
- package/dist/inbound-mail-foundation/screens.js +86 -0
- package/dist/inbound-mail-foundation/types.d.ts +2 -2
- package/dist/jobs/job-run-table.d.ts +6 -6
- package/dist/jobs/web/client-plugin.d.ts +1 -1
- package/dist/ledger/entity.d.ts +13 -13
- package/dist/legal-pages/feature.js +11 -1
- package/dist/legal-pages/layout.d.ts +2 -2
- package/dist/legal-pages/layout.js +4 -4
- package/dist/legal-pages/web/client-plugin.d.ts +1 -1
- package/dist/mail-foundation/feature.d.ts +20 -21
- package/dist/mail-foundation/feature.js +1 -1
- package/dist/managed-pages/table.d.ts +12 -12
- package/dist/managed-pages/web/client-plugin.d.ts +1 -1
- package/dist/notes-history/entity.d.ts +12 -12
- package/dist/notes-history/web/client-plugin.d.ts +1 -1
- package/dist/page-render/branding.js +1 -1
- package/dist/page-render/layout.d.ts +1 -1
- package/dist/page-render/layout.js +2 -2
- package/dist/page-render/markdown.js +1 -1
- package/dist/personal-access-tokens/i18n.js +1 -1
- package/dist/personal-access-tokens/schema/api-token.d.ts +6 -6
- package/dist/personal-access-tokens/screens.js +1 -1
- package/dist/secrets/feature.d.ts +1 -1
- package/dist/secrets/feature.js +3 -3
- package/dist/secrets/table.d.ts +1 -1
- package/dist/seo/sitemap.js +1 -1
- package/dist/sessions/schema/user-session.d.ts +4 -4
- package/dist/shared/mail-template-body.js +1 -1
- package/dist/shared/purge-files-reaching-subject.js +98 -3
- package/dist/tags/entity.d.ts +9 -9
- package/dist/tags/web/client-plugin.d.ts +1 -1
- package/dist/template-resolver/document-blocks.d.ts +5 -0
- package/dist/template-resolver/document-blocks.js +21 -0
- package/dist/template-resolver/document-ops.d.ts +167 -0
- package/dist/template-resolver/document-ops.js +390 -0
- package/dist/template-resolver/document-sanitizer.d.ts +3 -0
- package/dist/template-resolver/document-sanitizer.js +6 -0
- package/dist/template-resolver/feature.d.ts +2 -0
- package/dist/template-resolver/feature.js +4 -0
- package/dist/template-resolver/handlers/bundle-import.js +1 -0
- package/dist/template-resolver/handlers/document-base.d.ts +23 -0
- package/dist/template-resolver/handlers/document-base.js +55 -0
- package/dist/template-resolver/handlers/document-blocks.query.d.ts +22 -0
- package/dist/template-resolver/handlers/document-blocks.query.js +46 -0
- package/dist/template-resolver/handlers/export-bundle.query.d.ts +1 -0
- package/dist/template-resolver/handlers/export-bundle.query.js +9 -2
- package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +1 -0
- package/dist/template-resolver/handlers/import-bundle.write.d.ts +1 -0
- package/dist/template-resolver/handlers/patch-draft.write.d.ts +66 -0
- package/dist/template-resolver/handlers/patch-draft.write.js +105 -0
- package/dist/template-resolver/handlers/preview.query.d.ts +1 -0
- package/dist/template-resolver/handlers/preview.query.js +2 -1
- package/dist/template-resolver/handlers/send-test.write.d.ts +1 -0
- package/dist/template-resolver/handlers/send-test.write.js +2 -1
- package/dist/template-resolver/handlers/template-write.d.ts +2 -0
- package/dist/template-resolver/handlers/template-write.js +14 -2
- package/dist/template-resolver/handlers/validate.query.d.ts +10 -4
- package/dist/template-resolver/handlers/validate.query.js +12 -7
- package/dist/template-resolver/{web/placeholder-text.js → placeholder-text.js} +1 -1
- package/dist/template-resolver/qualified-names.d.ts +2 -0
- package/dist/template-resolver/qualified-names.js +2 -0
- package/dist/template-resolver/seeding.d.ts +1 -0
- package/dist/template-resolver/seeding.js +2 -1
- package/dist/template-resolver/table.d.ts +10 -10
- package/dist/template-resolver/template-bundle.d.ts +1 -0
- package/dist/template-resolver/template-bundle.js +6 -1
- package/dist/template-resolver/template-preview.d.ts +4 -1
- package/dist/template-resolver/template-preview.js +16 -3
- package/dist/template-resolver/template-validation.d.ts +2 -1
- package/dist/template-resolver/template-validation.js +1 -1
- package/dist/template-resolver/user-content-table.d.ts +10 -10
- package/dist/template-resolver/web/client-plugin.d.ts +1 -1
- package/dist/template-resolver/web/client-plugin.js +3 -3
- package/dist/template-resolver/web/document-tiptap-editor.js +1 -1
- package/dist/template-resolver/web/document-toolbar-blocks.d.ts +2 -5
- package/dist/template-resolver/web/document-toolbar-blocks.js +1 -21
- package/dist/template-resolver/web/i18n.js +14 -0
- package/dist/template-resolver/web/placeholder-line-editor.js +2 -2
- package/dist/tenant/invitation-table.d.ts +6 -6
- package/dist/tenant/membership-table.d.ts +4 -4
- package/dist/tenant/schema/tenant.d.ts +6 -6
- package/dist/tenant/web/client-plugin.d.ts +1 -1
- package/dist/tenant/web/member-status-cell.js +1 -1
- package/dist/tier-engine/entity.d.ts +1 -1
- package/dist/tier-engine/tier-resolver.d.ts +1 -1
- package/dist/tier-engine/web/client-plugin.d.ts +1 -1
- package/dist/user/schema/user.d.ts +12 -12
- package/dist/user-data-rights/env.d.ts +5 -0
- package/dist/user-data-rights/env.js +11 -0
- package/dist/user-data-rights/feature.js +4 -2
- package/dist/user-data-rights/index.d.ts +1 -0
- package/dist/user-data-rights/index.js +1 -0
- package/dist/user-data-rights/lib/mail-transport-resolver.js +1 -1
- package/dist/user-data-rights/lib/storage-provider-resolver.js +1 -1
- package/dist/user-data-rights/mail-notifications.js +1 -1
- package/dist/user-data-rights/schema/download-attempt.d.ts +14 -14
- package/dist/user-data-rights/schema/download-token.d.ts +8 -8
- package/dist/user-data-rights/schema/export-job.d.ts +6 -6
- package/dist/user-data-rights/web/client-plugin.d.ts +1 -1
- package/dist/user-data-rights/web/privacy-center-screen.js +2 -2
- package/dist/waitlist/entity.d.ts +14 -14
- package/dist/waitlist/legacy-migrate.d.ts +2 -0
- package/dist/waitlist/legacy-migrate.js +38 -3
- package/package.json +16 -11
- package/src/account-security/changes.json +6 -0
- package/src/auth-email-password/changes.json +6 -0
- package/src/auth-foundation/changes.json +6 -0
- package/src/billing-foundation/changes.json +6 -0
- package/src/cap-overview/changes.json +7 -0
- package/src/channel-email/changes.json +6 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/file-provider-s3/changes.json +6 -0
- package/src/host-routing/changes.json +6 -0
- package/src/inbound-mail-foundation/changes.json +7 -0
- package/src/legal-pages/changes.json +6 -0
- package/src/template-resolver/changes.json +18 -0
- package/src/user-data-rights/changes.json +6 -0
- package/src/waitlist/changes.json +6 -0
- /package/dist/template-resolver/{web/placeholder-text.d.ts → placeholder-text.d.ts} +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { FieldIssue } from "@cosmicdrift/kumiko-framework/errors";
|
|
2
|
+
import { type JSONContent } from "@tiptap/core";
|
|
3
|
+
import * as z from "zod";
|
|
4
|
+
import type { DocumentHtmlKind } from "./constants.ts";
|
|
5
|
+
export declare const MAX_DOCUMENT_OPS = 50;
|
|
6
|
+
export type DocumentBlockType = "paragraph" | "heading" | "list" | "table" | "repeat" | "image" | "button" | "divider" | "pageBreak" | "steps";
|
|
7
|
+
export type DocumentBlock = {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly type: DocumentBlockType;
|
|
10
|
+
/** Inline content with `{{name}}` for placeholders; containers list one line per text block. */
|
|
11
|
+
readonly text?: string;
|
|
12
|
+
readonly level?: number;
|
|
13
|
+
readonly align?: string;
|
|
14
|
+
readonly showIf?: string;
|
|
15
|
+
readonly resource?: string;
|
|
16
|
+
readonly alt?: string;
|
|
17
|
+
readonly href?: string;
|
|
18
|
+
readonly each?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function documentBlockId(index: number): string;
|
|
21
|
+
export declare function documentBlocksOf(doc: JSONContent): DocumentBlock[];
|
|
22
|
+
declare const blockInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
23
|
+
type: z.ZodLiteral<"paragraph">;
|
|
24
|
+
text: z.ZodString;
|
|
25
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
26
|
+
center: "center";
|
|
27
|
+
justify: "justify";
|
|
28
|
+
left: "left";
|
|
29
|
+
right: "right";
|
|
30
|
+
}>>;
|
|
31
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
32
|
+
type: z.ZodLiteral<"heading">;
|
|
33
|
+
level: z.ZodNumber;
|
|
34
|
+
text: z.ZodString;
|
|
35
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
36
|
+
type: z.ZodLiteral<"image">;
|
|
37
|
+
resource: z.ZodString;
|
|
38
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
39
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
40
|
+
type: z.ZodLiteral<"button">;
|
|
41
|
+
text: z.ZodString;
|
|
42
|
+
href: z.ZodString;
|
|
43
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
44
|
+
type: z.ZodLiteral<"divider">;
|
|
45
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
46
|
+
type: z.ZodLiteral<"pageBreak">;
|
|
47
|
+
}, z.core.$strip>], "type">;
|
|
48
|
+
export type BlockInput = z.infer<typeof blockInputSchema>;
|
|
49
|
+
export declare const documentOpSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
50
|
+
op: z.ZodLiteral<"insertBlock">;
|
|
51
|
+
after: z.ZodNullable<z.ZodString>;
|
|
52
|
+
block: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
53
|
+
type: z.ZodLiteral<"paragraph">;
|
|
54
|
+
text: z.ZodString;
|
|
55
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
56
|
+
center: "center";
|
|
57
|
+
justify: "justify";
|
|
58
|
+
left: "left";
|
|
59
|
+
right: "right";
|
|
60
|
+
}>>;
|
|
61
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
62
|
+
type: z.ZodLiteral<"heading">;
|
|
63
|
+
level: z.ZodNumber;
|
|
64
|
+
text: z.ZodString;
|
|
65
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
66
|
+
type: z.ZodLiteral<"image">;
|
|
67
|
+
resource: z.ZodString;
|
|
68
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
69
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
70
|
+
type: z.ZodLiteral<"button">;
|
|
71
|
+
text: z.ZodString;
|
|
72
|
+
href: z.ZodString;
|
|
73
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
74
|
+
type: z.ZodLiteral<"divider">;
|
|
75
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
76
|
+
type: z.ZodLiteral<"pageBreak">;
|
|
77
|
+
}, z.core.$strip>], "type">;
|
|
78
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
79
|
+
op: z.ZodLiteral<"replaceText">;
|
|
80
|
+
blockId: z.ZodString;
|
|
81
|
+
find: z.ZodString;
|
|
82
|
+
replace: z.ZodString;
|
|
83
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
84
|
+
op: z.ZodLiteral<"removeBlock">;
|
|
85
|
+
blockId: z.ZodString;
|
|
86
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
87
|
+
op: z.ZodLiteral<"setResource">;
|
|
88
|
+
blockId: z.ZodString;
|
|
89
|
+
resource: z.ZodString;
|
|
90
|
+
alt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
91
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
92
|
+
op: z.ZodLiteral<"setMeta">;
|
|
93
|
+
meta: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
94
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
95
|
+
op: z.ZodLiteral<"setVariable">;
|
|
96
|
+
name: z.ZodString;
|
|
97
|
+
definition: z.ZodNullable<z.ZodUnknown>;
|
|
98
|
+
}, z.core.$strip>], "op">;
|
|
99
|
+
export declare const documentOpsSchema: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
100
|
+
op: z.ZodLiteral<"insertBlock">;
|
|
101
|
+
after: z.ZodNullable<z.ZodString>;
|
|
102
|
+
block: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
103
|
+
type: z.ZodLiteral<"paragraph">;
|
|
104
|
+
text: z.ZodString;
|
|
105
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
106
|
+
center: "center";
|
|
107
|
+
justify: "justify";
|
|
108
|
+
left: "left";
|
|
109
|
+
right: "right";
|
|
110
|
+
}>>;
|
|
111
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
112
|
+
type: z.ZodLiteral<"heading">;
|
|
113
|
+
level: z.ZodNumber;
|
|
114
|
+
text: z.ZodString;
|
|
115
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
116
|
+
type: z.ZodLiteral<"image">;
|
|
117
|
+
resource: z.ZodString;
|
|
118
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
120
|
+
type: z.ZodLiteral<"button">;
|
|
121
|
+
text: z.ZodString;
|
|
122
|
+
href: z.ZodString;
|
|
123
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
124
|
+
type: z.ZodLiteral<"divider">;
|
|
125
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
126
|
+
type: z.ZodLiteral<"pageBreak">;
|
|
127
|
+
}, z.core.$strip>], "type">;
|
|
128
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
129
|
+
op: z.ZodLiteral<"replaceText">;
|
|
130
|
+
blockId: z.ZodString;
|
|
131
|
+
find: z.ZodString;
|
|
132
|
+
replace: z.ZodString;
|
|
133
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
134
|
+
op: z.ZodLiteral<"removeBlock">;
|
|
135
|
+
blockId: z.ZodString;
|
|
136
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
137
|
+
op: z.ZodLiteral<"setResource">;
|
|
138
|
+
blockId: z.ZodString;
|
|
139
|
+
resource: z.ZodString;
|
|
140
|
+
alt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
141
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
142
|
+
op: z.ZodLiteral<"setMeta">;
|
|
143
|
+
meta: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
144
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
145
|
+
op: z.ZodLiteral<"setVariable">;
|
|
146
|
+
name: z.ZodString;
|
|
147
|
+
definition: z.ZodNullable<z.ZodUnknown>;
|
|
148
|
+
}, z.core.$strip>], "op">>;
|
|
149
|
+
export type DocumentOp = z.infer<typeof documentOpSchema>;
|
|
150
|
+
export type DocumentOpsInput = {
|
|
151
|
+
readonly doc: JSONContent;
|
|
152
|
+
readonly meta: Readonly<Record<string, unknown>>;
|
|
153
|
+
readonly variableSchema: Readonly<Record<string, unknown>>;
|
|
154
|
+
readonly kind: DocumentHtmlKind;
|
|
155
|
+
readonly ops: readonly DocumentOp[];
|
|
156
|
+
};
|
|
157
|
+
export type DocumentOpsResult = {
|
|
158
|
+
readonly ok: true;
|
|
159
|
+
readonly doc: JSONContent;
|
|
160
|
+
readonly meta: Record<string, unknown>;
|
|
161
|
+
readonly variableSchema: Record<string, unknown>;
|
|
162
|
+
} | {
|
|
163
|
+
readonly ok: false;
|
|
164
|
+
readonly issues: FieldIssue[];
|
|
165
|
+
};
|
|
166
|
+
export declare function applyDocumentOps(input: DocumentOpsInput): DocumentOpsResult;
|
|
167
|
+
export {};
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { getSchema } from "@tiptap/core";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { documentBlocksForKind } from "./document-blocks.js";
|
|
4
|
+
import { DOCUMENT_TEXT_ALIGNMENTS, documentExtensions, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
|
|
5
|
+
import { contentToLine, lineToContent, singleLine } from "./placeholder-text.js";
|
|
6
|
+
import { toVariableDef } from "./template-validation.js";
|
|
7
|
+
export const MAX_DOCUMENT_OPS = 50;
|
|
8
|
+
// Assigning these keys would reach the prototype of the meta object.
|
|
9
|
+
const FORBIDDEN_META_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
10
|
+
const TEXT_BLOCK_TYPES = new Set(["paragraph", "heading", "button"]);
|
|
11
|
+
function blockTypeOf(node) {
|
|
12
|
+
switch (node.type) {
|
|
13
|
+
case "paragraph":
|
|
14
|
+
case "heading":
|
|
15
|
+
case "button":
|
|
16
|
+
case "divider":
|
|
17
|
+
case "pageBreak":
|
|
18
|
+
case "steps":
|
|
19
|
+
return node.type;
|
|
20
|
+
case "bulletList":
|
|
21
|
+
case "orderedList":
|
|
22
|
+
return "list";
|
|
23
|
+
case "table":
|
|
24
|
+
return eachOf(node) === undefined ? "table" : "repeat";
|
|
25
|
+
case "resource":
|
|
26
|
+
return "image";
|
|
27
|
+
default:
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function stringAttr(node, name) {
|
|
32
|
+
const value = node.attrs?.[name];
|
|
33
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
34
|
+
}
|
|
35
|
+
function eachOf(table) {
|
|
36
|
+
for (const row of table.content ?? []) {
|
|
37
|
+
const each = stringAttr(row, "each");
|
|
38
|
+
if (each !== undefined)
|
|
39
|
+
return each;
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
function textLinesOf(node) {
|
|
44
|
+
if (TEXT_BLOCK_TYPES.has(node.type ?? ""))
|
|
45
|
+
return [contentToLine(node.content)];
|
|
46
|
+
return (node.content ?? []).flatMap(textLinesOf);
|
|
47
|
+
}
|
|
48
|
+
const NON_TEXT_BLOCK_TYPES = new Set([
|
|
49
|
+
"image",
|
|
50
|
+
"divider",
|
|
51
|
+
"pageBreak",
|
|
52
|
+
"steps",
|
|
53
|
+
]);
|
|
54
|
+
function setOptionalAttrs(block, node) {
|
|
55
|
+
const align = stringAttr(node, "textAlign");
|
|
56
|
+
if (align !== undefined)
|
|
57
|
+
block.align = align;
|
|
58
|
+
const showIf = stringAttr(node, "showIf");
|
|
59
|
+
if (showIf !== undefined)
|
|
60
|
+
block.showIf = showIf;
|
|
61
|
+
}
|
|
62
|
+
function setTypeSpecificAttrs(block, node) {
|
|
63
|
+
const level = node.attrs?.["level"];
|
|
64
|
+
if (block.type === "heading" && typeof level === "number")
|
|
65
|
+
block.level = level;
|
|
66
|
+
const resource = stringAttr(node, "resource");
|
|
67
|
+
if (block.type === "image" && resource !== undefined)
|
|
68
|
+
block.resource = resource;
|
|
69
|
+
const alt = stringAttr(node, "alt");
|
|
70
|
+
if (block.type === "image" && alt !== undefined)
|
|
71
|
+
block.alt = alt;
|
|
72
|
+
const href = stringAttr(node, "href");
|
|
73
|
+
if (block.type === "button" && href !== undefined)
|
|
74
|
+
block.href = href;
|
|
75
|
+
const each = eachOf(node);
|
|
76
|
+
if (block.type === "repeat" && each !== undefined)
|
|
77
|
+
block.each = each;
|
|
78
|
+
}
|
|
79
|
+
function blockOf(node, id) {
|
|
80
|
+
const type = blockTypeOf(node);
|
|
81
|
+
if (type === null)
|
|
82
|
+
return null;
|
|
83
|
+
const block = { id, type };
|
|
84
|
+
if (!NON_TEXT_BLOCK_TYPES.has(type))
|
|
85
|
+
block.text = textLinesOf(node).join("\n");
|
|
86
|
+
setOptionalAttrs(block, node);
|
|
87
|
+
setTypeSpecificAttrs(block, node);
|
|
88
|
+
return block;
|
|
89
|
+
}
|
|
90
|
+
export function documentBlockId(index) {
|
|
91
|
+
return `b${index}`;
|
|
92
|
+
}
|
|
93
|
+
export function documentBlocksOf(doc) {
|
|
94
|
+
return (doc.content ?? []).flatMap((node, index) => blockOf(node, documentBlockId(index)) ?? []);
|
|
95
|
+
}
|
|
96
|
+
const blockIdSchema = z.string().min(1).max(20);
|
|
97
|
+
const singleLineText = z.string().max(2000);
|
|
98
|
+
const blockInputSchema = z.discriminatedUnion("type", [
|
|
99
|
+
z.object({
|
|
100
|
+
type: z.literal("paragraph"),
|
|
101
|
+
text: singleLineText,
|
|
102
|
+
align: z.enum(DOCUMENT_TEXT_ALIGNMENTS).optional(),
|
|
103
|
+
}),
|
|
104
|
+
z.object({
|
|
105
|
+
type: z.literal("heading"),
|
|
106
|
+
level: z.number().int().min(1).max(3),
|
|
107
|
+
text: singleLineText,
|
|
108
|
+
}),
|
|
109
|
+
z.object({
|
|
110
|
+
type: z.literal("image"),
|
|
111
|
+
resource: z.string().min(1).max(200),
|
|
112
|
+
alt: z.string().max(500).optional(),
|
|
113
|
+
}),
|
|
114
|
+
z.object({ type: z.literal("button"), text: singleLineText, href: z.string().max(300) }),
|
|
115
|
+
z.object({ type: z.literal("divider") }),
|
|
116
|
+
z.object({ type: z.literal("pageBreak") }),
|
|
117
|
+
]);
|
|
118
|
+
export const documentOpSchema = z.discriminatedUnion("op", [
|
|
119
|
+
z.object({
|
|
120
|
+
op: z.literal("insertBlock"),
|
|
121
|
+
after: blockIdSchema.nullable(),
|
|
122
|
+
block: blockInputSchema,
|
|
123
|
+
}),
|
|
124
|
+
z.object({
|
|
125
|
+
op: z.literal("replaceText"),
|
|
126
|
+
blockId: blockIdSchema,
|
|
127
|
+
find: z.string().min(1).max(2000),
|
|
128
|
+
replace: z.string().max(2000),
|
|
129
|
+
}),
|
|
130
|
+
z.object({ op: z.literal("removeBlock"), blockId: blockIdSchema }),
|
|
131
|
+
z.object({
|
|
132
|
+
op: z.literal("setResource"),
|
|
133
|
+
blockId: blockIdSchema,
|
|
134
|
+
resource: z.string().min(1).max(200),
|
|
135
|
+
alt: z.string().max(500).nullable().optional(),
|
|
136
|
+
}),
|
|
137
|
+
z.object({ op: z.literal("setMeta"), meta: z.record(z.string(), z.unknown()) }),
|
|
138
|
+
z.object({
|
|
139
|
+
op: z.literal("setVariable"),
|
|
140
|
+
name: z.string().min(1).max(100),
|
|
141
|
+
definition: z.unknown().nullable(),
|
|
142
|
+
}),
|
|
143
|
+
]);
|
|
144
|
+
export const documentOpsSchema = z.array(documentOpSchema).min(1).max(MAX_DOCUMENT_OPS);
|
|
145
|
+
function patchIssue(path, code, params) {
|
|
146
|
+
const camel = code.replace(/_([a-z])/g, (_match, letter) => letter.toUpperCase());
|
|
147
|
+
return {
|
|
148
|
+
path,
|
|
149
|
+
code,
|
|
150
|
+
i18nKey: `templateResolver.errors.patch.${camel}`,
|
|
151
|
+
...(params === undefined ? {} : { params }),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function textNodesIn(nodes) {
|
|
155
|
+
return nodes.flatMap((node) => (node.type === "text" ? [node] : textNodesIn(node.content ?? [])));
|
|
156
|
+
}
|
|
157
|
+
function occurrencesOf(text, find) {
|
|
158
|
+
return text.split(find).length - 1;
|
|
159
|
+
}
|
|
160
|
+
function replacementNodes(textNode, find, replace) {
|
|
161
|
+
const text = textNode.text ?? "";
|
|
162
|
+
const at = text.indexOf(find);
|
|
163
|
+
const withMarks = (node) => node.type === "text" && textNode.marks !== undefined
|
|
164
|
+
? { ...node, marks: textNode.marks }
|
|
165
|
+
: node;
|
|
166
|
+
const before = text.slice(0, at);
|
|
167
|
+
const after = text.slice(at + find.length);
|
|
168
|
+
return [
|
|
169
|
+
...(before === "" ? [] : [{ ...textNode, text: before }]),
|
|
170
|
+
...lineToContent(singleLine(replace)).map(withMarks),
|
|
171
|
+
...(after === "" ? [] : [{ ...textNode, text: after }]),
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
function replaceInContent(content, find, replace) {
|
|
175
|
+
return content.flatMap((node) => {
|
|
176
|
+
if (node.type === "text") {
|
|
177
|
+
return (node.text ?? "").includes(find) ? replacementNodes(node, find, replace) : [node];
|
|
178
|
+
}
|
|
179
|
+
return [
|
|
180
|
+
node.content === undefined
|
|
181
|
+
? node
|
|
182
|
+
: { ...node, content: replaceInContent(node.content, find, replace) },
|
|
183
|
+
];
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function nodeOfInput(input) {
|
|
187
|
+
switch (input.type) {
|
|
188
|
+
case "paragraph":
|
|
189
|
+
return {
|
|
190
|
+
type: "paragraph",
|
|
191
|
+
...(input.align === undefined ? {} : { attrs: { textAlign: input.align } }),
|
|
192
|
+
content: lineToContent(singleLine(input.text)),
|
|
193
|
+
};
|
|
194
|
+
case "heading":
|
|
195
|
+
return {
|
|
196
|
+
type: "heading",
|
|
197
|
+
attrs: { level: input.level },
|
|
198
|
+
content: lineToContent(singleLine(input.text)),
|
|
199
|
+
};
|
|
200
|
+
case "image":
|
|
201
|
+
return { type: "resource", attrs: { resource: input.resource, alt: input.alt ?? null } };
|
|
202
|
+
case "button":
|
|
203
|
+
return {
|
|
204
|
+
type: "button",
|
|
205
|
+
attrs: { href: input.href },
|
|
206
|
+
content: lineToContent(singleLine(input.text)),
|
|
207
|
+
};
|
|
208
|
+
case "divider":
|
|
209
|
+
case "pageBreak":
|
|
210
|
+
return { type: input.type };
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const TOOLBAR_BLOCK_OF_INPUT = {
|
|
214
|
+
image: "image",
|
|
215
|
+
button: "button",
|
|
216
|
+
divider: "divider",
|
|
217
|
+
pageBreak: "pageBreak",
|
|
218
|
+
};
|
|
219
|
+
function isBlockAllowed(input, kind) {
|
|
220
|
+
if (input.type === "paragraph" || input.type === "heading")
|
|
221
|
+
return true;
|
|
222
|
+
return documentBlocksForKind(kind).includes(TOOLBAR_BLOCK_OF_INPUT[input.type]);
|
|
223
|
+
}
|
|
224
|
+
function inputIssue(input, path) {
|
|
225
|
+
if (input.type === "image" && !isDocumentResourceKey(input.resource)) {
|
|
226
|
+
return patchIssue(`${path}.block.resource`, "invalid_resource_key", {
|
|
227
|
+
resource: input.resource,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
if (input.type === "button" && !isDocumentPlaceholderHref(input.href)) {
|
|
231
|
+
return patchIssue(`${path}.block.href`, "invalid_button_href", { href: input.href });
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
let cachedSchema = null;
|
|
236
|
+
function documentSchema() {
|
|
237
|
+
cachedSchema ??= getSchema(documentExtensions);
|
|
238
|
+
return cachedSchema;
|
|
239
|
+
}
|
|
240
|
+
function isValidDocument(doc) {
|
|
241
|
+
try {
|
|
242
|
+
documentSchema().nodeFromJSON(doc).check();
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function lookupEntry(state, blockId, fieldPath) {
|
|
250
|
+
const entry = state.entries.get(blockId);
|
|
251
|
+
if (entry === undefined)
|
|
252
|
+
return { issue: patchIssue(fieldPath, "unknown_block", { blockId }) };
|
|
253
|
+
if (entry.removed)
|
|
254
|
+
return { issue: patchIssue(fieldPath, "block_removed", { blockId }) };
|
|
255
|
+
return { entry };
|
|
256
|
+
}
|
|
257
|
+
function blockInputIssue(op, path, kind) {
|
|
258
|
+
if (!isBlockAllowed(op.block, kind)) {
|
|
259
|
+
return patchIssue(`${path}.block.type`, "block_not_allowed", { type: op.block.type, kind });
|
|
260
|
+
}
|
|
261
|
+
if (op.block.type === "paragraph" &&
|
|
262
|
+
op.block.align !== undefined &&
|
|
263
|
+
!documentBlocksForKind(kind).includes("align")) {
|
|
264
|
+
return patchIssue(`${path}.block.align`, "block_not_allowed", { type: "align", kind });
|
|
265
|
+
}
|
|
266
|
+
return inputIssue(op.block, path);
|
|
267
|
+
}
|
|
268
|
+
function insertBlockOp(state, op, path) {
|
|
269
|
+
const anchor = op.after === null ? null : lookupEntry(state, op.after, `${path}.after`);
|
|
270
|
+
if (anchor !== null && "issue" in anchor)
|
|
271
|
+
return anchor.issue;
|
|
272
|
+
const invalid = blockInputIssue(op, path, state.kind);
|
|
273
|
+
if (invalid !== null)
|
|
274
|
+
return invalid;
|
|
275
|
+
const target = anchor === null ? state.insertedAtStart : anchor.entry.insertedAfter;
|
|
276
|
+
target.push(nodeOfInput(op.block));
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
function removeBlockOp(state, op, path) {
|
|
280
|
+
const found = lookupEntry(state, op.blockId, `${path}.blockId`);
|
|
281
|
+
if ("issue" in found)
|
|
282
|
+
return found.issue;
|
|
283
|
+
found.entry.removed = true;
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
function replaceTextOp(state, op, path) {
|
|
287
|
+
const found = lookupEntry(state, op.blockId, `${path}.blockId`);
|
|
288
|
+
if ("issue" in found)
|
|
289
|
+
return found.issue;
|
|
290
|
+
const { entry } = found;
|
|
291
|
+
const count = textNodesIn([entry.node]).reduce((sum, node) => sum + occurrencesOf(node.text ?? "", op.find), 0);
|
|
292
|
+
if (count === 0)
|
|
293
|
+
return patchIssue(`${path}.find`, "text_not_found", { find: op.find });
|
|
294
|
+
if (count > 1)
|
|
295
|
+
return patchIssue(`${path}.find`, "text_ambiguous", { find: op.find, count });
|
|
296
|
+
entry.node = replaceInContent([entry.node], op.find, op.replace)[0] ?? entry.node;
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
function setResourceOp(state, op, path) {
|
|
300
|
+
const found = lookupEntry(state, op.blockId, `${path}.blockId`);
|
|
301
|
+
if ("issue" in found)
|
|
302
|
+
return found.issue;
|
|
303
|
+
const { entry } = found;
|
|
304
|
+
if (entry.node.type !== "resource") {
|
|
305
|
+
return patchIssue(`${path}.blockId`, "block_type_mismatch", {
|
|
306
|
+
expected: "image",
|
|
307
|
+
actual: entry.node.type ?? "unknown",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (!isDocumentResourceKey(op.resource)) {
|
|
311
|
+
return patchIssue(`${path}.resource`, "invalid_resource_key", { resource: op.resource });
|
|
312
|
+
}
|
|
313
|
+
const alt = op.alt === undefined ? (entry.node.attrs?.["alt"] ?? null) : op.alt;
|
|
314
|
+
entry.node = { ...entry.node, attrs: { resource: op.resource, alt } };
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
function setMetaOp(state, op, path) {
|
|
318
|
+
const forbidden = Object.keys(op.meta).find((key) => FORBIDDEN_META_KEYS.has(key));
|
|
319
|
+
if (forbidden !== undefined) {
|
|
320
|
+
return patchIssue(`${path}.meta`, "invalid_meta_key", { key: forbidden });
|
|
321
|
+
}
|
|
322
|
+
for (const [key, value] of Object.entries(op.meta)) {
|
|
323
|
+
if (value === null)
|
|
324
|
+
delete state.meta[key];
|
|
325
|
+
else
|
|
326
|
+
state.meta[key] = value;
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
function setVariableOp(state, op, path) {
|
|
331
|
+
if (!isDocumentReferenceName(op.name)) {
|
|
332
|
+
return patchIssue(`${path}.name`, "invalid_variable_name", { name: op.name });
|
|
333
|
+
}
|
|
334
|
+
if (op.definition === null) {
|
|
335
|
+
delete state.variableSchema[op.name];
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
const definition = toVariableDef(op.definition);
|
|
339
|
+
if (definition === null) {
|
|
340
|
+
return patchIssue(`${path}.definition`, "invalid_variable_definition", { name: op.name });
|
|
341
|
+
}
|
|
342
|
+
state.variableSchema[op.name] = definition;
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
function applyOp(state, op, path) {
|
|
346
|
+
switch (op.op) {
|
|
347
|
+
case "insertBlock":
|
|
348
|
+
return insertBlockOp(state, op, path);
|
|
349
|
+
case "removeBlock":
|
|
350
|
+
return removeBlockOp(state, op, path);
|
|
351
|
+
case "replaceText":
|
|
352
|
+
return replaceTextOp(state, op, path);
|
|
353
|
+
case "setResource":
|
|
354
|
+
return setResourceOp(state, op, path);
|
|
355
|
+
case "setMeta":
|
|
356
|
+
return setMetaOp(state, op, path);
|
|
357
|
+
case "setVariable":
|
|
358
|
+
return setVariableOp(state, op, path);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// Ops address blocks by the ids of the document as it was read, so inserted blocks are
|
|
362
|
+
// collected per anchor and the list is assembled once at the end.
|
|
363
|
+
export function applyDocumentOps(input) {
|
|
364
|
+
const entries = new Map();
|
|
365
|
+
(input.doc.content ?? []).forEach((node, index) => {
|
|
366
|
+
entries.set(documentBlockId(index), {
|
|
367
|
+
node: structuredClone(node),
|
|
368
|
+
removed: false,
|
|
369
|
+
insertedAfter: [],
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
const state = {
|
|
373
|
+
kind: input.kind,
|
|
374
|
+
entries,
|
|
375
|
+
insertedAtStart: [],
|
|
376
|
+
meta: { ...input.meta },
|
|
377
|
+
variableSchema: { ...input.variableSchema },
|
|
378
|
+
};
|
|
379
|
+
const issues = input.ops.flatMap((op, index) => applyOp(state, op, `ops.${index}`) ?? []);
|
|
380
|
+
if (issues.length > 0)
|
|
381
|
+
return { ok: false, issues };
|
|
382
|
+
const content = [
|
|
383
|
+
...state.insertedAtStart,
|
|
384
|
+
...[...entries.values()].flatMap((entry) => entry.removed ? entry.insertedAfter : [entry.node, ...entry.insertedAfter]),
|
|
385
|
+
];
|
|
386
|
+
const doc = { ...input.doc, content };
|
|
387
|
+
if (!isValidDocument(doc))
|
|
388
|
+
return { ok: false, issues: [patchIssue("ops", "invalid_document")] };
|
|
389
|
+
return { ok: true, doc, meta: state.meta, variableSchema: state.variableSchema };
|
|
390
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FieldIssue } from "@cosmicdrift/kumiko-framework/errors";
|
|
2
|
+
import type { JSONContent } from "@tiptap/core";
|
|
2
3
|
import { type Element as ScanElement } from "happy-dom";
|
|
3
4
|
import type { ContentFormat } from "./constants.ts";
|
|
4
5
|
export type DocumentViolationCode = "script_element" | "event_handler_attribute" | "disallowed_link_href" | "external_image_source" | "image_without_resource" | "invalid_reference_name" | "embedded_content" | "unsafe_attribute_value" | "button_href_not_placeholder" | "document_requires_html_format" | "layout_requires_mjml_format" | "layout_invalid_structure" | "layout_missing_content_slot" | "layout_source_system_only";
|
|
@@ -24,6 +25,8 @@ export type SanitizeBodyResult = {
|
|
|
24
25
|
export declare function violation(code: DocumentViolationCode, detail: string, message: string): DocumentViolation;
|
|
25
26
|
export declare function withParsedDocument<T>(html: string, read: (body: ScanElement) => T): T;
|
|
26
27
|
export declare function sanitizeDocumentHtml(html: string): SanitizeHtmlResult;
|
|
28
|
+
export declare function parseDocumentJson(html: string): JSONContent;
|
|
29
|
+
export declare function serializeDocumentJson(doc: JSONContent): string;
|
|
27
30
|
export declare function flattenParagraphsToLineBreaks(sanitizedHtml: string): string;
|
|
28
31
|
export declare function sanitizeTemplateBody(input: {
|
|
29
32
|
readonly kind: string;
|
|
@@ -156,6 +156,12 @@ export function sanitizeDocumentHtml(html) {
|
|
|
156
156
|
html: generateHTML(generateJSON(html, documentExtensions), documentExtensions),
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
|
+
export function parseDocumentJson(html) {
|
|
160
|
+
return generateJSON(html, documentExtensions);
|
|
161
|
+
}
|
|
162
|
+
export function serializeDocumentJson(doc) {
|
|
163
|
+
return generateHTML(doc, documentExtensions);
|
|
164
|
+
}
|
|
159
165
|
// For a sanitized value placed inside a line of text: paragraphs become line
|
|
160
166
|
// breaks. Other blocks (lists, headings) cannot be made inline and stay as they are.
|
|
161
167
|
export function flattenParagraphsToLineBreaks(sanitizedHtml) {
|
|
@@ -31,6 +31,7 @@ export declare function createTemplateResolverFeature(opts?: TemplateResolverOpt
|
|
|
31
31
|
resourceRemove: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
32
32
|
resourceLinkPdf: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
33
33
|
sendTest: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
34
|
+
patchDraft: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
34
35
|
};
|
|
35
36
|
queries: {
|
|
36
37
|
findById: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
@@ -44,6 +45,7 @@ export declare function createTemplateResolverFeature(opts?: TemplateResolverOpt
|
|
|
44
45
|
diffToSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
45
46
|
validate: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
46
47
|
preview: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
48
|
+
documentBlocks: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
47
49
|
exportBundle: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
48
50
|
};
|
|
49
51
|
treeHandle: import("@cosmicdrift/kumiko-types/tree-node").TreeActionsHandle<"template-resolver", {
|
|
@@ -8,6 +8,7 @@ import { makeCollectionSetWrite } from "./handlers/collection-set.write.js";
|
|
|
8
8
|
import { copyLocaleWrite } from "./handlers/copy-locale.write.js";
|
|
9
9
|
import { diffToSystemQuery } from "./handlers/diff-to-system.query.js";
|
|
10
10
|
import { discardDraftSystemWrite, discardDraftWrite } from "./handlers/discard-draft.write.js";
|
|
11
|
+
import { documentBlocksQuery } from "./handlers/document-blocks.query.js";
|
|
11
12
|
import { exportBundleQuery } from "./handlers/export-bundle.query.js";
|
|
12
13
|
import { findByIdQuery } from "./handlers/find-by-id.query.js";
|
|
13
14
|
import { importBundleWrite } from "./handlers/import-bundle.write.js";
|
|
@@ -15,6 +16,7 @@ import { importBundleSystemWrite } from "./handlers/import-bundle-system.write.j
|
|
|
15
16
|
import { layoutSourceQuery } from "./handlers/layout-source.query.js";
|
|
16
17
|
import { listQuery } from "./handlers/list.query.js";
|
|
17
18
|
import { overviewQuery } from "./handlers/overview.query.js";
|
|
19
|
+
import { patchDraftWrite } from "./handlers/patch-draft.write.js";
|
|
18
20
|
import { previewQuery } from "./handlers/preview.query.js";
|
|
19
21
|
import { resetToSystemWrite } from "./handlers/reset-to-system.write.js";
|
|
20
22
|
import { resourceLinkPdfWrite } from "./handlers/resource-link-pdf.write.js";
|
|
@@ -88,6 +90,7 @@ export function createTemplateResolverFeature(opts = {}) {
|
|
|
88
90
|
resourceRemove: r.writeHandler(resourceRemoveWrite),
|
|
89
91
|
resourceLinkPdf: r.writeHandler(resourceLinkPdfWrite),
|
|
90
92
|
sendTest: r.writeHandler(sendTestWrite),
|
|
93
|
+
patchDraft: r.writeHandler(patchDraftWrite),
|
|
91
94
|
};
|
|
92
95
|
const queries = {
|
|
93
96
|
findById: r.queryHandler(findByIdQuery),
|
|
@@ -101,6 +104,7 @@ export function createTemplateResolverFeature(opts = {}) {
|
|
|
101
104
|
diffToSystem: r.queryHandler(diffToSystemQuery),
|
|
102
105
|
validate: r.queryHandler(validateQuery),
|
|
103
106
|
preview: r.queryHandler(previewQuery),
|
|
107
|
+
documentBlocks: r.queryHandler(documentBlocksQuery),
|
|
104
108
|
exportBundle: r.queryHandler(exportBundleQuery),
|
|
105
109
|
};
|
|
106
110
|
for (const collection of collections) {
|
|
@@ -147,6 +147,7 @@ export async function importTemplateBundle(args) {
|
|
|
147
147
|
contentFormat: args.bundle.contentFormat,
|
|
148
148
|
variableSchema,
|
|
149
149
|
meta: entry.meta,
|
|
150
|
+
...(entry.title !== undefined && { title: entry.title }),
|
|
150
151
|
};
|
|
151
152
|
const written = await writeTemplateRow({
|
|
152
153
|
ctx: args.ctx,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type HandlerContext, type SessionUser } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import type { DocumentHtmlKind } from "../constants.ts";
|
|
3
|
+
export type DocumentBase = {
|
|
4
|
+
readonly scope: "tenant" | "system";
|
|
5
|
+
/** The stored row's own version, which counts every draft save. */
|
|
6
|
+
readonly version: number;
|
|
7
|
+
};
|
|
8
|
+
export type LoadedDocument = {
|
|
9
|
+
readonly rowId: string;
|
|
10
|
+
readonly base: DocumentBase;
|
|
11
|
+
readonly status: string;
|
|
12
|
+
readonly content: string;
|
|
13
|
+
readonly meta: Readonly<Record<string, unknown>>;
|
|
14
|
+
readonly variableSchema: Readonly<Record<string, unknown>>;
|
|
15
|
+
readonly title: string | null;
|
|
16
|
+
readonly folder: string | null;
|
|
17
|
+
readonly parentTemplateId: string | null;
|
|
18
|
+
};
|
|
19
|
+
export declare function loadDocumentBase(ctx: HandlerContext, user: SessionUser, where: {
|
|
20
|
+
readonly slug: string;
|
|
21
|
+
readonly kind: DocumentHtmlKind;
|
|
22
|
+
readonly locale: string;
|
|
23
|
+
}): Promise<LoadedDocument | null>;
|