@formfeed/sdk 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -7
- package/index.cjs +323 -62
- package/index.js +323 -62
- package/package.json +1 -1
- package/types/index.d.cts +1 -1
- package/types/index.d.ts +1 -1
- package/types/lib/client.d.cts +111 -0
- package/types/lib/client.d.ts +111 -0
package/index.js
CHANGED
|
@@ -11,7 +11,10 @@ function multipart(fields, file) {
|
|
|
11
11
|
form.set("file", blob, name);
|
|
12
12
|
for (const [key, value] of Object.entries(fields)) {
|
|
13
13
|
if (value === void 0) continue;
|
|
14
|
-
form.set(
|
|
14
|
+
form.set(
|
|
15
|
+
key,
|
|
16
|
+
typeof value === "string" ? value : typeof value === "object" ? JSON.stringify(value) : String(value)
|
|
17
|
+
);
|
|
15
18
|
}
|
|
16
19
|
return form;
|
|
17
20
|
}
|
|
@@ -41,7 +44,10 @@ function randomKey() {
|
|
|
41
44
|
if (c?.randomUUID) return c.randomUUID();
|
|
42
45
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
43
46
|
}
|
|
44
|
-
var withKey = (options) => ({
|
|
47
|
+
var withKey = (options) => ({
|
|
48
|
+
...options,
|
|
49
|
+
idempotencyKey: options.idempotencyKey ?? randomKey()
|
|
50
|
+
});
|
|
45
51
|
var idOf = (source) => typeof source === "string" ? source : source.id;
|
|
46
52
|
var Formfeed = class {
|
|
47
53
|
baseUrl;
|
|
@@ -51,14 +57,28 @@ var Formfeed = class {
|
|
|
51
57
|
timeoutMs;
|
|
52
58
|
extraHeaders;
|
|
53
59
|
constructor(options) {
|
|
54
|
-
if (!options.apiKey)
|
|
60
|
+
if (!options.apiKey)
|
|
61
|
+
throw new FormfeedError("invalid_request", "apiKey is required", 0);
|
|
55
62
|
this.apiKey = options.apiKey;
|
|
56
|
-
this.baseUrl = (options.baseUrl ?? hosts[options.region ?? "eu"]).replace(
|
|
63
|
+
this.baseUrl = (options.baseUrl ?? hosts[options.region ?? "eu"]).replace(
|
|
64
|
+
/\/$/,
|
|
65
|
+
""
|
|
66
|
+
);
|
|
57
67
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
58
68
|
this.maxRetries = options.maxRetries ?? 3;
|
|
59
69
|
this.timeoutMs = options.timeoutMs ?? 12e4;
|
|
60
|
-
this.extraHeaders = Object.fromEntries(
|
|
61
|
-
|
|
70
|
+
this.extraHeaders = Object.fromEntries(
|
|
71
|
+
Object.entries(options.headers ?? {}).map(([name, value]) => [
|
|
72
|
+
name.toLowerCase(),
|
|
73
|
+
value
|
|
74
|
+
])
|
|
75
|
+
);
|
|
76
|
+
if (!this.fetchImpl)
|
|
77
|
+
throw new FormfeedError(
|
|
78
|
+
"invalid_request",
|
|
79
|
+
"fetch is not available; pass options.fetch",
|
|
80
|
+
0
|
|
81
|
+
);
|
|
62
82
|
}
|
|
63
83
|
renders = {
|
|
64
84
|
/** Renders a template, HTML or URL. Sync by default; `mode: 'async'` returns a queued render. */
|
|
@@ -66,16 +86,26 @@ var Formfeed = class {
|
|
|
66
86
|
...options,
|
|
67
87
|
idempotencyKey: options.idempotencyKey ?? randomKey()
|
|
68
88
|
}),
|
|
69
|
-
get: (id, options = {}) => this.request(
|
|
89
|
+
get: (id, options = {}) => this.request(
|
|
90
|
+
"GET",
|
|
91
|
+
`/renders/${encodeURIComponent(id)}`,
|
|
92
|
+
void 0,
|
|
93
|
+
options
|
|
94
|
+
),
|
|
70
95
|
/** Polls until the render succeeded or failed (async renders). */
|
|
71
96
|
waitFor: async (id, options = {}) => {
|
|
72
97
|
const deadline = Date.now() + (options.timeoutMs ?? 12e4);
|
|
73
98
|
const interval = options.intervalMs ?? 1e3;
|
|
74
99
|
for (; ; ) {
|
|
75
100
|
const render = await this.renders.get(id, { signal: options.signal });
|
|
76
|
-
if (render.status === "succeeded" || render.status === "failed")
|
|
101
|
+
if (render.status === "succeeded" || render.status === "failed")
|
|
102
|
+
return render;
|
|
77
103
|
if (Date.now() + interval > deadline)
|
|
78
|
-
throw new FormfeedError(
|
|
104
|
+
throw new FormfeedError(
|
|
105
|
+
"timeout",
|
|
106
|
+
`render ${id} did not finish within the wait time`,
|
|
107
|
+
0
|
|
108
|
+
);
|
|
79
109
|
await sleep(interval, options.signal);
|
|
80
110
|
}
|
|
81
111
|
},
|
|
@@ -83,17 +113,34 @@ var Formfeed = class {
|
|
|
83
113
|
download: async (render, options = {}) => {
|
|
84
114
|
const target = typeof render === "string" ? await this.renders.get(render, options) : render;
|
|
85
115
|
if (!target.download_url)
|
|
86
|
-
throw new FormfeedError(
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
throw new FormfeedError(
|
|
117
|
+
"not_ready",
|
|
118
|
+
`render ${target.id} has no output (${target.status})`,
|
|
119
|
+
0
|
|
120
|
+
);
|
|
121
|
+
const res = await this.fetchImpl(target.download_url, {
|
|
122
|
+
signal: options.signal
|
|
123
|
+
});
|
|
124
|
+
if (!res.ok)
|
|
125
|
+
throw new FormfeedError(
|
|
126
|
+
"download_failed",
|
|
127
|
+
`download answered HTTP ${res.status}`,
|
|
128
|
+
res.status
|
|
129
|
+
);
|
|
89
130
|
return new Uint8Array(await res.arrayBuffer());
|
|
90
131
|
},
|
|
91
132
|
/** Page of renders, newest first. */
|
|
92
133
|
list: (query = {}, options = {}) => {
|
|
93
134
|
const params = new URLSearchParams();
|
|
94
|
-
for (const [k, v] of Object.entries(query))
|
|
135
|
+
for (const [k, v] of Object.entries(query))
|
|
136
|
+
if (v !== void 0 && v !== null && v !== "") params.set(k, String(v));
|
|
95
137
|
const qs = params.toString();
|
|
96
|
-
return this.request(
|
|
138
|
+
return this.request(
|
|
139
|
+
"GET",
|
|
140
|
+
`/renders${qs ? `?${qs}` : ""}`,
|
|
141
|
+
void 0,
|
|
142
|
+
options
|
|
143
|
+
);
|
|
97
144
|
},
|
|
98
145
|
/** Every render matching the query, following the cursor. */
|
|
99
146
|
all: async (query = {}, options = {}) => {
|
|
@@ -107,12 +154,22 @@ var Formfeed = class {
|
|
|
107
154
|
return out;
|
|
108
155
|
},
|
|
109
156
|
/** Removes the stored files of a render before they expire. Needs the `file:delete` scope. */
|
|
110
|
-
deleteOutputs: (id, options = {}) => this.request(
|
|
157
|
+
deleteOutputs: (id, options = {}) => this.request(
|
|
158
|
+
"DELETE",
|
|
159
|
+
`/renders/${encodeURIComponent(id)}/outputs`,
|
|
160
|
+
void 0,
|
|
161
|
+
options
|
|
162
|
+
),
|
|
111
163
|
/**
|
|
112
164
|
* The stored request of a render, to render it again. Needs `render:input`; throws
|
|
113
165
|
* `render_input_expired` (410) when the workspace keeps no requests or the period ended.
|
|
114
166
|
*/
|
|
115
|
-
input: (id, options = {}) => this.request(
|
|
167
|
+
input: (id, options = {}) => this.request(
|
|
168
|
+
"GET",
|
|
169
|
+
`/renders/${encodeURIComponent(id)}/input`,
|
|
170
|
+
void 0,
|
|
171
|
+
options
|
|
172
|
+
),
|
|
116
173
|
batch: (request, options = {}) => this.request("POST", "/renders/batch", request, {
|
|
117
174
|
...options,
|
|
118
175
|
idempotencyKey: options.idempotencyKey ?? randomKey()
|
|
@@ -124,10 +181,30 @@ var Formfeed = class {
|
|
|
124
181
|
* 0.5 units each on live keys; info is free.
|
|
125
182
|
*/
|
|
126
183
|
pdf = {
|
|
127
|
-
merge: (sources, output = {}, options = {}) => this.request(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
184
|
+
merge: (sources, output = {}, options = {}) => this.request(
|
|
185
|
+
"POST",
|
|
186
|
+
"/pdf/merge",
|
|
187
|
+
{ ...output, sources: sources.map(idOf) },
|
|
188
|
+
withKey(options)
|
|
189
|
+
),
|
|
190
|
+
protect: (source, protect, options = {}) => this.request(
|
|
191
|
+
"POST",
|
|
192
|
+
"/pdf/protect",
|
|
193
|
+
{ ...protect, source: idOf(source) },
|
|
194
|
+
withKey(options)
|
|
195
|
+
),
|
|
196
|
+
watermark: (source, watermark, options = {}) => this.request(
|
|
197
|
+
"POST",
|
|
198
|
+
"/pdf/watermark",
|
|
199
|
+
{ ...watermark, source: idOf(source) },
|
|
200
|
+
withKey(options)
|
|
201
|
+
),
|
|
202
|
+
info: (source, options = {}) => this.request(
|
|
203
|
+
"POST",
|
|
204
|
+
"/pdf/info",
|
|
205
|
+
{ source: idOf(source) },
|
|
206
|
+
options
|
|
207
|
+
),
|
|
131
208
|
/**
|
|
132
209
|
* Converts an office document to a PDF render (Starter plan and above): an uploaded file (Word,
|
|
133
210
|
* Excel, PowerPoint, OpenDocument, RTF or HTML, up to 20 MB, not kept), or the output of a Word or
|
|
@@ -136,8 +213,18 @@ var Formfeed = class {
|
|
|
136
213
|
*/
|
|
137
214
|
convert: (source, convert = {}, options = {}) => {
|
|
138
215
|
if (typeof source === "object" && "file" in source)
|
|
139
|
-
return this.request(
|
|
140
|
-
|
|
216
|
+
return this.request(
|
|
217
|
+
"POST",
|
|
218
|
+
"/pdf/convert",
|
|
219
|
+
multipart({ ...convert }, source.file),
|
|
220
|
+
withKey(options)
|
|
221
|
+
);
|
|
222
|
+
return this.request(
|
|
223
|
+
"POST",
|
|
224
|
+
"/pdf/convert",
|
|
225
|
+
{ ...convert, source: idOf(source) },
|
|
226
|
+
withKey(options)
|
|
227
|
+
);
|
|
141
228
|
}
|
|
142
229
|
};
|
|
143
230
|
/**
|
|
@@ -149,7 +236,10 @@ var Formfeed = class {
|
|
|
149
236
|
files = {
|
|
150
237
|
/** Uploads a file; the same name replaces the existing file in place and keeps its URL. */
|
|
151
238
|
upload: (file, options = {}) => {
|
|
152
|
-
const blob = file.data instanceof Blob ? file.data : new Blob(
|
|
239
|
+
const blob = file.data instanceof Blob ? file.data : new Blob(
|
|
240
|
+
[file.data],
|
|
241
|
+
file.contentType ? { type: file.contentType } : {}
|
|
242
|
+
);
|
|
153
243
|
const form = new FormData();
|
|
154
244
|
form.set("file", blob, file.name);
|
|
155
245
|
form.set("name", file.name);
|
|
@@ -158,9 +248,15 @@ var Formfeed = class {
|
|
|
158
248
|
/** Page of files, newest first. */
|
|
159
249
|
list: (query = {}, options = {}) => {
|
|
160
250
|
const params = new URLSearchParams();
|
|
161
|
-
for (const [k, v] of Object.entries(query))
|
|
251
|
+
for (const [k, v] of Object.entries(query))
|
|
252
|
+
if (v !== void 0 && v !== null && v !== "") params.set(k, String(v));
|
|
162
253
|
const qs = params.toString();
|
|
163
|
-
return this.request(
|
|
254
|
+
return this.request(
|
|
255
|
+
"GET",
|
|
256
|
+
`/files${qs ? `?${qs}` : ""}`,
|
|
257
|
+
void 0,
|
|
258
|
+
options
|
|
259
|
+
);
|
|
164
260
|
},
|
|
165
261
|
/** Every file matching the query, following the cursor. */
|
|
166
262
|
all: async (query = {}, options = {}) => {
|
|
@@ -173,9 +269,19 @@ var Formfeed = class {
|
|
|
173
269
|
} while (cursor);
|
|
174
270
|
return out;
|
|
175
271
|
},
|
|
176
|
-
get: (id, options = {}) => this.request(
|
|
272
|
+
get: (id, options = {}) => this.request(
|
|
273
|
+
"GET",
|
|
274
|
+
`/files/${encodeURIComponent(id)}`,
|
|
275
|
+
void 0,
|
|
276
|
+
options
|
|
277
|
+
),
|
|
177
278
|
/** Removes the file and its bytes; templates that name it render a missing image afterwards. */
|
|
178
|
-
delete: (file, options = {}) => this.request(
|
|
279
|
+
delete: (file, options = {}) => this.request(
|
|
280
|
+
"DELETE",
|
|
281
|
+
`/files/${encodeURIComponent(idOf(file))}`,
|
|
282
|
+
void 0,
|
|
283
|
+
options
|
|
284
|
+
)
|
|
179
285
|
};
|
|
180
286
|
/** The organisation's brand kit, read-only through the API (it is edited in the app). Needs `template:read`. */
|
|
181
287
|
brand = {
|
|
@@ -187,19 +293,44 @@ var Formfeed = class {
|
|
|
187
293
|
*/
|
|
188
294
|
partials = {
|
|
189
295
|
/** Every shared partial, without its source. */
|
|
190
|
-
list: async (options = {}) => (await this.request(
|
|
296
|
+
list: async (options = {}) => (await this.request(
|
|
297
|
+
"GET",
|
|
298
|
+
"/partials",
|
|
299
|
+
void 0,
|
|
300
|
+
options
|
|
301
|
+
)).data,
|
|
191
302
|
/** One partial with its source. */
|
|
192
|
-
get: (name, options = {}) => this.request(
|
|
303
|
+
get: (name, options = {}) => this.request(
|
|
304
|
+
"GET",
|
|
305
|
+
`/partials/${encodeURIComponent(name)}`,
|
|
306
|
+
void 0,
|
|
307
|
+
options
|
|
308
|
+
),
|
|
193
309
|
/** Creates or replaces a partial; pass `base_version` to fail with 409 when it changed since you read it. */
|
|
194
310
|
put: async (name, input, options = {}) => {
|
|
195
|
-
const { status, body } = await this.send(
|
|
311
|
+
const { status, body } = await this.send(
|
|
312
|
+
"PUT",
|
|
313
|
+
`/partials/${encodeURIComponent(name)}`,
|
|
314
|
+
input,
|
|
315
|
+
options
|
|
316
|
+
);
|
|
196
317
|
return { partial: body, created: status === 201 };
|
|
197
318
|
},
|
|
198
319
|
/** Removes a partial; templates that still include it fail to render afterwards. */
|
|
199
|
-
delete: (name, options = {}) => this.request(
|
|
320
|
+
delete: (name, options = {}) => this.request(
|
|
321
|
+
"DELETE",
|
|
322
|
+
`/partials/${encodeURIComponent(name)}`,
|
|
323
|
+
void 0,
|
|
324
|
+
options
|
|
325
|
+
)
|
|
200
326
|
};
|
|
201
327
|
jobs = {
|
|
202
|
-
get: (id, options = {}) => this.request(
|
|
328
|
+
get: (id, options = {}) => this.request(
|
|
329
|
+
"GET",
|
|
330
|
+
`/jobs/${encodeURIComponent(id)}`,
|
|
331
|
+
void 0,
|
|
332
|
+
options
|
|
333
|
+
),
|
|
203
334
|
waitFor: async (id, options = {}) => {
|
|
204
335
|
const deadline = Date.now() + (options.timeoutMs ?? 6e5);
|
|
205
336
|
const interval = options.intervalMs ?? 2e3;
|
|
@@ -207,37 +338,77 @@ var Formfeed = class {
|
|
|
207
338
|
const job = await this.jobs.get(id, { signal: options.signal });
|
|
208
339
|
if (job.status !== "queued" && job.status !== "processing") return job;
|
|
209
340
|
if (Date.now() + interval > deadline)
|
|
210
|
-
throw new FormfeedError(
|
|
341
|
+
throw new FormfeedError(
|
|
342
|
+
"timeout",
|
|
343
|
+
`job ${id} did not finish within the wait time`,
|
|
344
|
+
0
|
|
345
|
+
);
|
|
211
346
|
await sleep(interval, options.signal);
|
|
212
347
|
}
|
|
213
348
|
}
|
|
214
349
|
};
|
|
215
350
|
webhooks = {
|
|
216
|
-
list: async (options = {}) => (await this.request(
|
|
351
|
+
list: async (options = {}) => (await this.request(
|
|
352
|
+
"GET",
|
|
353
|
+
"/webhooks",
|
|
354
|
+
void 0,
|
|
355
|
+
options
|
|
356
|
+
)).data,
|
|
217
357
|
create: (input, options = {}) => this.request("POST", "/webhooks", input, options),
|
|
218
|
-
update: (id, patch, options = {}) => this.request(
|
|
219
|
-
|
|
220
|
-
|
|
358
|
+
update: (id, patch, options = {}) => this.request(
|
|
359
|
+
"PUT",
|
|
360
|
+
`/webhooks/${encodeURIComponent(id)}`,
|
|
361
|
+
patch,
|
|
362
|
+
options
|
|
363
|
+
),
|
|
364
|
+
delete: (id, options = {}) => this.request(
|
|
365
|
+
"DELETE",
|
|
366
|
+
`/webhooks/${encodeURIComponent(id)}`,
|
|
367
|
+
void 0,
|
|
368
|
+
options
|
|
369
|
+
),
|
|
370
|
+
test: (id, options = {}) => this.request(
|
|
371
|
+
"POST",
|
|
372
|
+
`/webhooks/${encodeURIComponent(id)}/test`,
|
|
373
|
+
void 0,
|
|
374
|
+
options
|
|
375
|
+
),
|
|
221
376
|
/**
|
|
222
377
|
* Sends a stored event (`evt_…`) again as a new delivery to a registered endpoint (`webhook:manage`)
|
|
223
378
|
* or a running listen session (`webhook:listen`).
|
|
224
379
|
*/
|
|
225
|
-
resend: (eventId, endpointId, options = {}) => this.request(
|
|
380
|
+
resend: (eventId, endpointId, options = {}) => this.request(
|
|
381
|
+
"POST",
|
|
382
|
+
`/webhooks/events/${encodeURIComponent(eventId)}/resend`,
|
|
383
|
+
{ endpoint_id: endpointId },
|
|
384
|
+
options
|
|
385
|
+
),
|
|
226
386
|
/**
|
|
227
387
|
* Listen sessions, what `formfeed listen` uses. Needs `webhook:listen`. Starting a session ends the
|
|
228
388
|
* previous one of the same key; the WebSocket itself is up to the caller.
|
|
229
389
|
*/
|
|
230
390
|
listen: {
|
|
231
391
|
start: (input = {}, options = {}) => this.request("POST", "/webhooks/listen", input, options),
|
|
232
|
-
end: (id, options = {}) => this.request(
|
|
392
|
+
end: (id, options = {}) => this.request(
|
|
393
|
+
"DELETE",
|
|
394
|
+
`/webhooks/listen/${encodeURIComponent(id)}`,
|
|
395
|
+
void 0,
|
|
396
|
+
options
|
|
397
|
+
)
|
|
233
398
|
}
|
|
234
399
|
};
|
|
235
400
|
templates = {
|
|
236
401
|
list: (query = {}, options = {}) => {
|
|
237
402
|
const params = new URLSearchParams();
|
|
238
|
-
for (const [k, v] of Object.entries(query))
|
|
403
|
+
for (const [k, v] of Object.entries(query))
|
|
404
|
+
if (v !== void 0 && v !== null && v !== "") params.set(k, String(v));
|
|
239
405
|
const qs = params.toString();
|
|
240
|
-
return this.request(
|
|
406
|
+
return this.request(
|
|
407
|
+
"GET",
|
|
408
|
+
`/templates${qs ? `?${qs}` : ""}`,
|
|
409
|
+
void 0,
|
|
410
|
+
options
|
|
411
|
+
);
|
|
241
412
|
},
|
|
242
413
|
/** Every template of the workspace, following the cursor. */
|
|
243
414
|
all: async (query = {}, options = {}) => {
|
|
@@ -250,27 +421,63 @@ var Formfeed = class {
|
|
|
250
421
|
} while (cursor);
|
|
251
422
|
return out;
|
|
252
423
|
},
|
|
253
|
-
get: (idOrSlug, options = {}) => this.request(
|
|
424
|
+
get: (idOrSlug, options = {}) => this.request(
|
|
425
|
+
"GET",
|
|
426
|
+
`/templates/${encodeURIComponent(idOrSlug)}`,
|
|
427
|
+
void 0,
|
|
428
|
+
options
|
|
429
|
+
),
|
|
254
430
|
/** A Word or PowerPoint template (`kind` `docx` or `pptx`) is created from its `file`, sent as multipart. */
|
|
255
431
|
create: (input, options = {}) => {
|
|
256
432
|
if (isOfficeInput(input) && input.file) {
|
|
257
433
|
const { file, ...fields } = input;
|
|
258
|
-
return this.request(
|
|
434
|
+
return this.request(
|
|
435
|
+
"POST",
|
|
436
|
+
"/templates",
|
|
437
|
+
multipart(fields, file),
|
|
438
|
+
options
|
|
439
|
+
);
|
|
259
440
|
}
|
|
260
441
|
return this.request("POST", "/templates", input, options);
|
|
261
442
|
},
|
|
262
|
-
update: (idOrSlug, patch, options = {}) => this.request(
|
|
263
|
-
|
|
443
|
+
update: (idOrSlug, patch, options = {}) => this.request(
|
|
444
|
+
"PUT",
|
|
445
|
+
`/templates/${encodeURIComponent(idOrSlug)}`,
|
|
446
|
+
patch,
|
|
447
|
+
options
|
|
448
|
+
),
|
|
449
|
+
archive: (idOrSlug, options = {}) => this.request(
|
|
450
|
+
"DELETE",
|
|
451
|
+
`/templates/${encodeURIComponent(idOrSlug)}`,
|
|
452
|
+
void 0,
|
|
453
|
+
options
|
|
454
|
+
),
|
|
264
455
|
versions: {
|
|
265
|
-
list: async (idOrSlug, options = {}) => (await this.request(
|
|
456
|
+
list: async (idOrSlug, options = {}) => (await this.request(
|
|
457
|
+
"GET",
|
|
458
|
+
`/templates/${encodeURIComponent(idOrSlug)}/versions`,
|
|
459
|
+
void 0,
|
|
460
|
+
options
|
|
461
|
+
)).data,
|
|
266
462
|
/** `which`: 'published', 'latest', a version number or a channel name (its main version). Carries the files. */
|
|
267
|
-
get: (idOrSlug, which = "published", options = {}) => this.request(
|
|
463
|
+
get: (idOrSlug, which = "published", options = {}) => this.request(
|
|
464
|
+
"GET",
|
|
465
|
+
`/templates/${encodeURIComponent(idOrSlug)}/versions/${encodeURIComponent(String(which))}`,
|
|
466
|
+
void 0,
|
|
467
|
+
options
|
|
468
|
+
),
|
|
268
469
|
/** For a Word or PowerPoint template, pass `file` to replace the document; without it the latest file is kept. */
|
|
269
470
|
create: (idOrSlug, input, options = {}) => {
|
|
270
471
|
const path = `/templates/${encodeURIComponent(idOrSlug)}/versions`;
|
|
271
472
|
if (isOfficeInput(input)) {
|
|
272
473
|
const { file, ...fields } = input;
|
|
273
|
-
if (file)
|
|
474
|
+
if (file)
|
|
475
|
+
return this.request(
|
|
476
|
+
"POST",
|
|
477
|
+
path,
|
|
478
|
+
multipart(fields, file),
|
|
479
|
+
options
|
|
480
|
+
);
|
|
274
481
|
return this.request("POST", path, fields, options);
|
|
275
482
|
}
|
|
276
483
|
return this.request("POST", path, input, options);
|
|
@@ -299,7 +506,12 @@ var Formfeed = class {
|
|
|
299
506
|
* uses the version the channel points at. Moves reach renders within a minute.
|
|
300
507
|
*/
|
|
301
508
|
channels: {
|
|
302
|
-
list: (idOrSlug, options = {}) => this.request(
|
|
509
|
+
list: (idOrSlug, options = {}) => this.request(
|
|
510
|
+
"GET",
|
|
511
|
+
`/templates/${encodeURIComponent(idOrSlug)}/channels`,
|
|
512
|
+
void 0,
|
|
513
|
+
options
|
|
514
|
+
),
|
|
303
515
|
/** Creates or moves a channel; on `published` this publishes. */
|
|
304
516
|
set: (idOrSlug, name, move, options = {}) => {
|
|
305
517
|
const { allowBreaking, ...rest } = options;
|
|
@@ -333,19 +545,39 @@ var Formfeed = class {
|
|
|
333
545
|
schema: (idOrSlug, options = {}) => {
|
|
334
546
|
const { version, ...rest } = options;
|
|
335
547
|
const query = version === void 0 ? "" : `?version=${encodeURIComponent(String(version))}`;
|
|
336
|
-
return this.request(
|
|
548
|
+
return this.request(
|
|
549
|
+
"GET",
|
|
550
|
+
`/templates/${encodeURIComponent(idOrSlug)}/schema${query}`,
|
|
551
|
+
void 0,
|
|
552
|
+
rest
|
|
553
|
+
);
|
|
337
554
|
},
|
|
338
555
|
/**
|
|
339
556
|
* Checks a version with data without rendering: syntax, header and footer, missing partials,
|
|
340
557
|
* runtime errors and the data against the stored schema. Free. Without `data`, the version's
|
|
341
558
|
* sample data is checked. `version` takes a channel name too.
|
|
342
559
|
*/
|
|
343
|
-
validate: (idOrSlug, input = {}, options = {}) => this.request(
|
|
560
|
+
validate: (idOrSlug, input = {}, options = {}) => this.request(
|
|
561
|
+
"POST",
|
|
562
|
+
`/templates/${encodeURIComponent(idOrSlug)}/validate`,
|
|
563
|
+
input,
|
|
564
|
+
options
|
|
565
|
+
)
|
|
344
566
|
};
|
|
345
567
|
account = {
|
|
346
|
-
get: (options = {}) => this.request(
|
|
568
|
+
get: (options = {}) => this.request(
|
|
569
|
+
"GET",
|
|
570
|
+
"/account",
|
|
571
|
+
void 0,
|
|
572
|
+
options
|
|
573
|
+
),
|
|
347
574
|
/** Units of the current period, or of `YYYY-MM`, with a daily series and a breakdown per template. */
|
|
348
|
-
usage: (period = "current", options = {}) => this.request(
|
|
575
|
+
usage: (period = "current", options = {}) => this.request(
|
|
576
|
+
"GET",
|
|
577
|
+
`/usage?period=${encodeURIComponent(period)}`,
|
|
578
|
+
void 0,
|
|
579
|
+
options
|
|
580
|
+
)
|
|
349
581
|
};
|
|
350
582
|
/** Workspaces of the key's organisation. Needs `workspace:delete`, which no key has by default. */
|
|
351
583
|
workspaces = {
|
|
@@ -353,7 +585,12 @@ var Formfeed = class {
|
|
|
353
585
|
* Deletes a workspace: it leaves the app and the API at once, its keys are revoked and its content
|
|
354
586
|
* is removed after 30 days. The organisation's last workspace is refused with `last_workspace`.
|
|
355
587
|
*/
|
|
356
|
-
delete: (id, options = {}) => this.request(
|
|
588
|
+
delete: (id, options = {}) => this.request(
|
|
589
|
+
"DELETE",
|
|
590
|
+
`/workspaces/${encodeURIComponent(id)}`,
|
|
591
|
+
void 0,
|
|
592
|
+
options
|
|
593
|
+
)
|
|
357
594
|
};
|
|
358
595
|
channelAction(idOrSlug, name, action, options) {
|
|
359
596
|
const { allowBreaking, ...rest } = options;
|
|
@@ -381,13 +618,21 @@ var Formfeed = class {
|
|
|
381
618
|
...this.extraHeaders
|
|
382
619
|
};
|
|
383
620
|
const isForm = typeof FormData !== "undefined" && body instanceof FormData;
|
|
384
|
-
if (body !== void 0 && !isForm)
|
|
385
|
-
|
|
621
|
+
if (body !== void 0 && !isForm)
|
|
622
|
+
headers["content-type"] = "application/json";
|
|
623
|
+
if (options.idempotencyKey)
|
|
624
|
+
headers["idempotency-key"] = options.idempotencyKey;
|
|
386
625
|
let attempt = 0;
|
|
387
626
|
for (; ; ) {
|
|
388
627
|
const controller = new AbortController();
|
|
389
|
-
const timer = setTimeout(
|
|
390
|
-
|
|
628
|
+
const timer = setTimeout(
|
|
629
|
+
() => controller.abort(new Error("request timed out")),
|
|
630
|
+
this.timeoutMs
|
|
631
|
+
);
|
|
632
|
+
options.signal?.addEventListener(
|
|
633
|
+
"abort",
|
|
634
|
+
() => controller.abort(options.signal?.reason)
|
|
635
|
+
);
|
|
391
636
|
let res;
|
|
392
637
|
try {
|
|
393
638
|
res = await this.fetchImpl(url, {
|
|
@@ -403,22 +648,38 @@ var Formfeed = class {
|
|
|
403
648
|
await sleep(this.backoff(attempt, null), options.signal);
|
|
404
649
|
continue;
|
|
405
650
|
}
|
|
406
|
-
throw new FormfeedError(
|
|
651
|
+
throw new FormfeedError(
|
|
652
|
+
"network_error",
|
|
653
|
+
e instanceof Error ? e.message : String(e),
|
|
654
|
+
0
|
|
655
|
+
);
|
|
407
656
|
}
|
|
408
657
|
clearTimeout(timer);
|
|
409
658
|
if ((res.status === 429 || res.status === 503) && attempt < this.maxRetries) {
|
|
410
659
|
attempt++;
|
|
411
|
-
await sleep(
|
|
660
|
+
await sleep(
|
|
661
|
+
this.backoff(attempt, res.headers.get("retry-after")),
|
|
662
|
+
options.signal
|
|
663
|
+
);
|
|
412
664
|
continue;
|
|
413
665
|
}
|
|
414
666
|
if (res.status === 204) return { status: 204, body: void 0 };
|
|
415
|
-
if (as === "bytes" && res.ok)
|
|
667
|
+
if (as === "bytes" && res.ok)
|
|
668
|
+
return {
|
|
669
|
+
status: res.status,
|
|
670
|
+
body: new Uint8Array(await res.arrayBuffer())
|
|
671
|
+
};
|
|
416
672
|
const text = await res.text();
|
|
417
673
|
let json = null;
|
|
418
674
|
try {
|
|
419
675
|
json = text ? JSON.parse(text) : null;
|
|
420
676
|
} catch {
|
|
421
|
-
if (res.ok)
|
|
677
|
+
if (res.ok)
|
|
678
|
+
throw new FormfeedError(
|
|
679
|
+
"invalid_response",
|
|
680
|
+
`the API answered HTTP ${res.status} with a body that is not JSON`,
|
|
681
|
+
res.status
|
|
682
|
+
);
|
|
422
683
|
}
|
|
423
684
|
if (!res.ok) {
|
|
424
685
|
const problem = json ?? {};
|
package/package.json
CHANGED
package/types/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { Formfeed, FormfeedError } from './lib/client.cjs';
|
|
2
|
-
export type { Template, TemplateCreate, TemplateFiles, TemplateKind, TemplateListOptions, TemplateValidation, VersionRef, TemplateVersion, TemplateVersionCreate, TemplateFile, OfficeTemplateKind, OfficeTemplateCreate, OfficeVersionCreate, OfficeFileUpload, ConvertOptions, VersionStatus, BatchRequest, Channel, ChannelList, ChannelMove, Brand, SharedPartial, SharedPartialPut, SharedPartialPutResult, Diagnostic, Engine, FileListOptions, FileUpload, FormfeedOptions, FormfeedTemplates, Job, LibraryFile, OutputFormat, PdfInfo, PdfOutputOptions, PdfPermission, PostProcessing, Problem, StorageDelivery, StorageDeliveryEvent, StorageError, StorageOption, WebhookEventType, ProtectOptions, Region, Render, RenderListOptions, RenderRequest, RenderStatus, TemplateData, TypedRenderRequest, RequestOptions, SchemaChange, SchemaCheck, SchemaGuardOptions, Usage, WaitOptions, WatermarkOptions, WebhookEndpoint, WebhookEndpointCreate, WebhookEndpointUpdate, WebhookEnvironment, WebhookResend, ListenSession, ListenSessionOptions, RenderInput, } from './lib/client.cjs';
|
|
2
|
+
export type { Template, TemplateCreate, TemplateFiles, TemplateKind, TemplateListOptions, TemplateValidation, VersionRef, TemplateVersion, TemplateVersionCreate, TemplateFile, OfficeTemplateKind, OfficeTemplateCreate, OfficeVersionCreate, OfficeFileUpload, ConvertOptions, VersionStatus, BatchRequest, Channel, ChannelList, ChannelMove, Brand, SharedPartial, SharedPartialPut, SharedPartialPutResult, Diagnostic, Engine, FileListOptions, FileUpload, FormfeedOptions, FormfeedTemplates, Job, LibraryFile, OutputFormat, PdfInfo, PdfOutputOptions, PdfPermission, PostProcessing, Einvoice, EinvoiceMessage, EinvoiceOptions, Accessibility, AccessibilityFailure, AccessibilityWarning, PdfUaOptions, Problem, StorageDelivery, StorageDeliveryEvent, StorageError, StorageOption, WebhookEventType, ProtectOptions, Region, Render, RenderListOptions, RenderRequest, RenderStatus, TemplateData, TypedRenderRequest, RequestOptions, SchemaChange, SchemaCheck, SchemaGuardOptions, Usage, WaitOptions, WatermarkOptions, WebhookEndpoint, WebhookEndpointCreate, WebhookEndpointUpdate, WebhookEnvironment, WebhookResend, ListenSession, ListenSessionOptions, RenderInput, } from './lib/client.cjs';
|
|
3
3
|
export { parseWebhookEvent, verifyWebhookSignature } from './lib/webhooks.cjs';
|
|
4
4
|
export type { VerifyOptions } from './lib/webhooks.cjs';
|
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { Formfeed, FormfeedError } from './lib/client.js';
|
|
2
|
-
export type { Template, TemplateCreate, TemplateFiles, TemplateKind, TemplateListOptions, TemplateValidation, VersionRef, TemplateVersion, TemplateVersionCreate, TemplateFile, OfficeTemplateKind, OfficeTemplateCreate, OfficeVersionCreate, OfficeFileUpload, ConvertOptions, VersionStatus, BatchRequest, Channel, ChannelList, ChannelMove, Brand, SharedPartial, SharedPartialPut, SharedPartialPutResult, Diagnostic, Engine, FileListOptions, FileUpload, FormfeedOptions, FormfeedTemplates, Job, LibraryFile, OutputFormat, PdfInfo, PdfOutputOptions, PdfPermission, PostProcessing, Problem, StorageDelivery, StorageDeliveryEvent, StorageError, StorageOption, WebhookEventType, ProtectOptions, Region, Render, RenderListOptions, RenderRequest, RenderStatus, TemplateData, TypedRenderRequest, RequestOptions, SchemaChange, SchemaCheck, SchemaGuardOptions, Usage, WaitOptions, WatermarkOptions, WebhookEndpoint, WebhookEndpointCreate, WebhookEndpointUpdate, WebhookEnvironment, WebhookResend, ListenSession, ListenSessionOptions, RenderInput, } from './lib/client.js';
|
|
2
|
+
export type { Template, TemplateCreate, TemplateFiles, TemplateKind, TemplateListOptions, TemplateValidation, VersionRef, TemplateVersion, TemplateVersionCreate, TemplateFile, OfficeTemplateKind, OfficeTemplateCreate, OfficeVersionCreate, OfficeFileUpload, ConvertOptions, VersionStatus, BatchRequest, Channel, ChannelList, ChannelMove, Brand, SharedPartial, SharedPartialPut, SharedPartialPutResult, Diagnostic, Engine, FileListOptions, FileUpload, FormfeedOptions, FormfeedTemplates, Job, LibraryFile, OutputFormat, PdfInfo, PdfOutputOptions, PdfPermission, PostProcessing, Einvoice, EinvoiceMessage, EinvoiceOptions, Accessibility, AccessibilityFailure, AccessibilityWarning, PdfUaOptions, Problem, StorageDelivery, StorageDeliveryEvent, StorageError, StorageOption, WebhookEventType, ProtectOptions, Region, Render, RenderListOptions, RenderRequest, RenderStatus, TemplateData, TypedRenderRequest, RequestOptions, SchemaChange, SchemaCheck, SchemaGuardOptions, Usage, WaitOptions, WatermarkOptions, WebhookEndpoint, WebhookEndpointCreate, WebhookEndpointUpdate, WebhookEnvironment, WebhookResend, ListenSession, ListenSessionOptions, RenderInput, } from './lib/client.js';
|
|
3
3
|
export { parseWebhookEvent, verifyWebhookSignature } from './lib/webhooks.js';
|
|
4
4
|
export type { VerifyOptions } from './lib/webhooks.js';
|