@formfeed/engine 0.2.0 → 0.3.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.
Files changed (64) hide show
  1. package/THIRD_PARTY_LICENSES.md +31 -0
  2. package/index.cjs +4204 -166
  3. package/index.js +4204 -166
  4. package/package.json +1 -1
  5. package/types/index.d.cts +19 -9
  6. package/types/index.d.ts +19 -9
  7. package/types/lib/assemble.d.cts +24 -9
  8. package/types/lib/assemble.d.ts +24 -9
  9. package/types/lib/brand.d.cts +46 -0
  10. package/types/lib/brand.d.ts +46 -0
  11. package/types/lib/helpers/document.d.cts +24 -0
  12. package/types/lib/helpers/document.d.ts +24 -0
  13. package/types/lib/helpers/index.d.cts +1 -0
  14. package/types/lib/helpers/index.d.ts +1 -0
  15. package/types/lib/helpers/office.d.cts +4 -0
  16. package/types/lib/helpers/office.d.ts +4 -0
  17. package/types/lib/import/apitemplate.d.cts +60 -0
  18. package/types/lib/import/apitemplate.d.ts +60 -0
  19. package/types/lib/office/detect.d.cts +36 -0
  20. package/types/lib/office/detect.d.ts +36 -0
  21. package/types/lib/office/drawings.d.cts +120 -0
  22. package/types/lib/office/drawings.d.ts +120 -0
  23. package/types/lib/office/errors.d.cts +21 -0
  24. package/types/lib/office/errors.d.ts +21 -0
  25. package/types/lib/office/fonts.d.cts +21 -0
  26. package/types/lib/office/fonts.d.ts +21 -0
  27. package/types/lib/office/ids.d.cts +1 -0
  28. package/types/lib/office/ids.d.ts +1 -0
  29. package/types/lib/office/index.d.cts +18 -0
  30. package/types/lib/office/index.d.ts +18 -0
  31. package/types/lib/office/render.d.cts +79 -0
  32. package/types/lib/office/render.d.ts +79 -0
  33. package/types/lib/office/sanitise.d.cts +35 -0
  34. package/types/lib/office/sanitise.d.ts +35 -0
  35. package/types/lib/office/slides.d.cts +47 -0
  36. package/types/lib/office/slides.d.ts +47 -0
  37. package/types/lib/office/starter-pptx.d.cts +6 -0
  38. package/types/lib/office/starter-pptx.d.ts +6 -0
  39. package/types/lib/office/starter.d.cts +24 -0
  40. package/types/lib/office/starter.d.ts +24 -0
  41. package/types/lib/office/structure.d.cts +51 -0
  42. package/types/lib/office/structure.d.ts +51 -0
  43. package/types/lib/office/tags.d.cts +51 -0
  44. package/types/lib/office/tags.d.ts +51 -0
  45. package/types/lib/office/template-text.d.cts +59 -0
  46. package/types/lib/office/template-text.d.ts +59 -0
  47. package/types/lib/office/xml.d.cts +44 -0
  48. package/types/lib/office/xml.d.ts +44 -0
  49. package/types/lib/office/zip.d.cts +49 -0
  50. package/types/lib/office/zip.d.ts +49 -0
  51. package/types/lib/output.d.cts +29 -0
  52. package/types/lib/output.d.ts +29 -0
  53. package/types/lib/preview.d.cts +9 -1
  54. package/types/lib/preview.d.ts +9 -1
  55. package/types/lib/schema-diff.d.cts +27 -0
  56. package/types/lib/schema-diff.d.ts +27 -0
  57. package/types/lib/schema.d.cts +8 -0
  58. package/types/lib/schema.d.ts +8 -0
  59. package/types/lib/snippets.d.cts +38 -1
  60. package/types/lib/snippets.d.ts +38 -1
  61. package/types/lib/source-positions.d.cts +27 -0
  62. package/types/lib/source-positions.d.ts +27 -0
  63. package/types/lib/types.d.cts +37 -1
  64. package/types/lib/types.d.ts +37 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formfeed/engine",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The Formfeed template engine (Jinja2, Liquid, Handlebars) for the browser and Node.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/types/index.d.cts CHANGED
@@ -3,21 +3,31 @@ export { EngineSyntaxError, RenderError, RenderLimitError } from './lib/errors.c
3
3
  export { defaultLimits, depthGuard, enforceLimits } from './lib/limits.cjs';
4
4
  export { DefaultHelperRegistry, builtinHelpers, chartMarkup, chartPayload, createHelperRegistry, defaultHelpers, epcPayload, escapeHtml, helperDocs, imageMarkup, qrSvg, toDate, toNumber, } from './lib/helpers/index.cjs';
5
5
  export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, getEngine, handlebarsEngine, jinja2Engine, liquidEngine, liquidBuiltinFilters, nunjucksBuiltinFilters, } from './lib/engines/index.cjs';
6
- export { inferSchema, schemaPaths } from './lib/schema.cjs';
7
- export { mergeSampleData, snippets, snippetsFor } from './lib/snippets.cjs';
8
- export { importApitemplate, slugFromName } from './lib/import/apitemplate.cjs';
9
- export type { ApitemplateExport } from './lib/import/apitemplate.cjs';
6
+ export { diffSchemas, inferSchema, inferSchemaFromDataSets, schemaPaths } from './lib/schema.cjs';
7
+ export { defaultOutput, imageOutput, isOfficeKind, isOutputFormat, officeKinds, outputFormats, outputsForKind, type OfficeKind, type OutputFormat, } from './lib/output.cjs';
8
+ export { brandCss, emptyBrand, layeredPartials, normalisePartialName } from './lib/brand.cjs';
9
+ export type { BrandContext, SharedPartial } from './lib/brand.cjs';
10
+ export { mergeSampleData, mergeSnippetCss, mergeSnippetI18n, partialInclude, snippets, snippetsFor, snippetText, } from './lib/snippets.cjs';
11
+ export { apitemplateRegions, importApitemplate, importApitemplateFromApi, isApitemplateHtmlTemplate, isApitemplateRegion, slugFromName, splitApitemplateCss, } from './lib/import/apitemplate.cjs';
12
+ export type { ApitemplateApiTemplate, ApitemplateExport, ApitemplateListItem, ApitemplateRegion } from './lib/import/apitemplate.cjs';
10
13
  export type { ImportNote, ImportResult, ImportSource } from './lib/import/common.cjs';
11
14
  export { importPdfmonkey, strftimeToDateFns } from './lib/import/pdfmonkey.cjs';
12
15
  export type { PdfmonkeyImportOptions, PdfmonkeySettings, PdfmonkeyTemplate } from './lib/import/pdfmonkey.cjs';
13
16
  export { importJsreport, jsreportTemplates, readJsreportExport } from './lib/import/jsreport.cjs';
14
17
  export type { JsreportBundle, JsreportImportOptions, JsreportTemplate } from './lib/import/jsreport.cjs';
15
18
  export { convertScss, isScss } from './lib/import/scss.cjs';
16
- export type { Snippet } from './lib/snippets.cjs';
17
- export type { JsonSchema } from './lib/schema.cjs';
18
- export { assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.cjs';
19
+ export type { Snippet, SnippetGroup } from './lib/snippets.cjs';
20
+ export type { JsonSchema, SchemaChange, SchemaChangeKind, SchemaDiff } from './lib/schema.cjs';
21
+ export { DEFAULT_CHROME_PADDING, assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.cjs';
19
22
  export type { ChartSpec, ImageOptions } from './lib/helpers/index.cjs';
20
- export { flowDocument, pagedDocument, pageNumberSpans, paperOf } from './lib/preview.cjs';
23
+ export { flowDocument, pagedDocument, pageNumberSpans, paperOf, zoomGestureScript } from './lib/preview.cjs';
21
24
  export type { PagedOptions, RenderedDraft } from './lib/preview.cjs';
22
- export type { AssembleExtras, AssembleInput, AssembleVendor, FontFace, RenderedDocument, TemplateKind, TemplateSettings, VersionSource, } from './lib/assemble.cjs';
25
+ export { annotateSourcePositions, parseSourceAttribute, sourceAttribute, } from './lib/source-positions.cjs';
26
+ export type { SourceFile, SourceLocation } from './lib/source-positions.cjs';
27
+ export type { AssembleExtras, AssembleInput, AssembleVendor, FontFace, HeaderFooterSettings, RenderedDocument, TemplateKind, TemplateSettings, VersionSource, } from './lib/assemble.cjs';
23
28
  export { resolvePath, scanBlocks, jinjaTags, liquidTags, } from './lib/analysis/tags.cjs';
29
+ export { OFFICE_FILLED_MAX_BYTES, OfficeTemplateError, analyzeOffice, officeTextParts, renderOffice, type OfficeAnalysis, type OfficeAnalysisDiagnostic, type OfficeRenderOptions, type OfficeRenderResult, } from './lib/office/render.cjs';
30
+ export type { OfficeTag } from './lib/office/tags.cjs';
31
+ export { starterDocument } from './lib/office/starter.cjs';
32
+ export { starterPresentation } from './lib/office/starter-pptx.cjs';
33
+ export { officeDrawingLimits, type OfficeImageHost } from './lib/office/drawings.cjs';
package/types/index.d.ts CHANGED
@@ -3,21 +3,31 @@ export { EngineSyntaxError, RenderError, RenderLimitError } from './lib/errors.j
3
3
  export { defaultLimits, depthGuard, enforceLimits } from './lib/limits.js';
4
4
  export { DefaultHelperRegistry, builtinHelpers, chartMarkup, chartPayload, createHelperRegistry, defaultHelpers, epcPayload, escapeHtml, helperDocs, imageMarkup, qrSvg, toDate, toNumber, } from './lib/helpers/index.js';
5
5
  export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, getEngine, handlebarsEngine, jinja2Engine, liquidEngine, liquidBuiltinFilters, nunjucksBuiltinFilters, } from './lib/engines/index.js';
6
- export { inferSchema, schemaPaths } from './lib/schema.js';
7
- export { mergeSampleData, snippets, snippetsFor } from './lib/snippets.js';
8
- export { importApitemplate, slugFromName } from './lib/import/apitemplate.js';
9
- export type { ApitemplateExport } from './lib/import/apitemplate.js';
6
+ export { diffSchemas, inferSchema, inferSchemaFromDataSets, schemaPaths } from './lib/schema.js';
7
+ export { defaultOutput, imageOutput, isOfficeKind, isOutputFormat, officeKinds, outputFormats, outputsForKind, type OfficeKind, type OutputFormat, } from './lib/output.js';
8
+ export { brandCss, emptyBrand, layeredPartials, normalisePartialName } from './lib/brand.js';
9
+ export type { BrandContext, SharedPartial } from './lib/brand.js';
10
+ export { mergeSampleData, mergeSnippetCss, mergeSnippetI18n, partialInclude, snippets, snippetsFor, snippetText, } from './lib/snippets.js';
11
+ export { apitemplateRegions, importApitemplate, importApitemplateFromApi, isApitemplateHtmlTemplate, isApitemplateRegion, slugFromName, splitApitemplateCss, } from './lib/import/apitemplate.js';
12
+ export type { ApitemplateApiTemplate, ApitemplateExport, ApitemplateListItem, ApitemplateRegion } from './lib/import/apitemplate.js';
10
13
  export type { ImportNote, ImportResult, ImportSource } from './lib/import/common.js';
11
14
  export { importPdfmonkey, strftimeToDateFns } from './lib/import/pdfmonkey.js';
12
15
  export type { PdfmonkeyImportOptions, PdfmonkeySettings, PdfmonkeyTemplate } from './lib/import/pdfmonkey.js';
13
16
  export { importJsreport, jsreportTemplates, readJsreportExport } from './lib/import/jsreport.js';
14
17
  export type { JsreportBundle, JsreportImportOptions, JsreportTemplate } from './lib/import/jsreport.js';
15
18
  export { convertScss, isScss } from './lib/import/scss.js';
16
- export type { Snippet } from './lib/snippets.js';
17
- export type { JsonSchema } from './lib/schema.js';
18
- export { assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.js';
19
+ export type { Snippet, SnippetGroup } from './lib/snippets.js';
20
+ export type { JsonSchema, SchemaChange, SchemaChangeKind, SchemaDiff } from './lib/schema.js';
21
+ export { DEFAULT_CHROME_PADDING, assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.js';
19
22
  export type { ChartSpec, ImageOptions } from './lib/helpers/index.js';
20
- export { flowDocument, pagedDocument, pageNumberSpans, paperOf } from './lib/preview.js';
23
+ export { flowDocument, pagedDocument, pageNumberSpans, paperOf, zoomGestureScript } from './lib/preview.js';
21
24
  export type { PagedOptions, RenderedDraft } from './lib/preview.js';
22
- export type { AssembleExtras, AssembleInput, AssembleVendor, FontFace, RenderedDocument, TemplateKind, TemplateSettings, VersionSource, } from './lib/assemble.js';
25
+ export { annotateSourcePositions, parseSourceAttribute, sourceAttribute, } from './lib/source-positions.js';
26
+ export type { SourceFile, SourceLocation } from './lib/source-positions.js';
27
+ export type { AssembleExtras, AssembleInput, AssembleVendor, FontFace, HeaderFooterSettings, RenderedDocument, TemplateKind, TemplateSettings, VersionSource, } from './lib/assemble.js';
23
28
  export { resolvePath, scanBlocks, jinjaTags, liquidTags, } from './lib/analysis/tags.js';
29
+ export { OFFICE_FILLED_MAX_BYTES, OfficeTemplateError, analyzeOffice, officeTextParts, renderOffice, type OfficeAnalysis, type OfficeAnalysisDiagnostic, type OfficeRenderOptions, type OfficeRenderResult, } from './lib/office/render.js';
30
+ export type { OfficeTag } from './lib/office/tags.js';
31
+ export { starterDocument } from './lib/office/starter.js';
32
+ export { starterPresentation } from './lib/office/starter-pptx.js';
33
+ export { officeDrawingLimits, type OfficeImageHost } from './lib/office/drawings.js';
@@ -1,5 +1,13 @@
1
+ import type { BrandContext } from './brand.cjs';
1
2
  import type { EngineId, RenderContext } from './types.cjs';
2
3
  /** Template settings (spec 01 §3); every field optional, `defaultSettings()` fills the rest. */
4
+ export interface HeaderFooterSettings {
5
+ html?: string;
6
+ height?: string;
7
+ padding?: string;
8
+ }
9
+ /** The side padding Formfeed gives header and footer unless the template sets its own. */
10
+ export declare const DEFAULT_CHROME_PADDING = "0 10mm";
3
11
  export interface TemplateSettings {
4
12
  paper?: {
5
13
  format?: string;
@@ -14,14 +22,12 @@ export interface TemplateSettings {
14
22
  bottom?: string;
15
23
  left?: string;
16
24
  };
17
- header?: {
18
- html?: string;
19
- height?: string;
20
- } | null;
21
- footer?: {
22
- html?: string;
23
- height?: string;
24
- } | null;
25
+ /**
26
+ * Header and footer span the full page width, as Chromium prints them; `padding` is the space
27
+ * inside that box (CSS shorthand, default `0 10mm`, `0` for designs that run edge to edge).
28
+ */
29
+ header?: HeaderFooterSettings | null;
30
+ footer?: HeaderFooterSettings | null;
25
31
  printBackground?: boolean;
26
32
  scale?: number;
27
33
  preferCssPageSize?: boolean;
@@ -52,6 +58,10 @@ export interface TemplateSettings {
52
58
  transparent?: boolean;
53
59
  clipSelector?: string | null;
54
60
  };
61
+ /** Office templates (spec 22 §4.1): the output when a request names none. */
62
+ office?: {
63
+ output?: 'docx' | 'pptx' | 'pdf';
64
+ };
55
65
  locale?: string;
56
66
  timezone?: string;
57
67
  currency?: string;
@@ -67,7 +77,10 @@ export declare function defaultSettings(): Required<Pick<TemplateSettings, 'pape
67
77
  export declare function mergeSettings(...layers: Array<TemplateSettings | null | undefined>): TemplateSettings;
68
78
  /** `@page` size expression from the paper settings. */
69
79
  export declare function pageSize(settings: TemplateSettings): string;
70
- /** Default print reset of spec 05 §5. */
80
+ /**
81
+ * Default print reset of spec 05 §5. Its element rules sit in `:where()`, so any rule of the template
82
+ * wins over them, as it did when the template's styles simply came later.
83
+ */
71
84
  export declare function printReset(settings: TemplateSettings, kind?: TemplateKind): string;
72
85
  /** An organisation font (spec 05 §6) reachable by URL from the preview frame or the worker. */
73
86
  export interface FontFace {
@@ -113,6 +126,8 @@ export interface AssembleInput extends AssembleExtras {
113
126
  kind?: TemplateKind;
114
127
  /** Base URL for relative asset references (`<base href>`); omitted when undefined. */
115
128
  assetBaseUrl?: string;
129
+ /** Brand kit whose `--brand-*` variables go before the reset and the template CSS (spec 18 §2.2). */
130
+ brand?: BrandContext;
116
131
  /** Preview marks the document so the preview frame can style it; print is what Chromium gets. */
117
132
  mode?: 'preview' | 'print';
118
133
  title?: string;
@@ -1,5 +1,13 @@
1
+ import type { BrandContext } from './brand.js';
1
2
  import type { EngineId, RenderContext } from './types.js';
2
3
  /** Template settings (spec 01 §3); every field optional, `defaultSettings()` fills the rest. */
4
+ export interface HeaderFooterSettings {
5
+ html?: string;
6
+ height?: string;
7
+ padding?: string;
8
+ }
9
+ /** The side padding Formfeed gives header and footer unless the template sets its own. */
10
+ export declare const DEFAULT_CHROME_PADDING = "0 10mm";
3
11
  export interface TemplateSettings {
4
12
  paper?: {
5
13
  format?: string;
@@ -14,14 +22,12 @@ export interface TemplateSettings {
14
22
  bottom?: string;
15
23
  left?: string;
16
24
  };
17
- header?: {
18
- html?: string;
19
- height?: string;
20
- } | null;
21
- footer?: {
22
- html?: string;
23
- height?: string;
24
- } | null;
25
+ /**
26
+ * Header and footer span the full page width, as Chromium prints them; `padding` is the space
27
+ * inside that box (CSS shorthand, default `0 10mm`, `0` for designs that run edge to edge).
28
+ */
29
+ header?: HeaderFooterSettings | null;
30
+ footer?: HeaderFooterSettings | null;
25
31
  printBackground?: boolean;
26
32
  scale?: number;
27
33
  preferCssPageSize?: boolean;
@@ -52,6 +58,10 @@ export interface TemplateSettings {
52
58
  transparent?: boolean;
53
59
  clipSelector?: string | null;
54
60
  };
61
+ /** Office templates (spec 22 §4.1): the output when a request names none. */
62
+ office?: {
63
+ output?: 'docx' | 'pptx' | 'pdf';
64
+ };
55
65
  locale?: string;
56
66
  timezone?: string;
57
67
  currency?: string;
@@ -67,7 +77,10 @@ export declare function defaultSettings(): Required<Pick<TemplateSettings, 'pape
67
77
  export declare function mergeSettings(...layers: Array<TemplateSettings | null | undefined>): TemplateSettings;
68
78
  /** `@page` size expression from the paper settings. */
69
79
  export declare function pageSize(settings: TemplateSettings): string;
70
- /** Default print reset of spec 05 §5. */
80
+ /**
81
+ * Default print reset of spec 05 §5. Its element rules sit in `:where()`, so any rule of the template
82
+ * wins over them, as it did when the template's styles simply came later.
83
+ */
71
84
  export declare function printReset(settings: TemplateSettings, kind?: TemplateKind): string;
72
85
  /** An organisation font (spec 05 §6) reachable by URL from the preview frame or the worker. */
73
86
  export interface FontFace {
@@ -113,6 +126,8 @@ export interface AssembleInput extends AssembleExtras {
113
126
  kind?: TemplateKind;
114
127
  /** Base URL for relative asset references (`<base href>`); omitted when undefined. */
115
128
  assetBaseUrl?: string;
129
+ /** Brand kit whose `--brand-*` variables go before the reset and the template CSS (spec 18 §2.2). */
130
+ brand?: BrandContext;
116
131
  /** Preview marks the document so the preview frame can style it; print is what Chromium gets. */
117
132
  mode?: 'preview' | 'print';
118
133
  title?: string;
@@ -0,0 +1,46 @@
1
+ import type { PartialResolver } from './types.cjs';
2
+ /**
3
+ * The organisation's brand kit as a template sees it (spec 18 §2.1): `brand.colors.primary`,
4
+ * `brand.logo.mark`, `brand.legal_footer`. Unset values are `null`; `colors` is always an object.
5
+ */
6
+ export interface BrandContext {
7
+ version: number;
8
+ name: string | null;
9
+ colors: Record<string, string>;
10
+ fonts: {
11
+ heading: string | null;
12
+ body: string | null;
13
+ };
14
+ font_size: string | null;
15
+ logo: {
16
+ primary: string | null;
17
+ inverse: string | null;
18
+ mark: string | null;
19
+ };
20
+ legal_footer: string | null;
21
+ }
22
+ /** The `brand` of an organisation that has set nothing, and of local renders without a pulled kit. */
23
+ export declare function emptyBrand(): BrandContext;
24
+ /**
25
+ * The `--brand-*` custom properties of spec 18 §2.2. Values are validated again here, because the
26
+ * stylesheet sits in a `<style>` element and a kit from a pulled file or an old cache is still input.
27
+ */
28
+ export declare function brandCss(brand: BrandContext | undefined): string;
29
+ /** The family names a kit names, so `fontFaceCss` injects their faces even behind `var(--brand-font-*)`. */
30
+ export declare function brandFontFamilies(brand: BrandContext | undefined): string;
31
+ /**
32
+ * The name a shared partial is matched by (spec 18 §2.3): lowercase, one template file extension
33
+ * removed. `@formfeed/api-types` and the database (`private.normalise_partial_name`) keep copies.
34
+ */
35
+ export declare function normalisePartialName(name: string): string;
36
+ /** A shared partial as hosts pass it: its source and the version a render records. */
37
+ export interface SharedPartial {
38
+ source: string;
39
+ version: number;
40
+ }
41
+ /**
42
+ * One resolver over both kinds of partial: the version's own by exact name first, then the
43
+ * organisation's shared ones by normalised name. `onShared` hears every shared partial that was
44
+ * actually read, which is what the render-worker records for reproducibility.
45
+ */
46
+ export declare function layeredPartials(own: Record<string, string> | undefined, shared: Record<string, SharedPartial> | undefined, onShared?: (name: string, partial: SharedPartial) => void): PartialResolver;
@@ -0,0 +1,46 @@
1
+ import type { PartialResolver } from './types.js';
2
+ /**
3
+ * The organisation's brand kit as a template sees it (spec 18 §2.1): `brand.colors.primary`,
4
+ * `brand.logo.mark`, `brand.legal_footer`. Unset values are `null`; `colors` is always an object.
5
+ */
6
+ export interface BrandContext {
7
+ version: number;
8
+ name: string | null;
9
+ colors: Record<string, string>;
10
+ fonts: {
11
+ heading: string | null;
12
+ body: string | null;
13
+ };
14
+ font_size: string | null;
15
+ logo: {
16
+ primary: string | null;
17
+ inverse: string | null;
18
+ mark: string | null;
19
+ };
20
+ legal_footer: string | null;
21
+ }
22
+ /** The `brand` of an organisation that has set nothing, and of local renders without a pulled kit. */
23
+ export declare function emptyBrand(): BrandContext;
24
+ /**
25
+ * The `--brand-*` custom properties of spec 18 §2.2. Values are validated again here, because the
26
+ * stylesheet sits in a `<style>` element and a kit from a pulled file or an old cache is still input.
27
+ */
28
+ export declare function brandCss(brand: BrandContext | undefined): string;
29
+ /** The family names a kit names, so `fontFaceCss` injects their faces even behind `var(--brand-font-*)`. */
30
+ export declare function brandFontFamilies(brand: BrandContext | undefined): string;
31
+ /**
32
+ * The name a shared partial is matched by (spec 18 §2.3): lowercase, one template file extension
33
+ * removed. `@formfeed/api-types` and the database (`private.normalise_partial_name`) keep copies.
34
+ */
35
+ export declare function normalisePartialName(name: string): string;
36
+ /** A shared partial as hosts pass it: its source and the version a render records. */
37
+ export interface SharedPartial {
38
+ source: string;
39
+ version: number;
40
+ }
41
+ /**
42
+ * One resolver over both kinds of partial: the version's own by exact name first, then the
43
+ * organisation's shared ones by normalised name. `onShared` hears every shared partial that was
44
+ * actually read, which is what the render-worker records for reproducibility.
45
+ */
46
+ export declare function layeredPartials(own: Record<string, string> | undefined, shared: Record<string, SharedPartial> | undefined, onShared?: (name: string, partial: SharedPartial) => void): PartialResolver;
@@ -10,7 +10,31 @@ export interface ChartSpec {
10
10
  options?: Record<string, unknown>;
11
11
  width?: number | string;
12
12
  height?: number | string;
13
+ /** Plain data instead of `data`: one label per point, with `values` or several `series`. */
14
+ labels?: unknown[];
15
+ values?: unknown[];
16
+ /** Name of the single `values` series; without one the legend is hidden. */
17
+ label?: string;
18
+ /** Colour of the single series; a list colours pie and doughnut slices one by one. */
19
+ color?: string | string[];
20
+ series?: ChartSeries[];
13
21
  }
22
+ export interface ChartSeries {
23
+ label?: string;
24
+ values?: unknown[];
25
+ color?: string | string[];
26
+ }
27
+ /** Colours for series and slices that name none. */
28
+ export declare const CHART_PALETTE: string[];
29
+ /**
30
+ * Chart.js `data` from plain data, so a template can chart `{ labels, values }` from a request
31
+ * without the caller knowing Chart.js. Values become numbers (anything else a gap); a series
32
+ * without a colour takes the next palette colour, and each slice of a pie or doughnut its own.
33
+ */
34
+ export declare function chartDataFromPlain(spec: ChartSpec): {
35
+ datasets: Record<string, unknown>[];
36
+ labels: unknown[];
37
+ };
14
38
  export interface ImageOptions {
15
39
  width?: number | string;
16
40
  height?: number | string;
@@ -10,7 +10,31 @@ export interface ChartSpec {
10
10
  options?: Record<string, unknown>;
11
11
  width?: number | string;
12
12
  height?: number | string;
13
+ /** Plain data instead of `data`: one label per point, with `values` or several `series`. */
14
+ labels?: unknown[];
15
+ values?: unknown[];
16
+ /** Name of the single `values` series; without one the legend is hidden. */
17
+ label?: string;
18
+ /** Colour of the single series; a list colours pie and doughnut slices one by one. */
19
+ color?: string | string[];
20
+ series?: ChartSeries[];
13
21
  }
22
+ export interface ChartSeries {
23
+ label?: string;
24
+ values?: unknown[];
25
+ color?: string | string[];
26
+ }
27
+ /** Colours for series and slices that name none. */
28
+ export declare const CHART_PALETTE: string[];
29
+ /**
30
+ * Chart.js `data` from plain data, so a template can chart `{ labels, values }` from a request
31
+ * without the caller knowing Chart.js. Values become numbers (anything else a gap); a series
32
+ * without a colour takes the next palette colour, and each slice of a pie or doughnut its own.
33
+ */
34
+ export declare function chartDataFromPlain(spec: ChartSpec): {
35
+ datasets: Record<string, unknown>[];
36
+ labels: unknown[];
37
+ };
14
38
  export interface ImageOptions {
15
39
  width?: number | string;
16
40
  height?: number | string;
@@ -4,6 +4,7 @@ export { DefaultHelperRegistry } from './registry.cjs';
4
4
  export { escapeHtml, toDate, toNumber } from './format.cjs';
5
5
  export { epcPayload, qrSvg } from './codes.cjs';
6
6
  export { chartMarkup, chartPayload, imageMarkup } from './document.cjs';
7
+ export { officeUnsupported, officeUnsupportedHelpers } from './office.cjs';
7
8
  export type { ChartSpec, ImageOptions } from './document.cjs';
8
9
  /** Helpers shipped with the product (spec 05 §2), identical in all three engines. */
9
10
  export declare const builtinHelpers: HelperDefinition[];
@@ -4,6 +4,7 @@ export { DefaultHelperRegistry } from './registry.js';
4
4
  export { escapeHtml, toDate, toNumber } from './format.js';
5
5
  export { epcPayload, qrSvg } from './codes.js';
6
6
  export { chartMarkup, chartPayload, imageMarkup } from './document.js';
7
+ export { officeUnsupported, officeUnsupportedHelpers } from './office.js';
7
8
  export type { ChartSpec, ImageOptions } from './document.js';
8
9
  /** Helpers shipped with the product (spec 05 §2), identical in all three engines. */
9
10
  export declare const builtinHelpers: HelperDefinition[];
@@ -0,0 +1,4 @@
1
+ /** Helpers that return HTML and have no office form yet (spec 22 §4.4). */
2
+ export declare const officeUnsupportedHelpers: ReadonlySet<string>;
3
+ /** The message those helpers fail with in office mode. */
4
+ export declare function officeUnsupported(name: string): string;
@@ -0,0 +1,4 @@
1
+ /** Helpers that return HTML and have no office form yet (spec 22 §4.4). */
2
+ export declare const officeUnsupportedHelpers: ReadonlySet<string>;
3
+ /** The message those helpers fail with in office mode. */
4
+ export declare function officeUnsupported(name: string): string;
@@ -18,4 +18,64 @@ export interface ApitemplateExport {
18
18
  /** Their template format; JPEG and PNG become image templates. */
19
19
  format?: string | null;
20
20
  }
21
+ /**
22
+ * apitemplate.io puts its CSS field into the document head as is, so it often carries `<link>`,
23
+ * `<script>` and `<style>` tags. Formfeed wraps CSS in a `<style>` element, where such tags break
24
+ * the stylesheet and never load: style blocks become CSS, the rest of the markup goes to the head.
25
+ */
26
+ export declare function splitApitemplateCss(source: string): {
27
+ css: string;
28
+ head: string;
29
+ };
21
30
  export declare function importApitemplate(input: ApitemplateExport): ImportResult;
31
+ /**
32
+ * apitemplate.io's regional API hosts (their "Regional API endpoints"). The key works in the
33
+ * region its account lives in; the importer only ever contacts these hosts.
34
+ */
35
+ export declare const apitemplateRegions: {
36
+ readonly default: "https://rest.apitemplate.io";
37
+ readonly de: "https://rest-de.apitemplate.io";
38
+ readonly us: "https://rest-us.apitemplate.io";
39
+ readonly au: "https://rest-au.apitemplate.io";
40
+ readonly alt: "https://rest-alt.apitemplate.io";
41
+ readonly 'alt-de': "https://rest-alt-de.apitemplate.io";
42
+ readonly 'alt-us': "https://rest-alt-us.apitemplate.io";
43
+ };
44
+ export type ApitemplateRegion = keyof typeof apitemplateRegions;
45
+ export declare function isApitemplateRegion(value: unknown): value is ApitemplateRegion;
46
+ /** One entry of `GET /v2/list-templates`. */
47
+ export interface ApitemplateListItem {
48
+ template_id: string;
49
+ name?: string | null;
50
+ status?: string | null;
51
+ /** `PDF` or `JPEG`. */
52
+ format?: string | null;
53
+ created_at?: string | null;
54
+ updated_at?: string | null;
55
+ group_name?: string | null;
56
+ }
57
+ /**
58
+ * `GET /v2/get-template` (experimental on their side): the HTML body, CSS, print settings and the
59
+ * editor's sample JSON (`sample_json`, not in their API reference but in the answer).
60
+ */
61
+ export interface ApitemplateApiTemplate {
62
+ status?: string | null;
63
+ template_id?: string | null;
64
+ body?: string | null;
65
+ css?: string | null;
66
+ /** A JSON string in their API; an object is accepted too. */
67
+ settings?: string | Record<string, unknown> | null;
68
+ /** The JSON of their editor's JSON tab, as a string; an object is accepted too. */
69
+ sample_json?: string | Record<string, unknown> | null;
70
+ }
71
+ /**
72
+ * Only PDF templates carry HTML; apitemplate.io's image templates are layer designs that
73
+ * `get-template` does not return.
74
+ */
75
+ export declare function isApitemplateHtmlTemplate(item: Pick<ApitemplateListItem, 'format'>): boolean;
76
+ /**
77
+ * Converts a template read through apitemplate.io's API, sample JSON included. A template without
78
+ * a body (an image template, or an editor the API does not serve) becomes a result with an error
79
+ * and no HTML, which callers skip.
80
+ */
81
+ export declare function importApitemplateFromApi(item: ApitemplateListItem, template: ApitemplateApiTemplate): ImportResult;
@@ -18,4 +18,64 @@ export interface ApitemplateExport {
18
18
  /** Their template format; JPEG and PNG become image templates. */
19
19
  format?: string | null;
20
20
  }
21
+ /**
22
+ * apitemplate.io puts its CSS field into the document head as is, so it often carries `<link>`,
23
+ * `<script>` and `<style>` tags. Formfeed wraps CSS in a `<style>` element, where such tags break
24
+ * the stylesheet and never load: style blocks become CSS, the rest of the markup goes to the head.
25
+ */
26
+ export declare function splitApitemplateCss(source: string): {
27
+ css: string;
28
+ head: string;
29
+ };
21
30
  export declare function importApitemplate(input: ApitemplateExport): ImportResult;
31
+ /**
32
+ * apitemplate.io's regional API hosts (their "Regional API endpoints"). The key works in the
33
+ * region its account lives in; the importer only ever contacts these hosts.
34
+ */
35
+ export declare const apitemplateRegions: {
36
+ readonly default: "https://rest.apitemplate.io";
37
+ readonly de: "https://rest-de.apitemplate.io";
38
+ readonly us: "https://rest-us.apitemplate.io";
39
+ readonly au: "https://rest-au.apitemplate.io";
40
+ readonly alt: "https://rest-alt.apitemplate.io";
41
+ readonly 'alt-de': "https://rest-alt-de.apitemplate.io";
42
+ readonly 'alt-us': "https://rest-alt-us.apitemplate.io";
43
+ };
44
+ export type ApitemplateRegion = keyof typeof apitemplateRegions;
45
+ export declare function isApitemplateRegion(value: unknown): value is ApitemplateRegion;
46
+ /** One entry of `GET /v2/list-templates`. */
47
+ export interface ApitemplateListItem {
48
+ template_id: string;
49
+ name?: string | null;
50
+ status?: string | null;
51
+ /** `PDF` or `JPEG`. */
52
+ format?: string | null;
53
+ created_at?: string | null;
54
+ updated_at?: string | null;
55
+ group_name?: string | null;
56
+ }
57
+ /**
58
+ * `GET /v2/get-template` (experimental on their side): the HTML body, CSS, print settings and the
59
+ * editor's sample JSON (`sample_json`, not in their API reference but in the answer).
60
+ */
61
+ export interface ApitemplateApiTemplate {
62
+ status?: string | null;
63
+ template_id?: string | null;
64
+ body?: string | null;
65
+ css?: string | null;
66
+ /** A JSON string in their API; an object is accepted too. */
67
+ settings?: string | Record<string, unknown> | null;
68
+ /** The JSON of their editor's JSON tab, as a string; an object is accepted too. */
69
+ sample_json?: string | Record<string, unknown> | null;
70
+ }
71
+ /**
72
+ * Only PDF templates carry HTML; apitemplate.io's image templates are layer designs that
73
+ * `get-template` does not return.
74
+ */
75
+ export declare function isApitemplateHtmlTemplate(item: Pick<ApitemplateListItem, 'format'>): boolean;
76
+ /**
77
+ * Converts a template read through apitemplate.io's API, sample JSON included. A template without
78
+ * a body (an image template, or an editor the API does not serve) becomes a result with an error
79
+ * and no HTML, which callers skip.
80
+ */
81
+ export declare function importApitemplateFromApi(item: ApitemplateListItem, template: ApitemplateApiTemplate): ImportResult;
@@ -0,0 +1,36 @@
1
+ import { type ZipArchive } from './zip.cjs';
2
+ /**
3
+ * What a customer file is, decided from its bytes (spec 22 §3.2). Gotenberg picks LibreOffice's
4
+ * import filter by extension, so the worker sends every file under the extension found here and the
5
+ * customer's own file name never reaches the sidecar.
6
+ */
7
+ export declare const officeFormats: readonly ["docx", "xlsx", "pptx", "odt", "ods", "odp", "doc", "xls", "ppt", "rtf", "html"];
8
+ export type OfficeFormat = (typeof officeFormats)[number];
9
+ export type OoxmlFormat = 'docx' | 'xlsx' | 'pptx';
10
+ export type OdfFormat = 'odt' | 'ods' | 'odp';
11
+ export declare const officeContentTypes: Record<OfficeFormat, string>;
12
+ export interface DetectedOffice {
13
+ format: OfficeFormat;
14
+ /** The parsed container for ZIP-based formats, so callers do not read it twice. */
15
+ archive: ZipArchive | null;
16
+ }
17
+ export declare function detectOfficeFormat(bytes: Uint8Array): DetectedOffice;
18
+ /**
19
+ * VBA projects in OOXML; Basic modules and scripts in ODF. LibreOffice may write the library
20
+ * descriptors `Basic/script-lc.xml` and `script-lb.xml` into documents without any macro, so only a
21
+ * module beside them counts.
22
+ */
23
+ export declare function isMacroPart(name: string): boolean;
24
+ /** A DOCTYPE anywhere in the text (entity expansion); the text is already decoded, UTF-16 included. */
25
+ export declare function hasDoctype(xml: string): boolean;
26
+ /**
27
+ * HTML: a BOM, whitespace, comments and an XML declaration may come first, then `<!DOCTYPE html>` or
28
+ * `<html>`. Deliberately narrow, so an SVG, an XML file or a text file is still refused.
29
+ */
30
+ export declare function isHtml(bytes: Uint8Array): boolean;
31
+ /**
32
+ * Legacy binary formats and encrypted OOXML share the Compound File container. Its directory names
33
+ * the streams, and they tell the formats apart: `EncryptionInfo` is an encrypted OOXML package,
34
+ * `WordDocument` a Word 97–2003 file, `Workbook` or `Book` Excel, `PowerPoint Document` PowerPoint.
35
+ */
36
+ export declare function cfbStreamNames(bytes: Uint8Array): string[];
@@ -0,0 +1,36 @@
1
+ import { type ZipArchive } from './zip.js';
2
+ /**
3
+ * What a customer file is, decided from its bytes (spec 22 §3.2). Gotenberg picks LibreOffice's
4
+ * import filter by extension, so the worker sends every file under the extension found here and the
5
+ * customer's own file name never reaches the sidecar.
6
+ */
7
+ export declare const officeFormats: readonly ["docx", "xlsx", "pptx", "odt", "ods", "odp", "doc", "xls", "ppt", "rtf", "html"];
8
+ export type OfficeFormat = (typeof officeFormats)[number];
9
+ export type OoxmlFormat = 'docx' | 'xlsx' | 'pptx';
10
+ export type OdfFormat = 'odt' | 'ods' | 'odp';
11
+ export declare const officeContentTypes: Record<OfficeFormat, string>;
12
+ export interface DetectedOffice {
13
+ format: OfficeFormat;
14
+ /** The parsed container for ZIP-based formats, so callers do not read it twice. */
15
+ archive: ZipArchive | null;
16
+ }
17
+ export declare function detectOfficeFormat(bytes: Uint8Array): DetectedOffice;
18
+ /**
19
+ * VBA projects in OOXML; Basic modules and scripts in ODF. LibreOffice may write the library
20
+ * descriptors `Basic/script-lc.xml` and `script-lb.xml` into documents without any macro, so only a
21
+ * module beside them counts.
22
+ */
23
+ export declare function isMacroPart(name: string): boolean;
24
+ /** A DOCTYPE anywhere in the text (entity expansion); the text is already decoded, UTF-16 included. */
25
+ export declare function hasDoctype(xml: string): boolean;
26
+ /**
27
+ * HTML: a BOM, whitespace, comments and an XML declaration may come first, then `<!DOCTYPE html>` or
28
+ * `<html>`. Deliberately narrow, so an SVG, an XML file or a text file is still refused.
29
+ */
30
+ export declare function isHtml(bytes: Uint8Array): boolean;
31
+ /**
32
+ * Legacy binary formats and encrypted OOXML share the Compound File container. Its directory names
33
+ * the streams, and they tell the formats apart: `EncryptionInfo` is an encrypted OOXML package,
34
+ * `WordDocument` a Word 97–2003 file, `Workbook` or `Book` Excel, `PowerPoint Document` PowerPoint.
35
+ */
36
+ export declare function cfbStreamNames(bytes: Uint8Array): string[];