@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,55 @@
|
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
2
|
+
import { SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
4
|
+
import { templateResourcesTable } from "../table.js";
|
|
5
|
+
import { isHiddenSystemDraft, toWorkingRow } from "../template-draft.js";
|
|
6
|
+
import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.js";
|
|
7
|
+
import { parseStoredJson } from "./template-gates.js";
|
|
8
|
+
function recordOrEmpty(raw) {
|
|
9
|
+
const parsed = parseStoredJson(raw);
|
|
10
|
+
return isPlainObject(parsed) ? parsed : {};
|
|
11
|
+
}
|
|
12
|
+
// The version an editor works on: the caller's own row (its open draft if there is one),
|
|
13
|
+
// else the served system default. A system default as base is what a patch copies into a tenant draft.
|
|
14
|
+
export async function loadDocumentBase(ctx, user, where) {
|
|
15
|
+
const own = await fetchOne(ctx.db, templateResourcesTable, {
|
|
16
|
+
tenantId: user.tenantId,
|
|
17
|
+
...where,
|
|
18
|
+
});
|
|
19
|
+
if (own !== undefined && !isSystemOnlyTemplateHiddenFrom(user, ctx.registry, own)) {
|
|
20
|
+
const working = toWorkingRow(own, user.tenantId);
|
|
21
|
+
return {
|
|
22
|
+
rowId: String(own.id),
|
|
23
|
+
base: { scope: own.scope === "system" ? "system" : "tenant", version: own.version },
|
|
24
|
+
status: working.status,
|
|
25
|
+
content: working.content ?? "",
|
|
26
|
+
meta: recordOrEmpty(working.meta),
|
|
27
|
+
variableSchema: recordOrEmpty(working.variableSchema),
|
|
28
|
+
title: working.title,
|
|
29
|
+
folder: working.folder,
|
|
30
|
+
parentTemplateId: working.parentTemplateId,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const system = await fetchOne(ctx.db, templateResourcesTable, {
|
|
34
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
35
|
+
scope: "system",
|
|
36
|
+
status: "active",
|
|
37
|
+
...where,
|
|
38
|
+
});
|
|
39
|
+
if (system === undefined ||
|
|
40
|
+
isHiddenSystemDraft(user, system) ||
|
|
41
|
+
isSystemOnlyTemplateHiddenFrom(user, ctx.registry, system)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
rowId: String(system.id),
|
|
46
|
+
base: { scope: "system", version: system.version },
|
|
47
|
+
status: system.status,
|
|
48
|
+
content: system.content ?? "",
|
|
49
|
+
meta: recordOrEmpty(system.meta),
|
|
50
|
+
variableSchema: recordOrEmpty(system.variableSchema),
|
|
51
|
+
title: system.title,
|
|
52
|
+
folder: system.folder,
|
|
53
|
+
parentTemplateId: String(system.id),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export declare const documentBlocksQuery: import("@cosmicdrift/kumiko-types/define-handler").QueryHandlerDefinition<"document-blocks", z.ZodObject<{
|
|
3
|
+
slug: z.ZodString;
|
|
4
|
+
kind: z.ZodEnum<{
|
|
5
|
+
"document-pdf": "document-pdf";
|
|
6
|
+
mail: "mail";
|
|
7
|
+
}>;
|
|
8
|
+
locale: z.ZodString;
|
|
9
|
+
}, z.core.$strip>, {
|
|
10
|
+
slug: string;
|
|
11
|
+
kind: "document-pdf" | "mail";
|
|
12
|
+
locale: string;
|
|
13
|
+
base: import("./document-base.ts").DocumentBase;
|
|
14
|
+
status: string;
|
|
15
|
+
blocks: import("../document-ops.ts").DocumentBlock[];
|
|
16
|
+
meta: Readonly<Record<string, unknown>>;
|
|
17
|
+
variableSchema: Readonly<Record<string, unknown>>;
|
|
18
|
+
variables: Readonly<Record<string, import("@cosmicdrift/kumiko-types/config").TemplateVariableDef>>;
|
|
19
|
+
variablesDeclaredByFeature: boolean;
|
|
20
|
+
allowedBlocks: readonly import("../document-blocks.ts").DocumentToolbarBlock[];
|
|
21
|
+
resourceKeys: string[];
|
|
22
|
+
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { NotFoundError } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import * as z from "zod";
|
|
4
|
+
import { DOCUMENT_HTML_KINDS } from "../constants.js";
|
|
5
|
+
import { documentBlocksForKind } from "../document-blocks.js";
|
|
6
|
+
import { documentBlocksOf } from "../document-ops.js";
|
|
7
|
+
import { parseDocumentJson } from "../document-sanitizer.js";
|
|
8
|
+
import { resolveTemplateVariables } from "../template-validation.js";
|
|
9
|
+
import { loadDocumentBase } from "./document-base.js";
|
|
10
|
+
import { localeSchema, templateSlugSchema } from "./shared.js";
|
|
11
|
+
import { knownResourceKeysFor } from "./validate.query.js";
|
|
12
|
+
export const documentBlocksQuery = defineQueryHandler({
|
|
13
|
+
name: "document-blocks",
|
|
14
|
+
schema: z.object({
|
|
15
|
+
slug: templateSlugSchema,
|
|
16
|
+
kind: z.enum(DOCUMENT_HTML_KINDS),
|
|
17
|
+
locale: localeSchema,
|
|
18
|
+
}),
|
|
19
|
+
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
20
|
+
description: "Reads a mail or PDF document template as a list of blocks with stable ids (b0, b1, ...) for structured editing: each block has its type (paragraph, heading, list, table, repeat, image, button, divider, pageBreak, steps), its text with {{name}} placeholders and its settings, plus the meta, the stored and effective variables (variablesDeclaredByFeature is true when a notification declares them, so they cannot be changed), the block types allowed for the kind and the uploaded image keys. It reads the caller's own version (the open draft if there is one), else the served system default; base carries the scope and version that patch-draft expects back.",
|
|
21
|
+
handler: async (query, ctx) => {
|
|
22
|
+
const { slug, kind, locale } = query.payload;
|
|
23
|
+
const loaded = await loadDocumentBase(ctx, query.user, { slug, kind, locale });
|
|
24
|
+
if (loaded === null)
|
|
25
|
+
throw new NotFoundError("template-resource", slug);
|
|
26
|
+
return {
|
|
27
|
+
slug,
|
|
28
|
+
kind,
|
|
29
|
+
locale,
|
|
30
|
+
base: loaded.base,
|
|
31
|
+
status: loaded.status,
|
|
32
|
+
blocks: documentBlocksOf(parseDocumentJson(loaded.content)),
|
|
33
|
+
meta: loaded.meta,
|
|
34
|
+
variableSchema: loaded.variableSchema,
|
|
35
|
+
variables: resolveTemplateVariables(ctx.registry, slug, loaded.variableSchema),
|
|
36
|
+
variablesDeclaredByFeature: ctx.registry.getAllNotifications().get(slug)?.variables !== undefined,
|
|
37
|
+
allowedBlocks: documentBlocksForKind(kind),
|
|
38
|
+
resourceKeys: await knownResourceKeysFor(ctx, query.user, {
|
|
39
|
+
slug,
|
|
40
|
+
kind,
|
|
41
|
+
scope: "tenant",
|
|
42
|
+
locale,
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
});
|
|
@@ -55,6 +55,14 @@ function assertLocalesShareFormat(rows) {
|
|
|
55
55
|
],
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
+
function localeEntryOf(row) {
|
|
59
|
+
const meta = parseStoredJson(row.meta);
|
|
60
|
+
return {
|
|
61
|
+
body: row.content ?? "",
|
|
62
|
+
...(meta === undefined ? {} : { meta }),
|
|
63
|
+
...(row.title === null ? {} : { title: row.title }),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
58
66
|
export const exportBundleQuery = defineQueryHandler({
|
|
59
67
|
name: "export-bundle",
|
|
60
68
|
schema: z.object({
|
|
@@ -79,8 +87,7 @@ export const exportBundleQuery = defineQueryHandler({
|
|
|
79
87
|
const locales = {};
|
|
80
88
|
const entryByKey = new Map();
|
|
81
89
|
for (const row of rows) {
|
|
82
|
-
|
|
83
|
-
locales[row.locale] = { body: row.content ?? "", ...(meta === undefined ? {} : { meta }) };
|
|
90
|
+
locales[row.locale] = localeEntryOf(row);
|
|
84
91
|
for (const [key, entry] of Object.entries(parseLinkedResourceEntries(row.linkedResources))) {
|
|
85
92
|
if (!entryByKey.has(key))
|
|
86
93
|
entryByKey.set(key, entry);
|
|
@@ -20,6 +20,7 @@ export declare const importBundleSystemWrite: import("@cosmicdrift/kumiko-types/
|
|
|
20
20
|
locales: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
21
21
|
body: z.ZodString;
|
|
22
22
|
meta: z.ZodOptional<z.ZodUnknown>;
|
|
23
|
+
title: z.ZodOptional<z.ZodString>;
|
|
23
24
|
}, z.core.$strict>>;
|
|
24
25
|
resources: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
25
26
|
fileName: z.ZodString;
|
|
@@ -20,6 +20,7 @@ export declare const importBundleWrite: import("@cosmicdrift/kumiko-types/define
|
|
|
20
20
|
locales: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
21
21
|
body: z.ZodString;
|
|
22
22
|
meta: z.ZodOptional<z.ZodUnknown>;
|
|
23
|
+
title: z.ZodOptional<z.ZodString>;
|
|
23
24
|
}, z.core.$strict>>;
|
|
24
25
|
resources: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
25
26
|
fileName: z.ZodString;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export declare const patchDraftWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"patch-draft", z.ZodObject<{
|
|
3
|
+
slug: z.ZodString;
|
|
4
|
+
kind: z.ZodEnum<{
|
|
5
|
+
"document-pdf": "document-pdf";
|
|
6
|
+
mail: "mail";
|
|
7
|
+
}>;
|
|
8
|
+
locale: z.ZodString;
|
|
9
|
+
base: z.ZodObject<{
|
|
10
|
+
scope: z.ZodEnum<{
|
|
11
|
+
system: "system";
|
|
12
|
+
tenant: "tenant";
|
|
13
|
+
}>;
|
|
14
|
+
version: z.ZodNumber;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
ops: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
17
|
+
op: z.ZodLiteral<"insertBlock">;
|
|
18
|
+
after: z.ZodNullable<z.ZodString>;
|
|
19
|
+
block: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
20
|
+
type: z.ZodLiteral<"paragraph">;
|
|
21
|
+
text: z.ZodString;
|
|
22
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
23
|
+
center: "center";
|
|
24
|
+
justify: "justify";
|
|
25
|
+
left: "left";
|
|
26
|
+
right: "right";
|
|
27
|
+
}>>;
|
|
28
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
29
|
+
type: z.ZodLiteral<"heading">;
|
|
30
|
+
level: z.ZodNumber;
|
|
31
|
+
text: z.ZodString;
|
|
32
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
33
|
+
type: z.ZodLiteral<"image">;
|
|
34
|
+
resource: z.ZodString;
|
|
35
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
37
|
+
type: z.ZodLiteral<"button">;
|
|
38
|
+
text: z.ZodString;
|
|
39
|
+
href: z.ZodString;
|
|
40
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
41
|
+
type: z.ZodLiteral<"divider">;
|
|
42
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
43
|
+
type: z.ZodLiteral<"pageBreak">;
|
|
44
|
+
}, z.core.$strip>], "type">;
|
|
45
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
46
|
+
op: z.ZodLiteral<"replaceText">;
|
|
47
|
+
blockId: z.ZodString;
|
|
48
|
+
find: z.ZodString;
|
|
49
|
+
replace: z.ZodString;
|
|
50
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
51
|
+
op: z.ZodLiteral<"removeBlock">;
|
|
52
|
+
blockId: z.ZodString;
|
|
53
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
54
|
+
op: z.ZodLiteral<"setResource">;
|
|
55
|
+
blockId: z.ZodString;
|
|
56
|
+
resource: z.ZodString;
|
|
57
|
+
alt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
58
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
59
|
+
op: z.ZodLiteral<"setMeta">;
|
|
60
|
+
meta: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
61
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
62
|
+
op: z.ZodLiteral<"setVariable">;
|
|
63
|
+
name: z.ZodString;
|
|
64
|
+
definition: z.ZodNullable<z.ZodUnknown>;
|
|
65
|
+
}, z.core.$strip>], "op">>;
|
|
66
|
+
}, z.core.$strip>, import("./template-write.ts").WrittenTemplateRow, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { NotFoundError, ValidationError, VersionConflictError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import * as z from "zod";
|
|
4
|
+
import { DOCUMENT_HTML_KINDS } from "../constants.js";
|
|
5
|
+
import { applyDocumentOps, documentOpsSchema } from "../document-ops.js";
|
|
6
|
+
import { parseDocumentJson, serializeDocumentJson } from "../document-sanitizer.js";
|
|
7
|
+
import { resolveTemplateVariables } from "../template-validation.js";
|
|
8
|
+
import { loadDocumentBase } from "./document-base.js";
|
|
9
|
+
import { localeSchema, templateSlugSchema } from "./shared.js";
|
|
10
|
+
import { writeTemplateRow } from "./template-write.js";
|
|
11
|
+
import { validateTemplateDraft } from "./validate.query.js";
|
|
12
|
+
function validationFailure(issue) {
|
|
13
|
+
return writeFailure(new ValidationError({ fields: [issue] }));
|
|
14
|
+
}
|
|
15
|
+
export const patchDraftWrite = defineWriteHandler({
|
|
16
|
+
name: "patch-draft",
|
|
17
|
+
schema: z.object({
|
|
18
|
+
slug: templateSlugSchema,
|
|
19
|
+
kind: z.enum(DOCUMENT_HTML_KINDS),
|
|
20
|
+
locale: localeSchema,
|
|
21
|
+
base: z.object({
|
|
22
|
+
scope: z.enum(["tenant", "system"]),
|
|
23
|
+
version: z.number().int().nonnegative(),
|
|
24
|
+
}),
|
|
25
|
+
ops: documentOpsSchema,
|
|
26
|
+
}),
|
|
27
|
+
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
28
|
+
description: "Changes a mail or PDF document template with structured operations instead of a full rewrite and saves the result as the caller's tenant draft (never published, an active version keeps being served until publish): insertBlock after a block id (null = at the start; paragraph, heading, image, button, divider, pageBreak), replaceText inside one block (the text must occur exactly once), removeBlock, setResource on an image block, setMeta (flat merge, null removes a key) and setVariable (adds, replaces or with null removes a variable definition; refused when a notification declares the variables). Block ids and base come from document-blocks and refer to the state that was read; if the template changed since, the call fails with version_conflict and nothing is written. A patch that removes a required placeholder is refused. Returns the written row.",
|
|
29
|
+
handler: async (event, ctx) => {
|
|
30
|
+
const { slug, kind, locale, base, ops } = event.payload;
|
|
31
|
+
const loaded = await loadDocumentBase(ctx, event.user, { slug, kind, locale });
|
|
32
|
+
if (loaded === null)
|
|
33
|
+
return writeFailure(new NotFoundError("template-resource", slug));
|
|
34
|
+
if (loaded.base.scope !== base.scope || loaded.base.version !== base.version) {
|
|
35
|
+
return writeFailure(new VersionConflictError({
|
|
36
|
+
entityId: loaded.rowId,
|
|
37
|
+
expectedVersion: base.version,
|
|
38
|
+
currentVersion: loaded.base.version,
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
const variableOpIndex = ops.findIndex((op) => op.op === "setVariable");
|
|
42
|
+
if (variableOpIndex !== -1 &&
|
|
43
|
+
ctx.registry.getAllNotifications().get(slug)?.variables !== undefined) {
|
|
44
|
+
return validationFailure({
|
|
45
|
+
path: `ops.${variableOpIndex}`,
|
|
46
|
+
code: "variables_declared_by_feature",
|
|
47
|
+
i18nKey: "templateResolver.errors.patch.variablesDeclaredByFeature",
|
|
48
|
+
params: { slug },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const applied = applyDocumentOps({
|
|
52
|
+
doc: parseDocumentJson(loaded.content),
|
|
53
|
+
meta: loaded.meta,
|
|
54
|
+
variableSchema: loaded.variableSchema,
|
|
55
|
+
kind,
|
|
56
|
+
ops,
|
|
57
|
+
});
|
|
58
|
+
if (!applied.ok)
|
|
59
|
+
return writeFailure(new ValidationError({ fields: applied.issues }));
|
|
60
|
+
const content = serializeDocumentJson(applied.doc);
|
|
61
|
+
const draftOf = (draftContent, meta, variableSchema) => validateTemplateDraft(ctx, event.user, {
|
|
62
|
+
slug,
|
|
63
|
+
kind,
|
|
64
|
+
contentFormat: "html",
|
|
65
|
+
content: draftContent,
|
|
66
|
+
meta,
|
|
67
|
+
variableSchema,
|
|
68
|
+
locale,
|
|
69
|
+
scope: "tenant",
|
|
70
|
+
});
|
|
71
|
+
const before = await draftOf(loaded.content, loaded.meta, loaded.variableSchema);
|
|
72
|
+
const after = await draftOf(content, applied.meta, applied.variableSchema);
|
|
73
|
+
const alreadyMissing = new Set(before.response.missingRequired);
|
|
74
|
+
const removed = after.response.missingRequired.filter((name) => !alreadyMissing.has(name));
|
|
75
|
+
if (removed.length > 0) {
|
|
76
|
+
return validationFailure({
|
|
77
|
+
path: "ops",
|
|
78
|
+
code: "required_placeholder_removed",
|
|
79
|
+
i18nKey: "templateResolver.errors.patch.requiredPlaceholderRemoved",
|
|
80
|
+
params: { names: removed },
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return writeTemplateRow({
|
|
84
|
+
ctx,
|
|
85
|
+
user: event.user,
|
|
86
|
+
tenantId: event.user.tenantId,
|
|
87
|
+
scope: "tenant",
|
|
88
|
+
status: "draft",
|
|
89
|
+
variables: resolveTemplateVariables(ctx.registry, slug, applied.variableSchema),
|
|
90
|
+
payload: {
|
|
91
|
+
slug,
|
|
92
|
+
kind,
|
|
93
|
+
locale,
|
|
94
|
+
content,
|
|
95
|
+
contentFormat: "html",
|
|
96
|
+
variableSchema: applied.variableSchema,
|
|
97
|
+
meta: applied.meta,
|
|
98
|
+
title: loaded.title,
|
|
99
|
+
folder: loaded.folder,
|
|
100
|
+
parentTemplateId: loaded.parentTemplateId,
|
|
101
|
+
},
|
|
102
|
+
expectedVersion: loaded.base.scope === "tenant" ? loaded.base.version : null,
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
});
|
|
@@ -9,4 +9,5 @@ export declare const previewQuery: import("@cosmicdrift/kumiko-types/define-hand
|
|
|
9
9
|
content: z.ZodOptional<z.ZodString>;
|
|
10
10
|
meta: z.ZodOptional<z.ZodUnknown>;
|
|
11
11
|
variableSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
12
|
+
variables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
12
13
|
}, z.core.$strip>, import("../template-preview.ts").TemplatePreview, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -12,9 +12,10 @@ export const previewQuery = defineQueryHandler({
|
|
|
12
12
|
content: z.string().max(200_000).optional(),
|
|
13
13
|
meta: z.unknown().optional(),
|
|
14
14
|
variableSchema: z.record(z.string(), z.unknown()).default({}),
|
|
15
|
+
variables: z.record(z.string(), z.unknown()).optional(),
|
|
15
16
|
}),
|
|
16
17
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
17
|
-
description: "Renders a template draft, or the stored template when no content is given, with sample values taken from the declared variable examples, without saving or sending anything: returns the mail subject, html and plain text with its inline images (a PDF template returns its body and layout regions instead), the sample values used, and checks for unresolved images, missing plain text, mail size and unused required placeholders; a draft that fails the write rules is rejected with the same problems as a save.",
|
|
18
|
+
description: "Renders a template draft, or the stored template when no content is given, with sample values taken from the declared variable examples (values passed in variables replace them and are checked against the variable schema), without saving or sending anything: returns the mail subject, html and plain text with its inline images (a PDF template returns its body and layout regions instead), the sample values used, and checks for unresolved images, missing plain text, mail size and unused required placeholders; a draft that fails the write rules is rejected with the same problems as a save.",
|
|
18
19
|
handler: async (query, ctx) => {
|
|
19
20
|
const outcome = await renderTemplatePreview(ctx, query.user, query.payload);
|
|
20
21
|
if (!outcome.ok)
|
|
@@ -5,6 +5,7 @@ export declare const sendTestWrite: import("@cosmicdrift/kumiko-types/define-han
|
|
|
5
5
|
content: z.ZodOptional<z.ZodString>;
|
|
6
6
|
meta: z.ZodOptional<z.ZodUnknown>;
|
|
7
7
|
variableSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
8
|
+
variables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
8
9
|
includeAttachments: z.ZodDefault<z.ZodBoolean>;
|
|
9
10
|
prefixSubject: z.ZodDefault<z.ZodBoolean>;
|
|
10
11
|
}, z.core.$strip>, {
|
|
@@ -31,12 +31,13 @@ export const sendTestWrite = defineWriteHandler({
|
|
|
31
31
|
content: z.string().max(200_000).optional(),
|
|
32
32
|
meta: z.unknown().optional(),
|
|
33
33
|
variableSchema: z.record(z.string(), z.unknown()).default({}),
|
|
34
|
+
variables: z.record(z.string(), z.unknown()).optional(),
|
|
34
35
|
includeAttachments: z.boolean().default(true),
|
|
35
36
|
prefixSubject: z.boolean().default(true),
|
|
36
37
|
}),
|
|
37
38
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
38
39
|
rateLimit: { per: "user+handler", ...TEST_MAIL_RATE_LIMIT },
|
|
39
|
-
description: "Sends the rendered preview of a mail template draft, or of the stored template when no content is given, to the calling user's own address with the subject prefixed by [TEST] unless prefixSubject is false, carrying the inline images and, unless includeAttachments is false, the files attached to the template; there is no recipient input, the sample values come from the declared variable examples, and a draft that fails the write rules is rejected without sending.",
|
|
40
|
+
description: "Sends the rendered preview of a mail template draft, or of the stored template when no content is given, to the calling user's own address with the subject prefixed by [TEST] unless prefixSubject is false, carrying the inline images and, unless includeAttachments is false, the files attached to the template; there is no recipient input, the sample values come from the declared variable examples unless variables replaces them (checked against the variable schema), and a draft that fails the write rules is rejected without sending.",
|
|
40
41
|
handler: async (event, ctx) => {
|
|
41
42
|
const { includeAttachments, prefixSubject, ...previewPayload } = event.payload;
|
|
42
43
|
const outcome = await renderTemplatePreview(ctx, event.user, {
|
|
@@ -30,6 +30,8 @@ export type TemplateRowWrite = {
|
|
|
30
30
|
readonly status: "draft" | "active";
|
|
31
31
|
readonly variables: TemplateVariables;
|
|
32
32
|
readonly payload: TemplateRowPayload;
|
|
33
|
+
/** The row version the edit was made against; null means no own row may exist yet. */
|
|
34
|
+
readonly expectedVersion?: number | null;
|
|
33
35
|
};
|
|
34
36
|
export declare function refuseTenantScopeUnderSystemTenant(scope: TemplateWriteScope, tenantId: string): WriteResult<never> | null;
|
|
35
37
|
export declare function refuseSystemOnlyTenantOverride(registry: Registry, scope: TemplateWriteScope, slug: string, kind: string): WriteFailure | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import { AccessDeniedError, ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import { AccessDeniedError, ValidationError, VersionConflictError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
4
|
import { requireForTenant } from "../../shared/index.js";
|
|
5
5
|
import { TemplateResolverErrors } from "../qualified-names.js";
|
|
6
6
|
import { templateResourcesTable } from "../table.js";
|
|
@@ -67,6 +67,15 @@ function updateChanges(existing, status, fields) {
|
|
|
67
67
|
}
|
|
68
68
|
: { draft };
|
|
69
69
|
}
|
|
70
|
+
function versionConflictFor(expectedVersion, existing, slug) {
|
|
71
|
+
if (expectedVersion === undefined || (existing?.version ?? null) === expectedVersion)
|
|
72
|
+
return null;
|
|
73
|
+
return writeFailure(new VersionConflictError({
|
|
74
|
+
entityId: existing?.id ?? slug,
|
|
75
|
+
expectedVersion: expectedVersion ?? 0,
|
|
76
|
+
currentVersion: existing?.version ?? 0,
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
70
79
|
// Shared by every template write: validate through the one pipeline, then
|
|
71
80
|
// create or update the (tenant, slug, kind, locale) row via the event-store
|
|
72
81
|
// executor. linkedResources is never part of an update; resources are attached
|
|
@@ -109,10 +118,13 @@ export async function writeTemplateRow(args) {
|
|
|
109
118
|
parentTemplateId: payload.parentTemplateId ?? null,
|
|
110
119
|
status,
|
|
111
120
|
};
|
|
121
|
+
const conflict = versionConflictFor(args.expectedVersion, existing, payload.slug);
|
|
122
|
+
if (conflict !== null)
|
|
123
|
+
return conflict;
|
|
112
124
|
if (existing) {
|
|
113
125
|
const result = await executor.update({
|
|
114
126
|
id: existing.id,
|
|
115
|
-
version: existing.version,
|
|
127
|
+
version: args.expectedVersion ?? existing.version,
|
|
116
128
|
changes: updateChanges(existing, status, fields),
|
|
117
129
|
}, user, db, { streamTenantId });
|
|
118
130
|
if (!result.isSuccess)
|
|
@@ -12,12 +12,18 @@ type TemplateDraftInput = {
|
|
|
12
12
|
readonly locale?: string | undefined;
|
|
13
13
|
readonly scope: TemplateWriteScope;
|
|
14
14
|
};
|
|
15
|
+
export declare function knownResourceKeysFor(ctx: HandlerContext, user: SessionUser, where: {
|
|
16
|
+
readonly slug: string;
|
|
17
|
+
readonly kind: string;
|
|
18
|
+
readonly scope: TemplateWriteScope;
|
|
19
|
+
readonly locale: string | undefined;
|
|
20
|
+
}): Promise<string[]>;
|
|
15
21
|
export declare function validateTemplateDraft(ctx: HandlerContext, user: SessionUser, payload: TemplateDraftInput): Promise<{
|
|
16
22
|
response: {
|
|
17
23
|
canSave: boolean;
|
|
18
24
|
canPublish: boolean;
|
|
19
|
-
issues: import("@cosmicdrift/kumiko-
|
|
20
|
-
publishIssues: import("@cosmicdrift/kumiko-
|
|
25
|
+
issues: import("@cosmicdrift/kumiko-framework/errors").FieldIssue[];
|
|
26
|
+
publishIssues: import("@cosmicdrift/kumiko-framework/errors").FieldIssue[];
|
|
21
27
|
used: string[];
|
|
22
28
|
unknown: string[];
|
|
23
29
|
missingRequired: string[];
|
|
@@ -58,8 +64,8 @@ export declare const validateQuery: import("@cosmicdrift/kumiko-types/define-han
|
|
|
58
64
|
}, z.core.$strip>, {
|
|
59
65
|
canSave: boolean;
|
|
60
66
|
canPublish: boolean;
|
|
61
|
-
issues: import("@cosmicdrift/kumiko-
|
|
62
|
-
publishIssues: import("@cosmicdrift/kumiko-
|
|
67
|
+
issues: import("@cosmicdrift/kumiko-framework/errors").FieldIssue[];
|
|
68
|
+
publishIssues: import("@cosmicdrift/kumiko-framework/errors").FieldIssue[];
|
|
63
69
|
used: string[];
|
|
64
70
|
unknown: string[];
|
|
65
71
|
missingRequired: string[];
|
|
@@ -18,13 +18,10 @@ async function knownResourceKeys(db, where) {
|
|
|
18
18
|
});
|
|
19
19
|
return rows.flatMap((row) => imageResourceKeysOf(row.linkedResources));
|
|
20
20
|
}
|
|
21
|
-
//
|
|
22
|
-
export async function
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
// The dry run must not promise what the caller's write handlers would refuse.
|
|
26
|
-
const scope = isSystemAdmin(user) ? payload.scope : "tenant";
|
|
27
|
-
const known = [
|
|
21
|
+
// Image keys the editor may reference: the system rows plus, for a tenant write, the caller's own.
|
|
22
|
+
export async function knownResourceKeysFor(ctx, user, where) {
|
|
23
|
+
const { slug, kind, scope, locale } = where;
|
|
24
|
+
return [
|
|
28
25
|
...(await knownResourceKeys(ctx.db, {
|
|
29
26
|
tenantId: SYSTEM_TENANT_ID,
|
|
30
27
|
slug,
|
|
@@ -36,6 +33,14 @@ export async function validateTemplateDraft(ctx, user, payload) {
|
|
|
36
33
|
? await knownResourceKeys(ctx.db, { tenantId: user.tenantId, slug, kind, scope, locale })
|
|
37
34
|
: []),
|
|
38
35
|
];
|
|
36
|
+
}
|
|
37
|
+
// The dry run of the write pipeline; preview feeds on the evaluation, validate returns the response.
|
|
38
|
+
export async function validateTemplateDraft(ctx, user, payload) {
|
|
39
|
+
const variables = resolveTemplateVariables(ctx.registry, payload.slug, payload.variableSchema);
|
|
40
|
+
const { slug, kind, locale } = payload;
|
|
41
|
+
// The dry run must not promise what the caller's write handlers would refuse.
|
|
42
|
+
const scope = isSystemAdmin(user) ? payload.scope : "tenant";
|
|
43
|
+
const known = await knownResourceKeysFor(ctx, user, { slug, kind, scope, locale });
|
|
39
44
|
const evaluation = evaluateTemplateWrite({
|
|
40
45
|
kind,
|
|
41
46
|
scope,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isDocumentReferenceName } from "
|
|
1
|
+
import { isDocumentReferenceName } from "./document-schema.js";
|
|
2
2
|
const PLACEHOLDER_TOKEN = /\{\{([^{}]*)\}\}/g;
|
|
3
3
|
// Names the schema refuses stay plain text, so a typo never becomes a chip
|
|
4
4
|
// that the server would reject.
|
|
@@ -17,6 +17,7 @@ export declare const TemplateResolverHandlers: {
|
|
|
17
17
|
readonly resourceRemove: "template-resolver:write:resource-remove";
|
|
18
18
|
readonly resourceLinkPdf: "template-resolver:write:resource-link-pdf";
|
|
19
19
|
readonly sendTest: "template-resolver:write:send-test";
|
|
20
|
+
readonly patchDraft: "template-resolver:write:patch-draft";
|
|
20
21
|
};
|
|
21
22
|
export declare const TemplateResolverQueries: {
|
|
22
23
|
readonly findById: "template-resolver:query:find-by-id";
|
|
@@ -28,6 +29,7 @@ export declare const TemplateResolverQueries: {
|
|
|
28
29
|
readonly diffToSystem: "template-resolver:query:diff-to-system";
|
|
29
30
|
readonly validate: "template-resolver:query:validate";
|
|
30
31
|
readonly preview: "template-resolver:query:preview";
|
|
32
|
+
readonly documentBlocks: "template-resolver:query:document-blocks";
|
|
31
33
|
readonly exportBundle: "template-resolver:query:export-bundle";
|
|
32
34
|
readonly bySlug: "template-resolver:query:by-slug";
|
|
33
35
|
readonly byTenant: "template-resolver:query:by-tenant";
|
|
@@ -19,6 +19,7 @@ export const TemplateResolverHandlers = {
|
|
|
19
19
|
resourceRemove: "template-resolver:write:resource-remove",
|
|
20
20
|
resourceLinkPdf: "template-resolver:write:resource-link-pdf",
|
|
21
21
|
sendTest: "template-resolver:write:send-test",
|
|
22
|
+
patchDraft: "template-resolver:write:patch-draft",
|
|
22
23
|
};
|
|
23
24
|
export const TemplateResolverQueries = {
|
|
24
25
|
findById: "template-resolver:query:find-by-id",
|
|
@@ -30,6 +31,7 @@ export const TemplateResolverQueries = {
|
|
|
30
31
|
diffToSystem: "template-resolver:query:diff-to-system",
|
|
31
32
|
validate: "template-resolver:query:validate",
|
|
32
33
|
preview: "template-resolver:query:preview",
|
|
34
|
+
documentBlocks: "template-resolver:query:document-blocks",
|
|
33
35
|
exportBundle: "template-resolver:query:export-bundle",
|
|
34
36
|
// Public pair — anonymous-reachable, kind pinned to text-block.
|
|
35
37
|
bySlug: "template-resolver:query:by-slug",
|
|
@@ -15,6 +15,7 @@ export type SeedSystemTemplateOptions = {
|
|
|
15
15
|
* system admin uploaded through resource-upload. */
|
|
16
16
|
readonly linkedResources?: Record<string, string>;
|
|
17
17
|
readonly meta?: unknown;
|
|
18
|
+
readonly title?: string;
|
|
18
19
|
readonly parentTemplateId?: string | null;
|
|
19
20
|
readonly by?: SessionUser;
|
|
20
21
|
readonly ifExists?: SeedIfExists;
|
|
@@ -81,7 +81,7 @@ export async function seedSystemTemplate(db, opts) {
|
|
|
81
81
|
variableSchema,
|
|
82
82
|
...(linkedResources !== undefined && { linkedResources }),
|
|
83
83
|
meta,
|
|
84
|
-
title: null,
|
|
84
|
+
title: opts.title ?? null,
|
|
85
85
|
folder: null,
|
|
86
86
|
scope: "system",
|
|
87
87
|
parentTemplateId,
|
|
@@ -171,6 +171,7 @@ export async function seedSystemTemplateBundle(db, bundle, opts = {}) {
|
|
|
171
171
|
contentFormat: bundle.contentFormat,
|
|
172
172
|
variableSchema: bundle.variableSchema ?? {},
|
|
173
173
|
meta: entry.meta,
|
|
174
|
+
...(entry.title !== undefined ? { title: entry.title } : {}),
|
|
174
175
|
...(opts.by !== undefined ? { by: opts.by } : {}),
|
|
175
176
|
...(opts.ifExists !== undefined ? { ifExists: opts.ifExists } : {}),
|
|
176
177
|
});
|