@formfeed/sdk 0.1.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.
@@ -6,7 +6,11 @@
6
6
  */
7
7
  export type Region = 'eu' | 'us';
8
8
  export type Engine = 'jinja2' | 'liquid' | 'handlebars';
9
- export type OutputFormat = 'pdf' | 'png' | 'jpg' | 'webp';
9
+ /**
10
+ * PDF and image templates, HTML and URLs produce `pdf` or an image; a Word template produces `docx`
11
+ * or `pdf`, a PowerPoint template `pptx` or `pdf`.
12
+ */
13
+ export type OutputFormat = 'pdf' | 'png' | 'jpg' | 'webp' | 'docx' | 'pptx';
10
14
  export type RenderStatus = 'queued' | 'rendering' | 'succeeded' | 'failed';
11
15
  export interface FormfeedOptions {
12
16
  apiKey: string;
@@ -26,6 +30,7 @@ export interface RenderRequest {
26
30
  url?: string;
27
31
  engine?: Engine;
28
32
  data?: Record<string, unknown>;
33
+ /** Left out, the template decides: PDF, or an image template's `settings.image.format`. */
29
34
  output?: OutputFormat;
30
35
  settings?: Record<string, unknown>;
31
36
  filename?: string;
@@ -34,9 +39,90 @@ export interface RenderRequest {
34
39
  mode?: 'sync' | 'async';
35
40
  locale?: string | null;
36
41
  webhook_url?: string | null;
42
+ /** Signs the deliveries to `webhook_url`, the way an endpoint secret does; 16 to 200 characters. */
43
+ webhook_secret?: string | null;
37
44
  meta?: Record<string, unknown>;
38
45
  region?: Region;
39
46
  dedupe?: boolean;
47
+ /**
48
+ * Decides a channel's canary split: renders with the same value (a customer or order id) land on the
49
+ * same version. Not the Idempotency-Key, which would replay the first response for every render.
50
+ */
51
+ canary_key?: string | null;
52
+ /** PDF post-processing: merge, watermark, password, applied in that order (0.5 units each). */
53
+ post?: PostProcessing | null;
54
+ /** Check `data` against the template's stored schema first; a mismatch throws `data_validation_error`. */
55
+ validate_data?: boolean;
56
+ }
57
+ /**
58
+ * Slug → data type of the workspace's templates. Empty here; the file `formfeed types` generates
59
+ * augments it (`declare module '@formfeed/sdk' { interface FormfeedTemplates { invoice: InvoiceData } }`),
60
+ * which makes `renders.create({ template: 'invoice', data })` check `data` at compile time.
61
+ */
62
+ export interface FormfeedTemplates {
63
+ }
64
+ /** The data type of template `T`: generated for known slugs, a plain record otherwise. */
65
+ export type TemplateData<T> = T extends keyof FormfeedTemplates ? FormfeedTemplates[T] : Record<string, unknown>;
66
+ /**
67
+ * A render request whose `data` follows the template's generated type. A slug the generated file
68
+ * does not know, a template id or a string variable keeps the untyped `Record<string, unknown>`.
69
+ */
70
+ export type TypedRenderRequest<T extends string = string> = Omit<RenderRequest, 'template' | 'data'> & {
71
+ template?: T;
72
+ } & (T extends keyof FormfeedTemplates ? {
73
+ data: FormfeedTemplates[T];
74
+ } : {
75
+ data?: Record<string, unknown>;
76
+ });
77
+ export type PdfPermission = 'print' | 'copy' | 'modify' | 'annotate';
78
+ /** A text or an image watermark; pass one of `text` and `image`. */
79
+ export interface WatermarkOptions {
80
+ text?: string;
81
+ /** A PNG or JPEG of the workspace file library: its id (`fil_…`) or its name. */
82
+ image?: string;
83
+ /** 0 to 1, default 0.2. */
84
+ opacity?: number;
85
+ /** Degrees clockwise as in CSS, default -45 (bottom left to top right). */
86
+ rotation?: number;
87
+ /** Hex colour such as `#cc0000`; grey by default. Text only. */
88
+ color?: string;
89
+ }
90
+ export interface PostProcessing {
91
+ /** PDFs appended after this document, in order: render ids, or file ids and names of library PDFs. */
92
+ merge_after?: string[];
93
+ watermark?: WatermarkOptions;
94
+ password?: {
95
+ user?: string;
96
+ owner?: string;
97
+ permissions?: PdfPermission[];
98
+ };
99
+ }
100
+ /** Where the result of a PDF tool is stored, as for a render. */
101
+ export interface PdfOutputOptions {
102
+ filename?: string;
103
+ expires_in?: number | null;
104
+ access?: 'public' | 'signed';
105
+ meta?: Record<string, unknown>;
106
+ }
107
+ export interface ProtectOptions extends PdfOutputOptions {
108
+ /** Needed to open the document. */
109
+ user_password?: string;
110
+ /** Lifts the restrictions; random when omitted. */
111
+ owner_password?: string;
112
+ /** What readers may do; everything not listed is forbidden. */
113
+ permissions?: PdfPermission[];
114
+ }
115
+ export interface PdfInfo {
116
+ source: string;
117
+ page_count: number;
118
+ pages: Array<{
119
+ width_pt: number;
120
+ height_pt: number;
121
+ width_mm: number;
122
+ height_mm: number;
123
+ }>;
124
+ encrypted: boolean;
125
+ metadata: Record<string, unknown>;
40
126
  }
41
127
  export interface Render {
42
128
  id: string;
@@ -49,10 +135,13 @@ export interface Render {
49
135
  units: number;
50
136
  region: string;
51
137
  environment: 'live' | 'test';
138
+ /** `channel`: the release channel the version came from; `canary` when the channel's canary share picked it. */
52
139
  template: {
53
140
  id: string;
54
141
  slug: string;
55
142
  version: number;
143
+ channel?: string | null;
144
+ canary?: boolean;
56
145
  } | null;
57
146
  engine_version: string | null;
58
147
  template_checksum: string | null;
@@ -68,11 +157,19 @@ export interface Render {
68
157
  created_at: string;
69
158
  completed_at: string | null;
70
159
  }
71
- export interface BatchRequest {
72
- template?: string;
73
- items: RenderRequest[];
160
+ export interface BatchRequest<T extends string = string> {
161
+ /** Default template of the items; with a generated type for it, every item's `data` is checked. */
162
+ template?: T;
163
+ /** Default `canary_key` of the items; without one the whole batch lands on one version. */
164
+ canary_key?: string;
165
+ /** Default `output` of the items; an item's own wins, without either its template decides. */
166
+ output?: OutputFormat;
167
+ items: Array<Omit<RenderRequest, 'data'> & {
168
+ data?: TemplateData<T>;
169
+ }>;
74
170
  zip?: boolean;
75
171
  webhook_url?: string | null;
172
+ webhook_secret?: string | null;
76
173
  meta?: Record<string, unknown>;
77
174
  }
78
175
  export interface Job {
@@ -89,10 +186,117 @@ export interface Job {
89
186
  created_at: string;
90
187
  completed_at: string | null;
91
188
  }
189
+ /** A file of the workspace library (`/files`); a template reaches it with `asset(name)`. */
190
+ export interface LibraryFile {
191
+ id: string;
192
+ name: string;
193
+ content_type: string;
194
+ bytes: number;
195
+ sha256: string;
196
+ /** The CDN URL, the same one `asset(name)` produces. */
197
+ url: string;
198
+ created_at: string;
199
+ updated_at: string;
200
+ }
201
+ export interface FileUpload {
202
+ /** The bytes: a Blob or File, a Uint8Array (Node's Buffer is one) or an ArrayBuffer. */
203
+ data: Blob | Uint8Array | ArrayBuffer;
204
+ /** The library name, e.g. `logo.png` or `brand/header.svg`. Uploading a name again replaces it. */
205
+ name: string;
206
+ /** Sent with the bytes; the API also goes by the extension when it is missing. */
207
+ contentType?: string;
208
+ }
209
+ /** A Word, PowerPoint or other office file sent to the API: a template's file or a document to convert. */
210
+ export interface OfficeFileUpload {
211
+ /** The bytes: a Blob or File, a Uint8Array (Node's Buffer is one) or an ArrayBuffer. */
212
+ data: Blob | Uint8Array | ArrayBuffer;
213
+ /** The file name, e.g. `offer.docx`; a File's own name when omitted. The API reads the type from the content. */
214
+ name?: string;
215
+ }
216
+ export interface ConvertOptions extends PdfOutputOptions {
217
+ /** Pages to convert, e.g. `1-3,5`; all when omitted. */
218
+ page_ranges?: string;
219
+ /** Landscape for spreadsheets and documents without their own page setup. */
220
+ landscape?: boolean;
221
+ /** Each spreadsheet sheet on one page. */
222
+ single_page_sheets?: boolean;
223
+ }
224
+ export interface FileListOptions {
225
+ /** Only names starting with this, e.g. `brand/`. */
226
+ prefix?: string;
227
+ limit?: number;
228
+ cursor?: string | null;
229
+ }
230
+ /**
231
+ * The organisation's brand kit (`GET /brand`): what templates see as `brand`, plus the page defaults
232
+ * new templates start from. Unset values are `null`; `colors` is always an object.
233
+ */
234
+ export interface Brand {
235
+ version: number;
236
+ name: string | null;
237
+ /** Token → hex colour, e.g. `primary`; also `--brand-color-<token>` in the document. */
238
+ colors: Record<string, string>;
239
+ fonts: {
240
+ heading: string | null;
241
+ body: string | null;
242
+ };
243
+ font_size: string | null;
244
+ /** CDN URLs of the logos. */
245
+ logo: {
246
+ primary: string | null;
247
+ inverse: string | null;
248
+ mark: string | null;
249
+ };
250
+ legal_footer: string | null;
251
+ /** `{}` when unset. */
252
+ page_defaults: {
253
+ paper?: {
254
+ format?: string;
255
+ landscape?: boolean;
256
+ };
257
+ margin?: {
258
+ top?: string;
259
+ right?: string;
260
+ bottom?: string;
261
+ left?: string;
262
+ };
263
+ };
264
+ updated_at: string | null;
265
+ }
266
+ /** A shared partial of the organisation (`/partials`), included by name from templates of its engine. */
267
+ export interface SharedPartial {
268
+ /** Lowercase letters, digits, `-` and `_`; the API stores a name in lowercase. */
269
+ name: string;
270
+ engine: Engine;
271
+ description: string | null;
272
+ version: number;
273
+ /** Only when read one by one (`partials.get`) and in the result of `partials.put`. */
274
+ source?: string;
275
+ created_at: string;
276
+ updated_at: string;
277
+ }
278
+ export interface SharedPartialPut {
279
+ engine: Engine;
280
+ source: string;
281
+ description?: string | null;
282
+ /**
283
+ * The version the change is based on; the API answers 409 `conflict` when the partial has another,
284
+ * with the stored partial as `problem.current` (`null` when it was deleted).
285
+ */
286
+ base_version?: number;
287
+ }
288
+ export interface SharedPartialPutResult {
289
+ partial: SharedPartial;
290
+ /** `true` when the name did not exist before (201), `false` for an update (200). */
291
+ created: boolean;
292
+ }
293
+ export type WebhookEnvironment = 'live' | 'test';
92
294
  export interface WebhookEndpoint {
93
295
  id: string;
94
296
  url: string;
95
297
  events: string[];
298
+ /** Render environments whose events the endpoint receives; both by default. Quota events are sent regardless. */
299
+ environments?: WebhookEnvironment[];
96
300
  enabled: boolean;
97
301
  description: string | null;
98
302
  consecutive_failures: number;
@@ -101,7 +305,78 @@ export interface WebhookEndpoint {
101
305
  created_at: string;
102
306
  updated_at: string;
103
307
  }
104
- export type TemplateKind = 'pdf' | 'image';
308
+ export interface WebhookEndpointCreate {
309
+ url: string;
310
+ events?: string[];
311
+ environments?: WebhookEnvironment[];
312
+ description?: string | null;
313
+ }
314
+ export interface WebhookEndpointUpdate {
315
+ url?: string;
316
+ events?: string[];
317
+ environments?: WebhookEnvironment[];
318
+ enabled?: boolean;
319
+ description?: string | null;
320
+ }
321
+ export interface ListenSessionOptions {
322
+ /** Event types the session receives; all by default. */
323
+ events?: string[];
324
+ /** Include live-environment events (needs `webhook:manage`); test events only by default. */
325
+ live?: boolean;
326
+ }
327
+ /**
328
+ * A listen session (`POST /webhooks/listen`): receives the workspace's events like an endpoint and relays
329
+ * them over `websocket_url`, which is valid for 60 seconds and needs no key. The SDK opens no socket.
330
+ */
331
+ export interface ListenSession {
332
+ id: string;
333
+ /** Signs the session's deliveries. */
334
+ secret: string;
335
+ events: string[];
336
+ environments: WebhookEnvironment[];
337
+ expires_at: string;
338
+ websocket_url: string;
339
+ }
340
+ export interface WebhookResend {
341
+ delivery_id: string;
342
+ event_id: string;
343
+ event: string;
344
+ endpoint_id: string;
345
+ }
346
+ /**
347
+ * The stored request of a render (`GET /renders/{id}/input`). Template renders carry `template` and
348
+ * `data`, ad-hoc renders `html` or `url`. Passwords of `post` are never included.
349
+ */
350
+ export interface RenderInput {
351
+ render_id: string;
352
+ template?: {
353
+ id: string;
354
+ slug: string;
355
+ version: number;
356
+ channel?: string | null;
357
+ };
358
+ html?: string;
359
+ engine?: Engine;
360
+ url?: string;
361
+ data?: Record<string, unknown>;
362
+ locale?: string | null;
363
+ output?: OutputFormat;
364
+ settings?: Record<string, unknown>;
365
+ filename?: string;
366
+ post?: Record<string, unknown>;
367
+ meta?: Record<string, unknown>;
368
+ environment: 'live' | 'test';
369
+ created_at: string;
370
+ }
371
+ /** `docx` and `pptx` templates are Word and PowerPoint files with tags in their text (Starter plan and above). */
372
+ export type TemplateKind = 'pdf' | 'image' | 'docx' | 'pptx';
373
+ export type OfficeTemplateKind = 'docx' | 'pptx';
374
+ /** The file of a Word or PowerPoint template version; download it with `templates.versions.file`. */
375
+ export interface TemplateFile {
376
+ sha256: string;
377
+ bytes: number;
378
+ format: OfficeTemplateKind;
379
+ }
105
380
  export type VersionStatus = 'draft' | 'published' | 'archived';
106
381
  export interface Template {
107
382
  id: string;
@@ -116,6 +391,28 @@ export interface Template {
116
391
  created_at: string;
117
392
  updated_at: string;
118
393
  }
394
+ /** One finding of `templates.validate`. */
395
+ export interface Diagnostic {
396
+ severity: 'error' | 'warning' | 'info';
397
+ code: string;
398
+ message: string;
399
+ location?: {
400
+ line: number;
401
+ column: number;
402
+ };
403
+ /** Data errors only: where in the data, e.g. `data.invoice.lines[0].qty`. */
404
+ path?: string;
405
+ }
406
+ export interface TemplateValidation {
407
+ /** `false` when at least one diagnostic is an error. */
408
+ ok: boolean;
409
+ template: {
410
+ id: string;
411
+ slug: string;
412
+ version: number;
413
+ };
414
+ diagnostics: Diagnostic[];
415
+ }
119
416
  /** The files of a version as the editor and the CLI keep them. */
120
417
  export interface TemplateFiles {
121
418
  html: string;
@@ -127,6 +424,8 @@ export interface TemplateFiles {
127
424
  data_sets?: Record<string, unknown> | null;
128
425
  data_schema?: Record<string, unknown> | null;
129
426
  i18n?: Record<string, unknown> | null;
427
+ /** Partials the template includes (`name` → source); `formfeed templates push` sends them. */
428
+ partials?: Record<string, string> | null;
130
429
  }
131
430
  export interface TemplateVersion extends Partial<TemplateFiles> {
132
431
  id: string;
@@ -136,6 +435,69 @@ export interface TemplateVersion extends Partial<TemplateFiles> {
136
435
  change_note: string | null;
137
436
  created_at: string;
138
437
  published_at: string | null;
438
+ /** Publishing only: how the data schema changed against the version callers used before. */
439
+ schema_check?: SchemaCheck;
440
+ /** Word and PowerPoint templates: the version's file; `null` for other kinds. */
441
+ source_file?: TemplateFile | null;
442
+ }
443
+ /** One difference between two data schemas, from the point of view of a caller sending data. */
444
+ export interface SchemaChange {
445
+ /** Dotted field path (`customer.email`, `items[]`); empty for the data itself. */
446
+ path: string;
447
+ pointer: string;
448
+ kind: string;
449
+ breaking: boolean;
450
+ message: string;
451
+ }
452
+ /**
453
+ * The schema comparison publishing and channel moves run. `stored`: both versions store a schema and
454
+ * breaking changes are refused unless `allowBreaking` is set. `inferred`: compared from sample data,
455
+ * a warning only. `none`: nothing to compare.
456
+ */
457
+ export interface SchemaCheck {
458
+ source: 'stored' | 'inferred' | 'none';
459
+ breaking: SchemaChange[];
460
+ safe: SchemaChange[];
461
+ }
462
+ /** A release channel of a template (`published` or a named one such as `staging`). */
463
+ export interface Channel {
464
+ name: string;
465
+ version: number | null;
466
+ canary: {
467
+ version: number;
468
+ percent: number;
469
+ } | null;
470
+ /** The version before the last move; `rollback` returns to it. */
471
+ previous_version: number | null;
472
+ updated_at: string;
473
+ /** Renders of the last 24 hours through this channel, per version (list only). */
474
+ usage_24h?: Array<{
475
+ version: number;
476
+ renders: number;
477
+ failed: number;
478
+ }>;
479
+ /** Writes only. */
480
+ schema_check?: SchemaCheck;
481
+ }
482
+ export interface ChannelList {
483
+ data: Channel[];
484
+ /** The plan's allowance: named channels per template (`null` unlimited) and whether canaries are allowed. */
485
+ limits: {
486
+ channels: number | null;
487
+ canary: boolean;
488
+ };
489
+ }
490
+ export interface ChannelMove {
491
+ version: number;
492
+ /** A second version that receives `percent` (1 to 50) of the channel's renders; `null` clears it. */
493
+ canary?: {
494
+ version: number;
495
+ percent: number;
496
+ } | null;
497
+ }
498
+ export interface SchemaGuardOptions extends RequestOptions {
499
+ /** Go ahead although the data schema breaks callers of the current version. */
500
+ allowBreaking?: boolean;
139
501
  }
140
502
  export interface TemplateCreate extends TemplateFiles {
141
503
  name: string;
@@ -151,6 +513,32 @@ export interface TemplateVersionCreate extends TemplateFiles {
151
513
  /** Checksum of the version the draft was based on; the API answers 409 when the latest differs. */
152
514
  base_checksum?: string;
153
515
  publish?: boolean;
516
+ /** With `publish`: go ahead although the data schema breaks callers of the published version. */
517
+ allow_breaking?: boolean;
518
+ }
519
+ /** What a Word or PowerPoint template has besides its file: no markup, no partials. */
520
+ type OfficeFields = Omit<TemplateFiles, 'html' | 'css' | 'head' | 'partials'>;
521
+ /** A Word or PowerPoint template, created from its file (up to 20 MB). */
522
+ export interface OfficeTemplateCreate extends OfficeFields {
523
+ name: string;
524
+ slug: string;
525
+ description?: string | null;
526
+ kind: OfficeTemplateKind;
527
+ engine: Engine;
528
+ tags?: string[];
529
+ publish?: boolean;
530
+ file: OfficeFileUpload;
531
+ }
532
+ /**
533
+ * A new version of a Word or PowerPoint template: with `file`, the new document; without, the
534
+ * latest version's file is kept and only data, schema or settings change.
535
+ */
536
+ export interface OfficeVersionCreate extends OfficeFields {
537
+ file?: OfficeFileUpload;
538
+ change_note?: string;
539
+ base_checksum?: string;
540
+ publish?: boolean;
541
+ allow_breaking?: boolean;
154
542
  }
155
543
  export interface Usage {
156
544
  period: string;
@@ -221,7 +609,7 @@ export declare class Formfeed {
221
609
  constructor(options: FormfeedOptions);
222
610
  readonly renders: {
223
611
  /** Renders a template, HTML or URL. Sync by default; `mode: 'async'` returns a queued render. */
224
- create: (request: RenderRequest, options?: RequestOptions) => Promise<Render>;
612
+ create: <T extends string = string>(request: TypedRenderRequest<T>, options?: RequestOptions) => Promise<Render>;
225
613
  get: (id: string, options?: RequestOptions) => Promise<Render>;
226
614
  /** Polls until the render succeeded or failed (async renders). */
227
615
  waitFor: (id: string, options?: WaitOptions) => Promise<Render>;
@@ -236,7 +624,70 @@ export declare class Formfeed {
236
624
  all: (query?: Omit<RenderListOptions, "cursor">, options?: RequestOptions) => Promise<Render[]>;
237
625
  /** Removes the stored files of a render before they expire. Needs the `file:delete` scope. */
238
626
  deleteOutputs: (id: string, options?: RequestOptions) => Promise<void>;
239
- batch: (request: BatchRequest, options?: RequestOptions) => Promise<Job>;
627
+ /**
628
+ * The stored request of a render, to render it again. Needs `render:input`; throws
629
+ * `render_input_expired` (410) when the workspace keeps no requests or the period ended.
630
+ */
631
+ input: (id: string, options?: RequestOptions) => Promise<RenderInput>;
632
+ batch: <T extends string = string>(request: BatchRequest<T>, options?: RequestOptions) => Promise<Job>;
633
+ };
634
+ /**
635
+ * PDF tools on the outputs of earlier renders (a `Render` or its id) and on PDFs of the file library
636
+ * (a `LibraryFile`, its id or its name). merge, protect and watermark return a new render and cost
637
+ * 0.5 units each on live keys; info is free.
638
+ */
639
+ readonly pdf: {
640
+ merge: (sources: Array<Render | LibraryFile | string>, output?: PdfOutputOptions, options?: RequestOptions) => Promise<Render>;
641
+ protect: (source: Render | string, protect: ProtectOptions, options?: RequestOptions) => Promise<Render>;
642
+ watermark: (source: Render | string, watermark: WatermarkOptions & PdfOutputOptions, options?: RequestOptions) => Promise<Render>;
643
+ info: (source: Render | string, options?: RequestOptions) => Promise<PdfInfo>;
644
+ /**
645
+ * Converts an office document to a PDF render (Starter plan and above): an uploaded file (Word,
646
+ * Excel, PowerPoint, OpenDocument, RTF or HTML, up to 20 MB, not kept), or the output of a Word or
647
+ * PowerPoint template render. Costs follow the PDF rule. A busy converter answers 503, which is
648
+ * retried like any other.
649
+ */
650
+ convert: (source: {
651
+ file: OfficeFileUpload;
652
+ } | Render | string, convert?: ConvertOptions, options?: RequestOptions) => Promise<Render>;
653
+ };
654
+ /**
655
+ * The workspace file library (`/files`): images and PDFs a template references by name with
656
+ * `asset('logo.png')`, and the sources of image watermarks and merges. Needs `file:read`,
657
+ * `file:write` or `file:delete`. Files are served without a signature, so keep confidential
658
+ * documents out of it.
659
+ */
660
+ readonly files: {
661
+ /** Uploads a file; the same name replaces the existing file in place and keeps its URL. */
662
+ upload: (file: FileUpload, options?: RequestOptions) => Promise<LibraryFile>;
663
+ /** Page of files, newest first. */
664
+ list: (query?: FileListOptions, options?: RequestOptions) => Promise<{
665
+ data: LibraryFile[];
666
+ next_cursor: string | null;
667
+ }>;
668
+ /** Every file matching the query, following the cursor. */
669
+ all: (query?: Omit<FileListOptions, "cursor">, options?: RequestOptions) => Promise<LibraryFile[]>;
670
+ get: (id: string, options?: RequestOptions) => Promise<LibraryFile>;
671
+ /** Removes the file and its bytes; templates that name it render a missing image afterwards. */
672
+ delete: (file: LibraryFile | string, options?: RequestOptions) => Promise<void>;
673
+ };
674
+ /** The organisation's brand kit, read-only through the API (it is edited in the app). Needs `template:read`. */
675
+ readonly brand: {
676
+ get: (options?: RequestOptions) => Promise<Brand>;
677
+ };
678
+ /**
679
+ * Shared partials of the organisation. Renders use the current source, so a change reaches every
680
+ * template that includes the partial without a new version. Needs `template:read` or `template:write`.
681
+ */
682
+ readonly partials: {
683
+ /** Every shared partial, without its source. */
684
+ list: (options?: RequestOptions) => Promise<SharedPartial[]>;
685
+ /** One partial with its source. */
686
+ get: (name: string, options?: RequestOptions) => Promise<SharedPartial>;
687
+ /** Creates or replaces a partial; pass `base_version` to fail with 409 when it changed since you read it. */
688
+ put: (name: string, input: SharedPartialPut, options?: RequestOptions) => Promise<SharedPartialPutResult>;
689
+ /** Removes a partial; templates that still include it fail to render afterwards. */
690
+ delete: (name: string, options?: RequestOptions) => Promise<void>;
240
691
  };
241
692
  readonly jobs: {
242
693
  get: (id: string, options?: RequestOptions) => Promise<Job>;
@@ -244,21 +695,25 @@ export declare class Formfeed {
244
695
  };
245
696
  readonly webhooks: {
246
697
  list: (options?: RequestOptions) => Promise<WebhookEndpoint[]>;
247
- create: (input: {
248
- url: string;
249
- events?: string[];
250
- description?: string | null;
251
- }, options?: RequestOptions) => Promise<WebhookEndpoint>;
252
- update: (id: string, patch: {
253
- url?: string;
254
- events?: string[];
255
- enabled?: boolean;
256
- description?: string | null;
257
- }, options?: RequestOptions) => Promise<WebhookEndpoint>;
698
+ create: (input: WebhookEndpointCreate, options?: RequestOptions) => Promise<WebhookEndpoint>;
699
+ update: (id: string, patch: WebhookEndpointUpdate, options?: RequestOptions) => Promise<WebhookEndpoint>;
258
700
  delete: (id: string, options?: RequestOptions) => Promise<void>;
259
701
  test: (id: string, options?: RequestOptions) => Promise<{
260
702
  queued: boolean;
261
703
  }>;
704
+ /**
705
+ * Sends a stored event (`evt_…`) again as a new delivery to a registered endpoint (`webhook:manage`)
706
+ * or a running listen session (`webhook:listen`).
707
+ */
708
+ resend: (eventId: string, endpointId: string, options?: RequestOptions) => Promise<WebhookResend>;
709
+ /**
710
+ * Listen sessions, what `formfeed listen` uses. Needs `webhook:listen`. Starting a session ends the
711
+ * previous one of the same key; the WebSocket itself is up to the caller.
712
+ */
713
+ listen: {
714
+ start: (input?: ListenSessionOptions, options?: RequestOptions) => Promise<ListenSession>;
715
+ end: (id: string, options?: RequestOptions) => Promise<void>;
716
+ };
262
717
  };
263
718
  readonly templates: {
264
719
  list: (query?: TemplateListOptions, options?: RequestOptions) => Promise<{
@@ -268,7 +723,8 @@ export declare class Formfeed {
268
723
  /** Every template of the workspace, following the cursor. */
269
724
  all: (query?: Omit<TemplateListOptions, "cursor">, options?: RequestOptions) => Promise<Template[]>;
270
725
  get: (idOrSlug: string, options?: RequestOptions) => Promise<Template>;
271
- create: (input: TemplateCreate, options?: RequestOptions) => Promise<Template>;
726
+ /** A Word or PowerPoint template (`kind` `docx` or `pptx`) is created from its `file`, sent as multipart. */
727
+ create: (input: TemplateCreate | OfficeTemplateCreate, options?: RequestOptions) => Promise<Template>;
272
728
  update: (idOrSlug: string, patch: {
273
729
  name?: string;
274
730
  description?: string | null;
@@ -277,19 +733,67 @@ export declare class Formfeed {
277
733
  archive: (idOrSlug: string, options?: RequestOptions) => Promise<void>;
278
734
  versions: {
279
735
  list: (idOrSlug: string, options?: RequestOptions) => Promise<TemplateVersion[]>;
280
- /** `which`: 'published', 'latest' or a version number. Carries the files. */
281
- get: (idOrSlug: string, which?: "published" | "latest" | number, options?: RequestOptions) => Promise<TemplateVersion>;
282
- create: (idOrSlug: string, input: TemplateVersionCreate, options?: RequestOptions) => Promise<TemplateVersion>;
283
- publish: (idOrSlug: string, number: number, options?: RequestOptions) => Promise<TemplateVersion>;
736
+ /** `which`: 'published', 'latest', a version number or a channel name (its main version). Carries the files. */
737
+ get: (idOrSlug: string, which?: string | number, options?: RequestOptions) => Promise<TemplateVersion>;
738
+ /** For a Word or PowerPoint template, pass `file` to replace the document; without it the latest file is kept. */
739
+ create: (idOrSlug: string, input: TemplateVersionCreate | OfficeVersionCreate, options?: RequestOptions) => Promise<TemplateVersion>;
740
+ /** The Word or PowerPoint file of a version (`which` as for `get`); needs `template:read`. */
741
+ file: (idOrSlug: string, which?: string | number, options?: RequestOptions) => Promise<Uint8Array>;
742
+ /**
743
+ * Publishes a version. When both versions store a data schema and the new one breaks callers of the
744
+ * published one, the API refuses with `schema_breaking_change` unless `allowBreaking` is set.
745
+ */
746
+ publish: (idOrSlug: string, number: number, options?: SchemaGuardOptions) => Promise<TemplateVersion>;
747
+ };
748
+ /**
749
+ * Release channels (`published` and named ones such as `staging`): a render with `version: 'staging'`
750
+ * uses the version the channel points at. Moves reach renders within a minute.
751
+ */
752
+ channels: {
753
+ list: (idOrSlug: string, options?: RequestOptions) => Promise<ChannelList>;
754
+ /** Creates or moves a channel; on `published` this publishes. */
755
+ set: (idOrSlug: string, name: string, move: ChannelMove, options?: SchemaGuardOptions) => Promise<Channel>;
756
+ /** The canary becomes the main version. */
757
+ promote: (idOrSlug: string, name: string, options?: SchemaGuardOptions) => Promise<Channel>;
758
+ /** Back to the version before the last move. */
759
+ rollback: (idOrSlug: string, name: string, options?: SchemaGuardOptions) => Promise<Channel>;
760
+ /** Refused with `channel_in_use` while renders of the last hour used the channel, unless `force`. */
761
+ delete: (idOrSlug: string, name: string, options?: RequestOptions & {
762
+ force?: boolean;
763
+ }) => Promise<void>;
284
764
  };
285
765
  schema: (idOrSlug: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
766
+ /**
767
+ * Checks a version with data without rendering: syntax, header and footer, missing partials,
768
+ * runtime errors and the data against the stored schema. Free. Without `data`, the version's
769
+ * sample data is checked.
770
+ */
771
+ validate: (idOrSlug: string, input?: {
772
+ version?: "published" | "latest" | number;
773
+ data?: Record<string, unknown>;
774
+ }, options?: RequestOptions) => Promise<TemplateValidation>;
286
775
  };
287
776
  readonly account: {
288
777
  get: (options?: RequestOptions) => Promise<Record<string, unknown>>;
289
778
  /** Units of the current period, or of `YYYY-MM`, with a daily series and a breakdown per template. */
290
779
  usage: (period?: string, options?: RequestOptions) => Promise<Usage>;
291
780
  };
781
+ /** Workspaces of the key's organisation. Needs `workspace:delete`, which no key has by default. */
782
+ readonly workspaces: {
783
+ /**
784
+ * Deletes a workspace: it leaves the app and the API at once, its keys are revoked and its content
785
+ * is removed after 30 days. The organisation's last workspace is refused with `last_workspace`.
786
+ */
787
+ delete: (id: string, options?: RequestOptions) => Promise<void>;
788
+ };
789
+ private channelAction;
292
790
  /** Raw request with auth, retries and problem mapping; use it for endpoints without a helper. */
293
791
  request<T>(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<T>;
792
+ /**
793
+ * `request` with the HTTP status, for endpoints whose answer depends on it (201 created, 200 updated).
794
+ * `bytes` returns a successful body as bytes (file downloads); problems are JSON either way.
795
+ */
796
+ private send;
294
797
  private backoff;
295
798
  }
799
+ export {};