@formfeed/sdk 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.
@@ -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;
@@ -39,11 +44,36 @@ export interface RenderRequest {
39
44
  meta?: Record<string, unknown>;
40
45
  region?: Region;
41
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;
42
52
  /** PDF post-processing: merge, watermark, password, applied in that order (0.5 units each). */
43
53
  post?: PostProcessing | null;
44
54
  /** Check `data` against the template's stored schema first; a mismatch throws `data_validation_error`. */
45
55
  validate_data?: boolean;
46
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
+ });
47
77
  export type PdfPermission = 'print' | 'copy' | 'modify' | 'annotate';
48
78
  /** A text or an image watermark; pass one of `text` and `image`. */
49
79
  export interface WatermarkOptions {
@@ -105,10 +135,13 @@ export interface Render {
105
135
  units: number;
106
136
  region: string;
107
137
  environment: 'live' | 'test';
138
+ /** `channel`: the release channel the version came from; `canary` when the channel's canary share picked it. */
108
139
  template: {
109
140
  id: string;
110
141
  slug: string;
111
142
  version: number;
143
+ channel?: string | null;
144
+ canary?: boolean;
112
145
  } | null;
113
146
  engine_version: string | null;
114
147
  template_checksum: string | null;
@@ -124,9 +157,16 @@ export interface Render {
124
157
  created_at: string;
125
158
  completed_at: string | null;
126
159
  }
127
- export interface BatchRequest {
128
- template?: string;
129
- 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
+ }>;
130
170
  zip?: boolean;
131
171
  webhook_url?: string | null;
132
172
  webhook_secret?: string | null;
@@ -166,16 +206,97 @@ export interface FileUpload {
166
206
  /** Sent with the bytes; the API also goes by the extension when it is missing. */
167
207
  contentType?: string;
168
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
+ }
169
224
  export interface FileListOptions {
170
225
  /** Only names starting with this, e.g. `brand/`. */
171
226
  prefix?: string;
172
227
  limit?: number;
173
228
  cursor?: string | null;
174
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';
175
294
  export interface WebhookEndpoint {
176
295
  id: string;
177
296
  url: string;
178
297
  events: string[];
298
+ /** Render environments whose events the endpoint receives; both by default. Quota events are sent regardless. */
299
+ environments?: WebhookEnvironment[];
179
300
  enabled: boolean;
180
301
  description: string | null;
181
302
  consecutive_failures: number;
@@ -184,7 +305,78 @@ export interface WebhookEndpoint {
184
305
  created_at: string;
185
306
  updated_at: string;
186
307
  }
187
- 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
+ }
188
380
  export type VersionStatus = 'draft' | 'published' | 'archived';
189
381
  export interface Template {
190
382
  id: string;
@@ -243,6 +435,69 @@ export interface TemplateVersion extends Partial<TemplateFiles> {
243
435
  change_note: string | null;
244
436
  created_at: string;
245
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;
246
501
  }
247
502
  export interface TemplateCreate extends TemplateFiles {
248
503
  name: string;
@@ -258,6 +513,32 @@ export interface TemplateVersionCreate extends TemplateFiles {
258
513
  /** Checksum of the version the draft was based on; the API answers 409 when the latest differs. */
259
514
  base_checksum?: string;
260
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;
261
542
  }
262
543
  export interface Usage {
263
544
  period: string;
@@ -328,7 +609,7 @@ export declare class Formfeed {
328
609
  constructor(options: FormfeedOptions);
329
610
  readonly renders: {
330
611
  /** Renders a template, HTML or URL. Sync by default; `mode: 'async'` returns a queued render. */
331
- create: (request: RenderRequest, options?: RequestOptions) => Promise<Render>;
612
+ create: <T extends string = string>(request: TypedRenderRequest<T>, options?: RequestOptions) => Promise<Render>;
332
613
  get: (id: string, options?: RequestOptions) => Promise<Render>;
333
614
  /** Polls until the render succeeded or failed (async renders). */
334
615
  waitFor: (id: string, options?: WaitOptions) => Promise<Render>;
@@ -343,7 +624,12 @@ export declare class Formfeed {
343
624
  all: (query?: Omit<RenderListOptions, "cursor">, options?: RequestOptions) => Promise<Render[]>;
344
625
  /** Removes the stored files of a render before they expire. Needs the `file:delete` scope. */
345
626
  deleteOutputs: (id: string, options?: RequestOptions) => Promise<void>;
346
- 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>;
347
633
  };
348
634
  /**
349
635
  * PDF tools on the outputs of earlier renders (a `Render` or its id) and on PDFs of the file library
@@ -355,6 +641,15 @@ export declare class Formfeed {
355
641
  protect: (source: Render | string, protect: ProtectOptions, options?: RequestOptions) => Promise<Render>;
356
642
  watermark: (source: Render | string, watermark: WatermarkOptions & PdfOutputOptions, options?: RequestOptions) => Promise<Render>;
357
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>;
358
653
  };
359
654
  /**
360
655
  * The workspace file library (`/files`): images and PDFs a template references by name with
@@ -376,27 +671,49 @@ export declare class Formfeed {
376
671
  /** Removes the file and its bytes; templates that name it render a missing image afterwards. */
377
672
  delete: (file: LibraryFile | string, options?: RequestOptions) => Promise<void>;
378
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>;
691
+ };
379
692
  readonly jobs: {
380
693
  get: (id: string, options?: RequestOptions) => Promise<Job>;
381
694
  waitFor: (id: string, options?: WaitOptions) => Promise<Job>;
382
695
  };
383
696
  readonly webhooks: {
384
697
  list: (options?: RequestOptions) => Promise<WebhookEndpoint[]>;
385
- create: (input: {
386
- url: string;
387
- events?: string[];
388
- description?: string | null;
389
- }, options?: RequestOptions) => Promise<WebhookEndpoint>;
390
- update: (id: string, patch: {
391
- url?: string;
392
- events?: string[];
393
- enabled?: boolean;
394
- description?: string | null;
395
- }, options?: RequestOptions) => Promise<WebhookEndpoint>;
698
+ create: (input: WebhookEndpointCreate, options?: RequestOptions) => Promise<WebhookEndpoint>;
699
+ update: (id: string, patch: WebhookEndpointUpdate, options?: RequestOptions) => Promise<WebhookEndpoint>;
396
700
  delete: (id: string, options?: RequestOptions) => Promise<void>;
397
701
  test: (id: string, options?: RequestOptions) => Promise<{
398
702
  queued: boolean;
399
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
+ };
400
717
  };
401
718
  readonly templates: {
402
719
  list: (query?: TemplateListOptions, options?: RequestOptions) => Promise<{
@@ -406,7 +723,8 @@ export declare class Formfeed {
406
723
  /** Every template of the workspace, following the cursor. */
407
724
  all: (query?: Omit<TemplateListOptions, "cursor">, options?: RequestOptions) => Promise<Template[]>;
408
725
  get: (idOrSlug: string, options?: RequestOptions) => Promise<Template>;
409
- 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>;
410
728
  update: (idOrSlug: string, patch: {
411
729
  name?: string;
412
730
  description?: string | null;
@@ -415,10 +733,34 @@ export declare class Formfeed {
415
733
  archive: (idOrSlug: string, options?: RequestOptions) => Promise<void>;
416
734
  versions: {
417
735
  list: (idOrSlug: string, options?: RequestOptions) => Promise<TemplateVersion[]>;
418
- /** `which`: 'published', 'latest' or a version number. Carries the files. */
419
- get: (idOrSlug: string, which?: "published" | "latest" | number, options?: RequestOptions) => Promise<TemplateVersion>;
420
- create: (idOrSlug: string, input: TemplateVersionCreate, options?: RequestOptions) => Promise<TemplateVersion>;
421
- 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>;
422
764
  };
423
765
  schema: (idOrSlug: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
424
766
  /**
@@ -436,7 +778,22 @@ export declare class Formfeed {
436
778
  /** Units of the current period, or of `YYYY-MM`, with a daily series and a breakdown per template. */
437
779
  usage: (period?: string, options?: RequestOptions) => Promise<Usage>;
438
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;
439
790
  /** Raw request with auth, retries and problem mapping; use it for endpoints without a helper. */
440
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;
441
797
  private backoff;
442
798
  }
799
+ export {};