@dokus/client 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +36 -0
- package/README.md +114 -0
- package/dist/browser-denied.d.ts +8 -0
- package/dist/browser-denied.js +12 -0
- package/dist/chunk-RJGJ7P2Y.js +73 -0
- package/dist/errors-Ce8Vc6yb.d.ts +45 -0
- package/dist/index.d.ts +211 -0
- package/dist/index.js +1424 -0
- package/package.json +45 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1424 @@
|
|
|
1
|
+
import { DokusValidationError, DokusAbortError, DokusTimeoutError, DokusConnectionError, DokusWaitTimeoutError, DokusProtocolError, DokusResponseTooLargeError, DokusApiError } from './chunk-RJGJ7P2Y.js';
|
|
2
|
+
export { DokusAbortError, DokusApiError, DokusConnectionError, DokusError, DokusProtocolError, DokusResponseTooLargeError, DokusTimeoutError, DokusValidationError, DokusWaitTimeoutError } from './chunk-RJGJ7P2Y.js';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
|
|
5
|
+
// src/validation.ts
|
|
6
|
+
var OPAQUE_ID_PATTERN = /^[A-Za-z0-9._:-]{8,128}$/;
|
|
7
|
+
var UUID_PATTERN = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
|
|
8
|
+
function assertExactDataObject(value, allowedKeys, label) {
|
|
9
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
10
|
+
throw new DokusValidationError(`${label} must be a plain data object.`);
|
|
11
|
+
}
|
|
12
|
+
let prototype;
|
|
13
|
+
let descriptors2;
|
|
14
|
+
try {
|
|
15
|
+
prototype = Object.getPrototypeOf(value);
|
|
16
|
+
descriptors2 = Object.getOwnPropertyDescriptors(value);
|
|
17
|
+
} catch {
|
|
18
|
+
throw new DokusValidationError(`${label} must be a plain data object.`);
|
|
19
|
+
}
|
|
20
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
21
|
+
throw new DokusValidationError(`${label} must be a plain data object.`);
|
|
22
|
+
}
|
|
23
|
+
for (const key of Reflect.ownKeys(descriptors2)) {
|
|
24
|
+
const descriptor = descriptors2[key];
|
|
25
|
+
if (!descriptor) continue;
|
|
26
|
+
if (!("value" in descriptor)) {
|
|
27
|
+
throw new DokusValidationError(`${label} must not contain accessors.`);
|
|
28
|
+
}
|
|
29
|
+
if (typeof key !== "string" || !allowedKeys.has(key)) {
|
|
30
|
+
throw new DokusValidationError(
|
|
31
|
+
`${label} contains unsupported field ${JSON.stringify(String(key))}.`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (!descriptor.enumerable) {
|
|
35
|
+
throw new DokusValidationError(
|
|
36
|
+
`${label} field ${JSON.stringify(key)} must be enumerable.`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
for (const key of allowedKeys) {
|
|
42
|
+
if (!Object.hasOwn(value, key) && key in value) {
|
|
43
|
+
throw new DokusValidationError(
|
|
44
|
+
`${label} field ${JSON.stringify(key)} must be an own data property.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error instanceof DokusValidationError) throw error;
|
|
50
|
+
throw new DokusValidationError(`${label} must be a plain data object.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function assertPlainObject(value, label) {
|
|
54
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
55
|
+
throw new DokusValidationError(`${label} must be a plain data object.`);
|
|
56
|
+
}
|
|
57
|
+
let prototype;
|
|
58
|
+
try {
|
|
59
|
+
prototype = Object.getPrototypeOf(value);
|
|
60
|
+
} catch {
|
|
61
|
+
throw new DokusValidationError(`${label} must be a plain data object.`);
|
|
62
|
+
}
|
|
63
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
64
|
+
throw new DokusValidationError(`${label} must be a plain data object.`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function assertOptionalBoolean(value, label) {
|
|
68
|
+
if (value !== void 0 && typeof value !== "boolean") {
|
|
69
|
+
throw new DokusValidationError(`${label} must be a boolean.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function assertOptionalString(value, label) {
|
|
73
|
+
if (value !== void 0 && typeof value !== "string") {
|
|
74
|
+
throw new DokusValidationError(`${label} must be a string.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function assertOptionalEnum(value, allowed, label) {
|
|
78
|
+
if (value !== void 0 && !allowed.includes(value)) {
|
|
79
|
+
throw new DokusValidationError(
|
|
80
|
+
`${label} must be one of ${allowed.map((entry) => JSON.stringify(entry)).join(", ")}.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function assertNonEmpty(value, label) {
|
|
85
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
86
|
+
throw new DokusValidationError(`${label} must be a non-empty string.`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function pathSegment(value, label) {
|
|
90
|
+
assertNonEmpty(value, label);
|
|
91
|
+
if (value.trim() !== value) {
|
|
92
|
+
throw new DokusValidationError(
|
|
93
|
+
`${label} must not contain surrounding whitespace.`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (!UUID_PATTERN.test(value)) {
|
|
97
|
+
throw new DokusValidationError(`${label} must be a UUID.`);
|
|
98
|
+
}
|
|
99
|
+
return encodeURIComponent(value);
|
|
100
|
+
}
|
|
101
|
+
function assertOpaqueId(value, label) {
|
|
102
|
+
if (!OPAQUE_ID_PATTERN.test(value)) {
|
|
103
|
+
throw new DokusValidationError(
|
|
104
|
+
`${label} must be 8-128 characters using letters, numbers, dot, colon, underscore, or hyphen.`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function requireIdempotencyKey(options) {
|
|
109
|
+
const key = options?.idempotencyKey;
|
|
110
|
+
if (typeof key !== "string") {
|
|
111
|
+
throw new DokusValidationError(
|
|
112
|
+
"A validated idempotencyKey is required for this state-changing request."
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
assertOpaqueId(key, "idempotencyKey");
|
|
116
|
+
return key;
|
|
117
|
+
}
|
|
118
|
+
function assertPositiveFinite(value, label) {
|
|
119
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
120
|
+
throw new DokusValidationError(
|
|
121
|
+
`${label} must be a positive finite number.`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function assertTimerMs(value, label) {
|
|
126
|
+
assertPositiveFinite(value, label);
|
|
127
|
+
if (value > 2147483647) {
|
|
128
|
+
throw new DokusValidationError(
|
|
129
|
+
`${label} exceeds the supported timer range.`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function assertPositiveInteger(value, label) {
|
|
134
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
135
|
+
throw new DokusValidationError(`${label} must be a positive safe integer.`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function toEpochMs(value) {
|
|
139
|
+
if (value === null) return null;
|
|
140
|
+
const epochMs = value instanceof Date ? value.getTime() : value;
|
|
141
|
+
if (!Number.isSafeInteger(epochMs) || epochMs <= 0) {
|
|
142
|
+
throw new DokusValidationError(
|
|
143
|
+
"expireAt must be null, a valid Date, or a positive epoch-millisecond integer."
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return epochMs;
|
|
147
|
+
}
|
|
148
|
+
function expireAtQuery(value) {
|
|
149
|
+
if (value === void 0) return void 0;
|
|
150
|
+
const epochMs = toEpochMs(value);
|
|
151
|
+
return epochMs === null ? "never" : String(epochMs);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/public-options.ts
|
|
155
|
+
var REQUEST_KEYS = /* @__PURE__ */ new Set(["signal", "timeoutMs", "requestId"]);
|
|
156
|
+
var WRITE_KEYS = /* @__PURE__ */ new Set([
|
|
157
|
+
"signal",
|
|
158
|
+
"timeoutMs",
|
|
159
|
+
"requestId",
|
|
160
|
+
"idempotencyKey"
|
|
161
|
+
]);
|
|
162
|
+
var RUN_GET_KEYS = /* @__PURE__ */ new Set(["signal", "timeoutMs", "requestId", "expireAt"]);
|
|
163
|
+
var DOCUMENT_RUNS_KEYS = /* @__PURE__ */ new Set([
|
|
164
|
+
"signal",
|
|
165
|
+
"timeoutMs",
|
|
166
|
+
"requestId",
|
|
167
|
+
"limit"
|
|
168
|
+
]);
|
|
169
|
+
var WAIT_KEYS = /* @__PURE__ */ new Set([
|
|
170
|
+
"expireAt",
|
|
171
|
+
"signal",
|
|
172
|
+
"requestId",
|
|
173
|
+
"intervalMs",
|
|
174
|
+
"timeoutMs",
|
|
175
|
+
"requestTimeoutMs"
|
|
176
|
+
]);
|
|
177
|
+
var ROTATE_KEYS = /* @__PURE__ */ new Set([
|
|
178
|
+
"signal",
|
|
179
|
+
"timeoutMs",
|
|
180
|
+
"requestId",
|
|
181
|
+
"idempotencyKey",
|
|
182
|
+
"allowDownload",
|
|
183
|
+
"expiresIn"
|
|
184
|
+
]);
|
|
185
|
+
var EXPIRES_IN_KEYS = /* @__PURE__ */ new Set(["days"]);
|
|
186
|
+
function assertSignal(value, label) {
|
|
187
|
+
if (value !== void 0 && !(value instanceof AbortSignal)) {
|
|
188
|
+
throw new DokusValidationError(`${label} must be an AbortSignal.`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function assertRequestFields(options, label) {
|
|
192
|
+
assertSignal(options.signal, `${label}.signal`);
|
|
193
|
+
if (options.timeoutMs !== void 0) {
|
|
194
|
+
assertTimerMs(options.timeoutMs, `${label}.timeoutMs`);
|
|
195
|
+
}
|
|
196
|
+
if (options.requestId !== void 0) {
|
|
197
|
+
assertOpaqueId(options.requestId, `${label}.requestId`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function assertRequestOptions(options, label = "request options") {
|
|
201
|
+
if (options === void 0) return;
|
|
202
|
+
assertExactDataObject(options, REQUEST_KEYS, label);
|
|
203
|
+
assertRequestFields(options, label);
|
|
204
|
+
}
|
|
205
|
+
function assertWriteOptions(options, label = "write options") {
|
|
206
|
+
if (options === void 0) {
|
|
207
|
+
throw new DokusValidationError(`${label} are required.`);
|
|
208
|
+
}
|
|
209
|
+
assertExactDataObject(options, WRITE_KEYS, label);
|
|
210
|
+
assertRequestFields(options, label);
|
|
211
|
+
requireIdempotencyKey(options);
|
|
212
|
+
}
|
|
213
|
+
function assertRunGetOptions(options) {
|
|
214
|
+
if (options === void 0) return;
|
|
215
|
+
assertExactDataObject(options, RUN_GET_KEYS, "runs.get options");
|
|
216
|
+
assertRequestFields(options, "runs.get options");
|
|
217
|
+
if (options.expireAt !== void 0) toEpochMs(options.expireAt);
|
|
218
|
+
}
|
|
219
|
+
function assertDocumentRunsOptions(options) {
|
|
220
|
+
if (options === void 0) return;
|
|
221
|
+
assertExactDataObject(
|
|
222
|
+
options,
|
|
223
|
+
DOCUMENT_RUNS_KEYS,
|
|
224
|
+
"workflows.documentRuns options"
|
|
225
|
+
);
|
|
226
|
+
assertRequestFields(options, "workflows.documentRuns options");
|
|
227
|
+
if (options.limit !== void 0) {
|
|
228
|
+
assertPositiveInteger(
|
|
229
|
+
options.limit,
|
|
230
|
+
"workflows.documentRuns options.limit"
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function assertWaitOptions(options) {
|
|
235
|
+
if (options === void 0) return;
|
|
236
|
+
assertExactDataObject(options, WAIT_KEYS, "runs.wait options");
|
|
237
|
+
assertSignal(options.signal, "runs.wait options.signal");
|
|
238
|
+
if (options.requestId !== void 0) {
|
|
239
|
+
assertOpaqueId(options.requestId, "runs.wait options.requestId");
|
|
240
|
+
}
|
|
241
|
+
if (options.expireAt !== void 0) toEpochMs(options.expireAt);
|
|
242
|
+
if (options.intervalMs !== void 0) {
|
|
243
|
+
assertTimerMs(options.intervalMs, "runs.wait options.intervalMs");
|
|
244
|
+
}
|
|
245
|
+
if (options.timeoutMs !== void 0) {
|
|
246
|
+
assertTimerMs(options.timeoutMs, "runs.wait options.timeoutMs");
|
|
247
|
+
}
|
|
248
|
+
if (options.requestTimeoutMs !== void 0) {
|
|
249
|
+
assertTimerMs(
|
|
250
|
+
options.requestTimeoutMs,
|
|
251
|
+
"runs.wait options.requestTimeoutMs"
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function assertRotateOptions(options) {
|
|
256
|
+
if (options === void 0) {
|
|
257
|
+
throw new DokusValidationError(
|
|
258
|
+
"runs.rotatePreviewLink options are required."
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
assertExactDataObject(options, ROTATE_KEYS, "runs.rotatePreviewLink options");
|
|
262
|
+
assertRequestFields(options, "runs.rotatePreviewLink options");
|
|
263
|
+
requireIdempotencyKey(options);
|
|
264
|
+
assertOptionalBoolean(
|
|
265
|
+
options.allowDownload,
|
|
266
|
+
"runs.rotatePreviewLink options.allowDownload"
|
|
267
|
+
);
|
|
268
|
+
if (options.expiresIn !== void 0 && options.expiresIn !== null) {
|
|
269
|
+
assertExactDataObject(
|
|
270
|
+
options.expiresIn,
|
|
271
|
+
EXPIRES_IN_KEYS,
|
|
272
|
+
"runs.rotatePreviewLink options.expiresIn"
|
|
273
|
+
);
|
|
274
|
+
assertPositiveInteger(
|
|
275
|
+
options.expiresIn.days,
|
|
276
|
+
"runs.rotatePreviewLink options.expiresIn.days"
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/response-validation.ts
|
|
282
|
+
var UUID_PATTERN2 = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
|
|
283
|
+
function invalid(requestId) {
|
|
284
|
+
throw new DokusProtocolError(requestId);
|
|
285
|
+
}
|
|
286
|
+
function record(value, requestId) {
|
|
287
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
288
|
+
invalid(requestId);
|
|
289
|
+
}
|
|
290
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
291
|
+
let keys;
|
|
292
|
+
try {
|
|
293
|
+
keys = Object.keys(value);
|
|
294
|
+
} catch {
|
|
295
|
+
invalid(requestId);
|
|
296
|
+
}
|
|
297
|
+
for (const key of keys) {
|
|
298
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
299
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) continue;
|
|
300
|
+
Object.defineProperty(result, key, {
|
|
301
|
+
enumerable: true,
|
|
302
|
+
value: descriptor.value
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
function string(value, requestId) {
|
|
308
|
+
return typeof value === "string" ? value : invalid(requestId);
|
|
309
|
+
}
|
|
310
|
+
function nullableString(value, requestId) {
|
|
311
|
+
return value === null ? null : string(value, requestId);
|
|
312
|
+
}
|
|
313
|
+
function uuid(value, requestId) {
|
|
314
|
+
return typeof value === "string" && UUID_PATTERN2.test(value) ? value : invalid(requestId);
|
|
315
|
+
}
|
|
316
|
+
function nullableUuid(value, requestId) {
|
|
317
|
+
return value === null ? null : uuid(value, requestId);
|
|
318
|
+
}
|
|
319
|
+
function nullableNumber(value, requestId) {
|
|
320
|
+
return value === null || typeof value === "number" && Number.isFinite(value) ? value : invalid(requestId);
|
|
321
|
+
}
|
|
322
|
+
function oneOf(value, allowed, requestId) {
|
|
323
|
+
return typeof value === "string" && allowed.includes(value) ? value : invalid(requestId);
|
|
324
|
+
}
|
|
325
|
+
function optionalString(source, key, requestId) {
|
|
326
|
+
return source[key] === void 0 ? void 0 : string(source[key], requestId);
|
|
327
|
+
}
|
|
328
|
+
function parsePreviewLink(value, requestId) {
|
|
329
|
+
if (value === null) return null;
|
|
330
|
+
const source = record(value, requestId);
|
|
331
|
+
if (typeof source.allowDownload !== "boolean") invalid(requestId);
|
|
332
|
+
return {
|
|
333
|
+
status: oneOf(source.status, ["issued", "revoked"], requestId),
|
|
334
|
+
createdAt: string(source.createdAt, requestId),
|
|
335
|
+
rotatedAt: nullableString(source.rotatedAt, requestId),
|
|
336
|
+
allowDownload: source.allowDownload,
|
|
337
|
+
expiresAt: nullableString(source.expiresAt, requestId)
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function parseOutput(value, requestId) {
|
|
341
|
+
const source = record(value, requestId);
|
|
342
|
+
if (!Number.isSafeInteger(source.id) || source.id <= 0)
|
|
343
|
+
invalid(requestId);
|
|
344
|
+
return {
|
|
345
|
+
id: source.id,
|
|
346
|
+
fileType: oneOf(source.fileType, ["docx", "xlsx", "pdf"], requestId),
|
|
347
|
+
outputFileName: string(source.outputFileName, requestId),
|
|
348
|
+
status: oneOf(
|
|
349
|
+
source.status,
|
|
350
|
+
["pending", "processing", "completed", "failed", "skipped"],
|
|
351
|
+
requestId
|
|
352
|
+
),
|
|
353
|
+
error: nullableString(source.error, requestId),
|
|
354
|
+
size: nullableNumber(source.size, requestId),
|
|
355
|
+
pages: nullableNumber(source.pages, requestId),
|
|
356
|
+
completedAt: nullableString(source.completedAt, requestId),
|
|
357
|
+
downloadUrl: nullableString(source.downloadUrl, requestId),
|
|
358
|
+
previewUrl: nullableString(source.previewUrl, requestId),
|
|
359
|
+
previewLink: parsePreviewLink(source.previewLink, requestId)
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function parseOutputs(value, requestId) {
|
|
363
|
+
if (!Array.isArray(value)) invalid(requestId);
|
|
364
|
+
return value.map((output) => parseOutput(output, requestId));
|
|
365
|
+
}
|
|
366
|
+
function parseRunResultResponse(value, requestId) {
|
|
367
|
+
const source = record(value, requestId);
|
|
368
|
+
return {
|
|
369
|
+
runId: uuid(source.runId, requestId),
|
|
370
|
+
workflowId: uuid(source.workflowId, requestId),
|
|
371
|
+
mode: oneOf(source.mode, ["sync", "async"], requestId),
|
|
372
|
+
status: oneOf(
|
|
373
|
+
source.status,
|
|
374
|
+
["pending", "running", "completed", "failed", "cancelled"],
|
|
375
|
+
requestId
|
|
376
|
+
),
|
|
377
|
+
startedAt: nullableString(source.startedAt, requestId),
|
|
378
|
+
completedAt: nullableString(source.completedAt, requestId),
|
|
379
|
+
error: nullableString(source.error, requestId),
|
|
380
|
+
createdAt: string(source.createdAt, requestId),
|
|
381
|
+
outputs: parseOutputs(source.outputs, requestId)
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function parseDocumentRenderCompletedResponse(value, requestId) {
|
|
385
|
+
const run = parseRunResultResponse(value, requestId);
|
|
386
|
+
if (run.mode !== "sync") invalid(requestId);
|
|
387
|
+
const source = record(value, requestId);
|
|
388
|
+
return {
|
|
389
|
+
...run,
|
|
390
|
+
documentId: uuid(source.documentId, requestId),
|
|
391
|
+
documentVersionId: uuid(source.documentVersionId, requestId),
|
|
392
|
+
planId: nullableUuid(source.planId, requestId),
|
|
393
|
+
mode: "sync"
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function parseDocumentRenderStartedResponse(value, requestId) {
|
|
397
|
+
const source = record(value, requestId);
|
|
398
|
+
return {
|
|
399
|
+
documentId: uuid(source.documentId, requestId),
|
|
400
|
+
documentVersionId: uuid(source.documentVersionId, requestId),
|
|
401
|
+
planId: nullableUuid(source.planId, requestId),
|
|
402
|
+
runId: uuid(source.runId, requestId),
|
|
403
|
+
workflowId: uuid(source.workflowId, requestId),
|
|
404
|
+
status: oneOf(source.status, ["pending"], requestId)
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
function parseRunOutputsResponse(value, requestId) {
|
|
408
|
+
const source = record(value, requestId);
|
|
409
|
+
return {
|
|
410
|
+
runId: uuid(source.runId, requestId),
|
|
411
|
+
outputs: parseOutputs(source.outputs, requestId)
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function parseOutputDownloadResponse(value, requestId) {
|
|
415
|
+
const source = record(value, requestId);
|
|
416
|
+
return {
|
|
417
|
+
url: string(source.url, requestId),
|
|
418
|
+
expiresAt: string(source.expiresAt, requestId)
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function parsePreviewLinkRotatedResponse(value, requestId) {
|
|
422
|
+
const source = record(value, requestId);
|
|
423
|
+
const previewLink = parsePreviewLink(source.previewLink, requestId);
|
|
424
|
+
if (previewLink === null) invalid(requestId);
|
|
425
|
+
return {
|
|
426
|
+
previewUrl: string(source.previewUrl, requestId),
|
|
427
|
+
previewLink
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function parseGenerateStartedResponse(value, requestId) {
|
|
431
|
+
const source = record(value, requestId);
|
|
432
|
+
return {
|
|
433
|
+
runId: uuid(source.runId, requestId),
|
|
434
|
+
temporalWorkflowId: string(source.temporalWorkflowId, requestId),
|
|
435
|
+
status: oneOf(source.status, ["started", "already_running"], requestId)
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function parseGenerateAllResponse(value, requestId) {
|
|
439
|
+
if (!Array.isArray(value)) invalid(requestId);
|
|
440
|
+
return value.map((entry) => {
|
|
441
|
+
const source = record(entry, requestId);
|
|
442
|
+
const runId = source.runId === void 0 ? void 0 : uuid(source.runId, requestId);
|
|
443
|
+
const temporalWorkflowId = optionalString(
|
|
444
|
+
source,
|
|
445
|
+
"temporalWorkflowId",
|
|
446
|
+
requestId
|
|
447
|
+
);
|
|
448
|
+
const error = optionalString(source, "error", requestId);
|
|
449
|
+
return {
|
|
450
|
+
documentId: uuid(source.documentId, requestId),
|
|
451
|
+
status: oneOf(
|
|
452
|
+
source.status,
|
|
453
|
+
["started", "already_running", "failed"],
|
|
454
|
+
requestId
|
|
455
|
+
),
|
|
456
|
+
...runId === void 0 ? {} : { runId },
|
|
457
|
+
...temporalWorkflowId === void 0 ? {} : { temporalWorkflowId },
|
|
458
|
+
...error === void 0 ? {} : { error }
|
|
459
|
+
};
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
function parseDocumentRunsResponse(value, requestId) {
|
|
463
|
+
if (!Array.isArray(value)) invalid(requestId);
|
|
464
|
+
return value.map((entry) => {
|
|
465
|
+
const source = record(entry, requestId);
|
|
466
|
+
if (!Number.isSafeInteger(source.outputCount) || source.outputCount < 0) {
|
|
467
|
+
invalid(requestId);
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
id: uuid(source.id, requestId),
|
|
471
|
+
workflowId: uuid(source.workflowId, requestId),
|
|
472
|
+
status: oneOf(
|
|
473
|
+
source.status,
|
|
474
|
+
["pending", "running", "completed", "failed", "cancelled"],
|
|
475
|
+
requestId
|
|
476
|
+
),
|
|
477
|
+
startedAt: nullableString(source.startedAt, requestId),
|
|
478
|
+
completedAt: nullableString(source.completedAt, requestId),
|
|
479
|
+
error: nullableString(source.error, requestId),
|
|
480
|
+
triggeredByType: string(source.triggeredByType, requestId),
|
|
481
|
+
triggeredById: nullableString(source.triggeredById, requestId),
|
|
482
|
+
createdAt: string(source.createdAt, requestId),
|
|
483
|
+
outputCount: source.outputCount
|
|
484
|
+
};
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/documents.ts
|
|
489
|
+
var RENDER_INPUT_KEYS = /* @__PURE__ */ new Set([
|
|
490
|
+
"documentId",
|
|
491
|
+
"planId",
|
|
492
|
+
"contract",
|
|
493
|
+
"data",
|
|
494
|
+
"generatePdf",
|
|
495
|
+
"generateDocx",
|
|
496
|
+
"expireAt",
|
|
497
|
+
"version",
|
|
498
|
+
"versionId",
|
|
499
|
+
"mode"
|
|
500
|
+
]);
|
|
501
|
+
function transportWriteOptions(options) {
|
|
502
|
+
assertWriteOptions(options, "documents.render options");
|
|
503
|
+
return {
|
|
504
|
+
signal: options.signal,
|
|
505
|
+
timeoutMs: options.timeoutMs,
|
|
506
|
+
requestId: options.requestId,
|
|
507
|
+
idempotencyKey: options.idempotencyKey
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
function assertRenderInput(input) {
|
|
511
|
+
assertExactDataObject(input, RENDER_INPUT_KEYS, "documents.render input");
|
|
512
|
+
pathSegment(input.documentId, "documentId");
|
|
513
|
+
if (input.planId !== void 0) pathSegment(input.planId, "planId");
|
|
514
|
+
if (input.versionId !== void 0) pathSegment(input.versionId, "versionId");
|
|
515
|
+
assertOptionalEnum(input.version, ["latest", "draft"], "version");
|
|
516
|
+
assertOptionalEnum(input.mode, ["sync", "async"], "mode");
|
|
517
|
+
assertOptionalBoolean(input.generatePdf, "generatePdf");
|
|
518
|
+
assertOptionalBoolean(input.generateDocx, "generateDocx");
|
|
519
|
+
if (input.data !== void 0) assertPlainObject(input.data, "data");
|
|
520
|
+
if (input.contract !== void 0)
|
|
521
|
+
assertPlainObject(input.contract, "contract");
|
|
522
|
+
if (input.expireAt !== void 0) toEpochMs(input.expireAt);
|
|
523
|
+
if (input.version !== void 0 && input.versionId !== void 0) {
|
|
524
|
+
throw new DokusValidationError(
|
|
525
|
+
"Choose either version or versionId, not both."
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
if (input.planId !== void 0 && input.contract !== void 0) {
|
|
529
|
+
throw new DokusValidationError(
|
|
530
|
+
"Choose either planId or an inline contract, not both."
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
if (input.generatePdf === false && input.generateDocx !== true) {
|
|
534
|
+
throw new DokusValidationError(
|
|
535
|
+
"At least one output format must be enabled."
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
var Documents = class {
|
|
540
|
+
constructor(transport) {
|
|
541
|
+
this.transport = transport;
|
|
542
|
+
}
|
|
543
|
+
async render(input, options) {
|
|
544
|
+
assertRenderInput(input);
|
|
545
|
+
const mode = input.mode ?? "sync";
|
|
546
|
+
return this.transport.request(
|
|
547
|
+
"POST",
|
|
548
|
+
`/api/documents/${pathSegment(input.documentId, "documentId")}/run`,
|
|
549
|
+
{
|
|
550
|
+
...transportWriteOptions(options),
|
|
551
|
+
parseResponse: (value, requestId) => mode === "async" ? parseDocumentRenderStartedResponse(value, requestId) : parseDocumentRenderCompletedResponse(value, requestId),
|
|
552
|
+
body: {
|
|
553
|
+
kind: "json",
|
|
554
|
+
value: {
|
|
555
|
+
data: input.data ?? {},
|
|
556
|
+
generatePdf: input.generatePdf ?? true,
|
|
557
|
+
mode,
|
|
558
|
+
...input.planId !== void 0 ? { planId: input.planId } : {},
|
|
559
|
+
...input.contract !== void 0 ? { contract: input.contract } : {},
|
|
560
|
+
...input.version !== void 0 ? { version: input.version } : {},
|
|
561
|
+
...input.versionId !== void 0 ? { versionId: input.versionId } : {},
|
|
562
|
+
...input.generateDocx !== void 0 ? { generateDocx: input.generateDocx } : {},
|
|
563
|
+
...input.expireAt !== void 0 ? { expireAt: toEpochMs(input.expireAt) } : {}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
function createDocuments(transport) {
|
|
571
|
+
return new Documents(transport);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// src/runs.ts
|
|
575
|
+
var TERMINAL = /* @__PURE__ */ new Set([
|
|
576
|
+
"completed",
|
|
577
|
+
"failed",
|
|
578
|
+
"cancelled"
|
|
579
|
+
]);
|
|
580
|
+
function capturePreviews(run, retained) {
|
|
581
|
+
for (const output of run.outputs) {
|
|
582
|
+
const current = retained.get(output.id) ?? {
|
|
583
|
+
previewUrl: null,
|
|
584
|
+
previewLink: null
|
|
585
|
+
};
|
|
586
|
+
current.previewUrl ??= output.previewUrl;
|
|
587
|
+
current.previewLink ??= output.previewLink;
|
|
588
|
+
retained.set(output.id, current);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function mergePreviews(run, retained) {
|
|
592
|
+
return {
|
|
593
|
+
...run,
|
|
594
|
+
outputs: run.outputs.map((output) => {
|
|
595
|
+
const current = retained.get(output.id);
|
|
596
|
+
return current ? {
|
|
597
|
+
...output,
|
|
598
|
+
previewUrl: current.previewUrl ?? output.previewUrl,
|
|
599
|
+
previewLink: current.previewLink ?? output.previewLink
|
|
600
|
+
} : output;
|
|
601
|
+
})
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
function transportRequestOptions(options = {}) {
|
|
605
|
+
return {
|
|
606
|
+
signal: options.signal,
|
|
607
|
+
timeoutMs: options.timeoutMs,
|
|
608
|
+
requestId: options.requestId
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
function pollSleep(ms, signal) {
|
|
612
|
+
return new Promise((resolve, reject) => {
|
|
613
|
+
if (signal?.aborted) {
|
|
614
|
+
reject(new DokusAbortError());
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
const onAbort = () => {
|
|
618
|
+
clearTimeout(timer);
|
|
619
|
+
reject(new DokusAbortError());
|
|
620
|
+
};
|
|
621
|
+
const timer = setTimeout(() => {
|
|
622
|
+
signal?.removeEventListener("abort", onAbort);
|
|
623
|
+
resolve();
|
|
624
|
+
}, ms);
|
|
625
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
function outputPath(runId, outputId) {
|
|
629
|
+
assertPositiveInteger(outputId, "outputId");
|
|
630
|
+
return `/api/runs/${pathSegment(runId, "runId")}/outputs/${outputId}`;
|
|
631
|
+
}
|
|
632
|
+
function createRuns(transport) {
|
|
633
|
+
const get = async (runId, options = {}) => {
|
|
634
|
+
assertRunGetOptions(options);
|
|
635
|
+
return transport.request(
|
|
636
|
+
"GET",
|
|
637
|
+
`/api/runs/${pathSegment(runId, "runId")}`,
|
|
638
|
+
{
|
|
639
|
+
...transportRequestOptions(options),
|
|
640
|
+
parseResponse: parseRunResultResponse,
|
|
641
|
+
query: { expireAt: expireAtQuery(options.expireAt) }
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
};
|
|
645
|
+
return {
|
|
646
|
+
get,
|
|
647
|
+
outputs: async (runId, options) => {
|
|
648
|
+
assertRequestOptions(options, "runs.outputs options");
|
|
649
|
+
return transport.request(
|
|
650
|
+
"GET",
|
|
651
|
+
`/api/runs/${pathSegment(runId, "runId")}/outputs`,
|
|
652
|
+
{
|
|
653
|
+
...transportRequestOptions(options),
|
|
654
|
+
parseResponse: parseRunOutputsResponse
|
|
655
|
+
}
|
|
656
|
+
);
|
|
657
|
+
},
|
|
658
|
+
outputDownload: async (runId, outputId, options) => {
|
|
659
|
+
assertRequestOptions(options, "runs.outputDownload options");
|
|
660
|
+
return transport.request(
|
|
661
|
+
"GET",
|
|
662
|
+
`${outputPath(runId, outputId)}/download`,
|
|
663
|
+
{
|
|
664
|
+
...transportRequestOptions(options),
|
|
665
|
+
parseResponse: parseOutputDownloadResponse
|
|
666
|
+
}
|
|
667
|
+
);
|
|
668
|
+
},
|
|
669
|
+
rotatePreviewLink: async (runId, outputId, options) => {
|
|
670
|
+
assertRotateOptions(options);
|
|
671
|
+
const value = {
|
|
672
|
+
...options.allowDownload !== void 0 ? { allowDownload: options.allowDownload } : {},
|
|
673
|
+
...options.expiresIn !== void 0 ? { expiresIn: options.expiresIn } : {}
|
|
674
|
+
};
|
|
675
|
+
return transport.request(
|
|
676
|
+
"POST",
|
|
677
|
+
`${outputPath(runId, outputId)}/preview-link/rotate`,
|
|
678
|
+
{
|
|
679
|
+
...transportRequestOptions(options),
|
|
680
|
+
idempotencyKey: options.idempotencyKey,
|
|
681
|
+
parseResponse: parsePreviewLinkRotatedResponse,
|
|
682
|
+
...Object.keys(value).length ? { body: { kind: "json", value } } : {}
|
|
683
|
+
}
|
|
684
|
+
);
|
|
685
|
+
},
|
|
686
|
+
revokePreviewLink: async (runId, outputId, options) => {
|
|
687
|
+
assertWriteOptions(options, "runs.revokePreviewLink options");
|
|
688
|
+
await transport.request(
|
|
689
|
+
"DELETE",
|
|
690
|
+
`${outputPath(runId, outputId)}/preview-link`,
|
|
691
|
+
{
|
|
692
|
+
...transportRequestOptions(options),
|
|
693
|
+
idempotencyKey: options.idempotencyKey,
|
|
694
|
+
responseKind: "void"
|
|
695
|
+
}
|
|
696
|
+
);
|
|
697
|
+
},
|
|
698
|
+
delete: async (runId, options) => {
|
|
699
|
+
assertWriteOptions(options, "runs.delete options");
|
|
700
|
+
await transport.request(
|
|
701
|
+
"DELETE",
|
|
702
|
+
`/api/runs/${pathSegment(runId, "runId")}`,
|
|
703
|
+
{
|
|
704
|
+
...transportRequestOptions(options),
|
|
705
|
+
idempotencyKey: options.idempotencyKey,
|
|
706
|
+
responseKind: "void"
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
},
|
|
710
|
+
wait: async (runId, options = {}) => {
|
|
711
|
+
assertWaitOptions(options);
|
|
712
|
+
pathSegment(runId, "runId");
|
|
713
|
+
const intervalMs = options.intervalMs ?? 2e3;
|
|
714
|
+
const timeoutMs = options.timeoutMs ?? 12e4;
|
|
715
|
+
if (options.signal?.aborted) throw new DokusAbortError(options.requestId);
|
|
716
|
+
const deadline = Date.now() + timeoutMs;
|
|
717
|
+
const retained = /* @__PURE__ */ new Map();
|
|
718
|
+
for (; ; ) {
|
|
719
|
+
const remaining = deadline - Date.now();
|
|
720
|
+
if (remaining <= 0) {
|
|
721
|
+
throw new DokusWaitTimeoutError(timeoutMs, "unknown");
|
|
722
|
+
}
|
|
723
|
+
const run = await get(runId, {
|
|
724
|
+
expireAt: options.expireAt,
|
|
725
|
+
signal: options.signal,
|
|
726
|
+
requestId: options.requestId,
|
|
727
|
+
timeoutMs: Math.min(options.requestTimeoutMs ?? remaining, remaining)
|
|
728
|
+
});
|
|
729
|
+
capturePreviews(run, retained);
|
|
730
|
+
if (TERMINAL.has(run.status)) return mergePreviews(run, retained);
|
|
731
|
+
if (Date.now() + intervalMs > deadline) {
|
|
732
|
+
throw new DokusWaitTimeoutError(timeoutMs, run.status);
|
|
733
|
+
}
|
|
734
|
+
await pollSleep(intervalMs, options.signal);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// src/transport/base-url.ts
|
|
741
|
+
var DOKUS_API_BASE_URL = "https://api.dokus.pro";
|
|
742
|
+
function normalizeBaseUrl(value) {
|
|
743
|
+
let url;
|
|
744
|
+
try {
|
|
745
|
+
url = new URL(value);
|
|
746
|
+
} catch {
|
|
747
|
+
throw new DokusValidationError("baseUrl must be a valid absolute URL.");
|
|
748
|
+
}
|
|
749
|
+
if (url.username || url.password) {
|
|
750
|
+
throw new DokusValidationError("baseUrl must not contain credentials.");
|
|
751
|
+
}
|
|
752
|
+
if (url.search || url.hash) {
|
|
753
|
+
throw new DokusValidationError(
|
|
754
|
+
"baseUrl must not contain a query or fragment."
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
const hostname = url.hostname.toLowerCase();
|
|
758
|
+
const loopback = hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
759
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
|
|
760
|
+
throw new DokusValidationError(
|
|
761
|
+
"baseUrl must use HTTPS; HTTP is allowed only for a loopback host."
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
return url.toString().replace(/\/+$/, "");
|
|
765
|
+
}
|
|
766
|
+
function buildRequestUrl(baseUrl, path, query = {}) {
|
|
767
|
+
if (!path.startsWith("/") || path.includes("?") || path.includes("#")) {
|
|
768
|
+
throw new DokusValidationError("The request path is invalid.");
|
|
769
|
+
}
|
|
770
|
+
const search = new URLSearchParams();
|
|
771
|
+
for (const [key, value] of Object.entries(query)) {
|
|
772
|
+
if (value !== void 0) search.set(key, String(value));
|
|
773
|
+
}
|
|
774
|
+
const serialized = search.toString();
|
|
775
|
+
return `${baseUrl}${path}${serialized ? `?${serialized}` : ""}`;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// src/transport/json-body.ts
|
|
779
|
+
var MAX_DEPTH = 32;
|
|
780
|
+
var MAX_NODES = 1e5;
|
|
781
|
+
var MAX_UTF8_BYTES = 1024 * 1024;
|
|
782
|
+
function invalid2(reason) {
|
|
783
|
+
throw new DokusValidationError(`The request body ${reason}.`);
|
|
784
|
+
}
|
|
785
|
+
function descriptors(value) {
|
|
786
|
+
try {
|
|
787
|
+
return Object.getOwnPropertyDescriptors(value);
|
|
788
|
+
} catch {
|
|
789
|
+
return invalid2("must contain only inspectable data properties");
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
function prototypeOf(value) {
|
|
793
|
+
try {
|
|
794
|
+
return Object.getPrototypeOf(value);
|
|
795
|
+
} catch {
|
|
796
|
+
return invalid2("must contain only inspectable data values");
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
function descriptorAt(source, key) {
|
|
800
|
+
return Object.getOwnPropertyDescriptor(source, key)?.value;
|
|
801
|
+
}
|
|
802
|
+
function enter(value, state, depth) {
|
|
803
|
+
if (depth > MAX_DEPTH) invalid2("exceeds the maximum nesting depth");
|
|
804
|
+
if (state.active.has(value)) invalid2("must not contain cycles");
|
|
805
|
+
state.active.add(value);
|
|
806
|
+
}
|
|
807
|
+
function count(state) {
|
|
808
|
+
state.nodes += 1;
|
|
809
|
+
if (state.nodes > MAX_NODES) invalid2("exceeds the maximum node count");
|
|
810
|
+
}
|
|
811
|
+
function cloneArray(value, state, depth) {
|
|
812
|
+
if (prototypeOf(value) !== Array.prototype) {
|
|
813
|
+
return invalid2("must not contain array subclasses");
|
|
814
|
+
}
|
|
815
|
+
if (value.length > MAX_NODES) invalid2("exceeds the maximum node count");
|
|
816
|
+
enter(value, state, depth);
|
|
817
|
+
try {
|
|
818
|
+
const source = descriptors(value);
|
|
819
|
+
const keys = Reflect.ownKeys(source);
|
|
820
|
+
if (keys.length !== value.length + 1 || !keys.includes("length")) {
|
|
821
|
+
return invalid2("must not contain sparse or decorated arrays");
|
|
822
|
+
}
|
|
823
|
+
const result = new Array(value.length);
|
|
824
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
825
|
+
const descriptor = descriptorAt(source, String(index));
|
|
826
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) {
|
|
827
|
+
return invalid2("must not contain sparse or accessor-bearing arrays");
|
|
828
|
+
}
|
|
829
|
+
result[index] = cloneJson(descriptor.value, state, depth + 1);
|
|
830
|
+
}
|
|
831
|
+
return result;
|
|
832
|
+
} finally {
|
|
833
|
+
state.active.delete(value);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function cloneObject(value, state, depth) {
|
|
837
|
+
const prototype = prototypeOf(value);
|
|
838
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
839
|
+
return invalid2("must contain only plain or null-prototype objects");
|
|
840
|
+
}
|
|
841
|
+
enter(value, state, depth);
|
|
842
|
+
try {
|
|
843
|
+
const source = descriptors(value);
|
|
844
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
845
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
846
|
+
if (typeof key !== "string") {
|
|
847
|
+
return invalid2("must not contain symbol-keyed properties");
|
|
848
|
+
}
|
|
849
|
+
const descriptor = descriptorAt(source, key);
|
|
850
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) {
|
|
851
|
+
return invalid2("must contain only enumerable data properties");
|
|
852
|
+
}
|
|
853
|
+
Object.defineProperty(result, key, {
|
|
854
|
+
enumerable: true,
|
|
855
|
+
value: cloneJson(descriptor.value, state, depth + 1)
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
return result;
|
|
859
|
+
} finally {
|
|
860
|
+
state.active.delete(value);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
function cloneJson(value, state, depth) {
|
|
864
|
+
if (depth > MAX_DEPTH) invalid2("exceeds the maximum nesting depth");
|
|
865
|
+
count(state);
|
|
866
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
867
|
+
return value;
|
|
868
|
+
}
|
|
869
|
+
if (typeof value === "number") {
|
|
870
|
+
return Number.isFinite(value) ? value : invalid2("must contain only finite numbers");
|
|
871
|
+
}
|
|
872
|
+
if (Array.isArray(value)) return cloneArray(value, state, depth);
|
|
873
|
+
if (typeof value === "object") return cloneObject(value, state, depth);
|
|
874
|
+
return invalid2("must contain only JSON values");
|
|
875
|
+
}
|
|
876
|
+
function encodeJsonRequestBody(value) {
|
|
877
|
+
const clone = cloneJson(value, { nodes: 0, active: /* @__PURE__ */ new WeakSet() }, 0);
|
|
878
|
+
const encoded = JSON.stringify(clone);
|
|
879
|
+
if (new TextEncoder().encode(encoded).byteLength > MAX_UTF8_BYTES) {
|
|
880
|
+
invalid2("exceeds the maximum UTF-8 byte size");
|
|
881
|
+
}
|
|
882
|
+
return encoded;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// src/transport/retry.ts
|
|
886
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([
|
|
887
|
+
408,
|
|
888
|
+
429,
|
|
889
|
+
502,
|
|
890
|
+
503,
|
|
891
|
+
504
|
|
892
|
+
]);
|
|
893
|
+
function parseRetryAfter(value, now = Date.now()) {
|
|
894
|
+
if (value === null) return void 0;
|
|
895
|
+
const seconds = Number(value);
|
|
896
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
897
|
+
const date = Date.parse(value);
|
|
898
|
+
return Number.isFinite(date) ? Math.max(0, date - now) : void 0;
|
|
899
|
+
}
|
|
900
|
+
function retryDelayMs(attempt, retryAfterMs, maxDelayMs) {
|
|
901
|
+
if (retryAfterMs !== void 0) return Math.min(retryAfterMs, maxDelayMs);
|
|
902
|
+
const ceiling = Math.min(250 * 2 ** (attempt - 1), maxDelayMs);
|
|
903
|
+
return Math.round(ceiling * (0.5 + Math.random() * 0.5));
|
|
904
|
+
}
|
|
905
|
+
function sleep(ms, signal) {
|
|
906
|
+
return new Promise((resolve, reject) => {
|
|
907
|
+
if (signal.aborted) {
|
|
908
|
+
reject(signal.reason);
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
const onAbort = () => {
|
|
912
|
+
clearTimeout(timer);
|
|
913
|
+
reject(signal.reason);
|
|
914
|
+
};
|
|
915
|
+
const timer = setTimeout(() => {
|
|
916
|
+
signal.removeEventListener("abort", onAbort);
|
|
917
|
+
resolve();
|
|
918
|
+
}, ms);
|
|
919
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// src/transport/response.ts
|
|
924
|
+
var JSON_LIMIT_BYTES = 1024 * 1024;
|
|
925
|
+
var BINARY_LIMIT_BYTES = 64 * 1024 * 1024;
|
|
926
|
+
var SENSITIVE_KEYS = /(?:api[-_]?key|authorization|cookie|password|secret|token|headers?|body)/i;
|
|
927
|
+
function ownDataRecord(value) {
|
|
928
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
929
|
+
return null;
|
|
930
|
+
}
|
|
931
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
932
|
+
let keys;
|
|
933
|
+
try {
|
|
934
|
+
keys = Object.keys(value);
|
|
935
|
+
} catch {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
for (const key of keys) {
|
|
939
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
940
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) continue;
|
|
941
|
+
Object.defineProperty(result, key, {
|
|
942
|
+
enumerable: true,
|
|
943
|
+
value: descriptor.value
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
return result;
|
|
947
|
+
}
|
|
948
|
+
function header(response, name) {
|
|
949
|
+
return typeof response.headers?.get === "function" ? response.headers.get(name) : null;
|
|
950
|
+
}
|
|
951
|
+
function responseRequestId(response, fallback, apiKey) {
|
|
952
|
+
const value = header(response, "x-request-id");
|
|
953
|
+
return value && /^[A-Za-z0-9._:-]{8,128}$/.test(value) && value !== apiKey ? value : fallback;
|
|
954
|
+
}
|
|
955
|
+
async function readBounded(response, limitBytes, requestId) {
|
|
956
|
+
const declared = Number(header(response, "content-length"));
|
|
957
|
+
if (Number.isFinite(declared) && declared > limitBytes) {
|
|
958
|
+
throw new DokusResponseTooLargeError(limitBytes, requestId);
|
|
959
|
+
}
|
|
960
|
+
const reader = response.body?.getReader();
|
|
961
|
+
if (!reader) {
|
|
962
|
+
const bytes2 = new Uint8Array(await response.arrayBuffer());
|
|
963
|
+
if (bytes2.byteLength > limitBytes) {
|
|
964
|
+
throw new DokusResponseTooLargeError(limitBytes, requestId);
|
|
965
|
+
}
|
|
966
|
+
return bytes2;
|
|
967
|
+
}
|
|
968
|
+
const chunks = [];
|
|
969
|
+
let size = 0;
|
|
970
|
+
for (; ; ) {
|
|
971
|
+
const { done, value } = await reader.read();
|
|
972
|
+
if (done) break;
|
|
973
|
+
size += value.byteLength;
|
|
974
|
+
if (size > limitBytes) {
|
|
975
|
+
await reader.cancel().catch(() => void 0);
|
|
976
|
+
throw new DokusResponseTooLargeError(limitBytes, requestId);
|
|
977
|
+
}
|
|
978
|
+
chunks.push(value);
|
|
979
|
+
}
|
|
980
|
+
const bytes = new Uint8Array(size);
|
|
981
|
+
let offset = 0;
|
|
982
|
+
for (const chunk of chunks) {
|
|
983
|
+
bytes.set(chunk, offset);
|
|
984
|
+
offset += chunk.byteLength;
|
|
985
|
+
}
|
|
986
|
+
return bytes;
|
|
987
|
+
}
|
|
988
|
+
function parseJson(bytes) {
|
|
989
|
+
if (bytes.byteLength === 0) return null;
|
|
990
|
+
try {
|
|
991
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
992
|
+
} catch {
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
function redactText(value, apiKey) {
|
|
997
|
+
return value.includes(apiKey) ? value.split(apiKey).join("[REDACTED]") : value;
|
|
998
|
+
}
|
|
999
|
+
function ownEnumerableDataEntries(value) {
|
|
1000
|
+
let keys;
|
|
1001
|
+
try {
|
|
1002
|
+
keys = Object.keys(value);
|
|
1003
|
+
} catch {
|
|
1004
|
+
return [];
|
|
1005
|
+
}
|
|
1006
|
+
const entries = [];
|
|
1007
|
+
for (const key of keys.slice(0, 30)) {
|
|
1008
|
+
let descriptor;
|
|
1009
|
+
try {
|
|
1010
|
+
descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1011
|
+
} catch {
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) continue;
|
|
1015
|
+
entries.push([key, descriptor.value]);
|
|
1016
|
+
}
|
|
1017
|
+
return entries;
|
|
1018
|
+
}
|
|
1019
|
+
function safePropertyName(key, apiKey) {
|
|
1020
|
+
return SENSITIVE_KEYS.test(key) || key.includes(apiKey) ? "[REDACTED]" : redactText(key.slice(0, 256), apiKey);
|
|
1021
|
+
}
|
|
1022
|
+
function safeDetails(value, apiKey, depth = 0) {
|
|
1023
|
+
if (depth > 4) return "[TRUNCATED]";
|
|
1024
|
+
if (typeof value === "string") {
|
|
1025
|
+
return redactText(value.slice(0, 2048), apiKey);
|
|
1026
|
+
}
|
|
1027
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
1028
|
+
return value;
|
|
1029
|
+
}
|
|
1030
|
+
if (Array.isArray(value)) {
|
|
1031
|
+
const result = [];
|
|
1032
|
+
for (let index = 0; index < Math.min(value.length, 20); index += 1) {
|
|
1033
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
1034
|
+
if (descriptor?.enumerable && "value" in descriptor) {
|
|
1035
|
+
result.push(safeDetails(descriptor.value, apiKey, depth + 1));
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return result;
|
|
1039
|
+
}
|
|
1040
|
+
if (typeof value === "object") {
|
|
1041
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
1042
|
+
for (const [key, item] of ownEnumerableDataEntries(value)) {
|
|
1043
|
+
const outputKey = safePropertyName(key, apiKey);
|
|
1044
|
+
Object.defineProperty(result, outputKey, {
|
|
1045
|
+
configurable: true,
|
|
1046
|
+
enumerable: true,
|
|
1047
|
+
writable: true,
|
|
1048
|
+
value: outputKey === "[REDACTED]" ? "[REDACTED]" : safeDetails(item, apiKey, depth + 1)
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
return result;
|
|
1052
|
+
}
|
|
1053
|
+
return void 0;
|
|
1054
|
+
}
|
|
1055
|
+
function errorFromEnvelope(response, envelope, requestId, apiKey) {
|
|
1056
|
+
const error = ownDataRecord(envelope?.error);
|
|
1057
|
+
const code = typeof error?.code === "string" ? redactText(error.code.slice(0, 256), apiKey) : void 0;
|
|
1058
|
+
const retryAfterMs = parseRetryAfter(header(response, "retry-after"));
|
|
1059
|
+
if (typeof error?.message === "string" && error.message.length > 0) {
|
|
1060
|
+
return new DokusApiError(
|
|
1061
|
+
redactText(error.message.slice(0, 4096), apiKey),
|
|
1062
|
+
response.status,
|
|
1063
|
+
requestId,
|
|
1064
|
+
code,
|
|
1065
|
+
safeDetails(error.details, apiKey),
|
|
1066
|
+
retryAfterMs
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
const issues = Array.isArray(error?.issues) ? error.issues : [];
|
|
1070
|
+
const messages = issues.slice(0, 3).map((issue) => ownDataRecord(issue)?.message).filter((message2) => typeof message2 === "string").map((message2) => redactText(message2.slice(0, 1024), apiKey));
|
|
1071
|
+
const message = messages.length ? `Dokus API request rejected (${response.status}): ${messages.join("; ")}` : `Dokus API request failed (${response.status})`;
|
|
1072
|
+
return new DokusApiError(
|
|
1073
|
+
message,
|
|
1074
|
+
response.status,
|
|
1075
|
+
requestId,
|
|
1076
|
+
code,
|
|
1077
|
+
issues.length ? safeDetails({ issues }, apiKey) : void 0,
|
|
1078
|
+
retryAfterMs
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
async function decodeResponse(response, kind, fallbackRequestId, apiKey, parseResponse) {
|
|
1082
|
+
const requestId = responseRequestId(response, fallbackRequestId, apiKey);
|
|
1083
|
+
if (response.status === 204) {
|
|
1084
|
+
if (kind !== "void") throw new DokusProtocolError(requestId);
|
|
1085
|
+
return void 0;
|
|
1086
|
+
}
|
|
1087
|
+
if (kind === "binary" && response.ok) {
|
|
1088
|
+
return await readBounded(response, BINARY_LIMIT_BYTES, requestId);
|
|
1089
|
+
}
|
|
1090
|
+
const bytes = await readBounded(response, JSON_LIMIT_BYTES, requestId);
|
|
1091
|
+
const parsed = parseJson(bytes);
|
|
1092
|
+
const envelope = ownDataRecord(parsed);
|
|
1093
|
+
if (!response.ok) {
|
|
1094
|
+
throw errorFromEnvelope(response, envelope, requestId, apiKey);
|
|
1095
|
+
}
|
|
1096
|
+
if (kind === "void") return void 0;
|
|
1097
|
+
if (envelope?.success !== true || !Object.hasOwn(envelope, "data")) {
|
|
1098
|
+
throw new DokusProtocolError(requestId);
|
|
1099
|
+
}
|
|
1100
|
+
return parseResponse ? parseResponse(envelope.data, requestId) : envelope.data;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// src/transport/transport.ts
|
|
1104
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
1105
|
+
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
1106
|
+
var DEFAULT_MAX_RETRY_DELAY_MS = 3e4;
|
|
1107
|
+
var CLIENT_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
1108
|
+
"apiKey",
|
|
1109
|
+
"baseUrl",
|
|
1110
|
+
"fetch",
|
|
1111
|
+
"timeoutMs",
|
|
1112
|
+
"retry"
|
|
1113
|
+
]);
|
|
1114
|
+
var RETRY_OPTION_KEYS = /* @__PURE__ */ new Set(["maxAttempts", "maxDelayMs"]);
|
|
1115
|
+
function isDeniedRuntime() {
|
|
1116
|
+
const scope = globalThis;
|
|
1117
|
+
return typeof scope.window !== "undefined" || typeof scope.document !== "undefined" || typeof scope.importScripts === "function" || /WorkerGlobalScope$/.test(scope.constructor?.name ?? "");
|
|
1118
|
+
}
|
|
1119
|
+
function deadlineSignal(caller, timeoutMs) {
|
|
1120
|
+
const controller = new AbortController();
|
|
1121
|
+
let timedOut = false;
|
|
1122
|
+
const onAbort = () => controller.abort();
|
|
1123
|
+
if (caller?.aborted) controller.abort();
|
|
1124
|
+
else caller?.addEventListener("abort", onAbort, { once: true });
|
|
1125
|
+
const timer = setTimeout(() => {
|
|
1126
|
+
timedOut = true;
|
|
1127
|
+
controller.abort();
|
|
1128
|
+
}, timeoutMs);
|
|
1129
|
+
return {
|
|
1130
|
+
signal: controller.signal,
|
|
1131
|
+
didTimeout: () => timedOut,
|
|
1132
|
+
dispose: () => {
|
|
1133
|
+
clearTimeout(timer);
|
|
1134
|
+
caller?.removeEventListener("abort", onAbort);
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
function encodeBody(body) {
|
|
1139
|
+
if (!body) return {};
|
|
1140
|
+
if (body.kind === "multipart") return { body: body.value };
|
|
1141
|
+
if (body.kind === "binary") {
|
|
1142
|
+
return { body: body.value, contentType: body.contentType };
|
|
1143
|
+
}
|
|
1144
|
+
return {
|
|
1145
|
+
body: encodeJsonRequestBody(body.value),
|
|
1146
|
+
contentType: "application/json"
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
function validateConfig(options) {
|
|
1150
|
+
assertExactDataObject(
|
|
1151
|
+
options,
|
|
1152
|
+
CLIENT_OPTION_KEYS,
|
|
1153
|
+
"createDokusClient options"
|
|
1154
|
+
);
|
|
1155
|
+
if (options.baseUrl !== void 0 && typeof options.baseUrl !== "string") {
|
|
1156
|
+
throw new DokusValidationError("baseUrl must be a string.");
|
|
1157
|
+
}
|
|
1158
|
+
if (options.fetch !== void 0 && typeof options.fetch !== "function") {
|
|
1159
|
+
throw new DokusValidationError("fetch must be a function.");
|
|
1160
|
+
}
|
|
1161
|
+
if (options.retry !== void 0 && options.retry !== false) {
|
|
1162
|
+
assertExactDataObject(options.retry, RETRY_OPTION_KEYS, "retry options");
|
|
1163
|
+
}
|
|
1164
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1165
|
+
assertTimerMs(timeoutMs, "timeoutMs");
|
|
1166
|
+
const maxAttempts = options.retry === false ? 1 : options.retry?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
1167
|
+
const maxDelayMs = options.retry === false ? 0 : options.retry?.maxDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;
|
|
1168
|
+
assertPositiveInteger(maxAttempts, "retry.maxAttempts");
|
|
1169
|
+
if (maxAttempts > 10) {
|
|
1170
|
+
throw new DokusValidationError("retry.maxAttempts must not exceed 10.");
|
|
1171
|
+
}
|
|
1172
|
+
if (options.retry !== false) assertTimerMs(maxDelayMs, "retry.maxDelayMs");
|
|
1173
|
+
return { timeoutMs, maxAttempts, maxDelayMs };
|
|
1174
|
+
}
|
|
1175
|
+
function createTransport(options) {
|
|
1176
|
+
const config = validateConfig(options);
|
|
1177
|
+
if (typeof options.apiKey !== "string" || options.apiKey.trim().length === 0) {
|
|
1178
|
+
throw new DokusValidationError("createDokusClient requires an apiKey.");
|
|
1179
|
+
}
|
|
1180
|
+
if (isDeniedRuntime()) {
|
|
1181
|
+
throw new DokusValidationError(
|
|
1182
|
+
"createDokusClient is server-only; keep Dokus API keys out of browsers and web workers."
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
const apiKey = options.apiKey;
|
|
1186
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1187
|
+
if (typeof fetchImpl !== "function") {
|
|
1188
|
+
throw new DokusValidationError("No fetch implementation is available.");
|
|
1189
|
+
}
|
|
1190
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl ?? DOKUS_API_BASE_URL);
|
|
1191
|
+
return {
|
|
1192
|
+
request: async (method, path, init = {}) => {
|
|
1193
|
+
const requestId = init.requestId ?? randomUUID();
|
|
1194
|
+
assertOpaqueId(requestId, "requestId");
|
|
1195
|
+
if (requestId === apiKey) {
|
|
1196
|
+
throw new DokusValidationError(
|
|
1197
|
+
"requestId must be independent from the apiKey."
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
if (init.idempotencyKey !== void 0) {
|
|
1201
|
+
assertOpaqueId(init.idempotencyKey, "idempotencyKey");
|
|
1202
|
+
}
|
|
1203
|
+
const timeoutMs = init.timeoutMs ?? config.timeoutMs;
|
|
1204
|
+
assertTimerMs(timeoutMs, "timeoutMs");
|
|
1205
|
+
const url = buildRequestUrl(baseUrl, path, init.query);
|
|
1206
|
+
const encoded = encodeBody(init.body);
|
|
1207
|
+
const headers = {
|
|
1208
|
+
accept: init.responseKind === "binary" ? "application/octet-stream" : "application/json",
|
|
1209
|
+
"x-api-key": apiKey,
|
|
1210
|
+
"x-request-id": requestId,
|
|
1211
|
+
...encoded.contentType ? { "content-type": encoded.contentType } : {},
|
|
1212
|
+
...init.idempotencyKey ? { "idempotency-key": init.idempotencyKey } : {}
|
|
1213
|
+
};
|
|
1214
|
+
const attempts = method === "GET" ? config.maxAttempts : 1;
|
|
1215
|
+
const deadline = deadlineSignal(init.signal, timeoutMs);
|
|
1216
|
+
try {
|
|
1217
|
+
if (deadline.signal.aborted) throw new DokusAbortError(requestId);
|
|
1218
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
1219
|
+
let response;
|
|
1220
|
+
try {
|
|
1221
|
+
response = await fetchImpl(url, {
|
|
1222
|
+
method,
|
|
1223
|
+
headers,
|
|
1224
|
+
...encoded.body !== void 0 ? { body: encoded.body } : {},
|
|
1225
|
+
signal: deadline.signal,
|
|
1226
|
+
redirect: "error"
|
|
1227
|
+
});
|
|
1228
|
+
} catch {
|
|
1229
|
+
if (deadline.signal.aborted) {
|
|
1230
|
+
throw deadline.didTimeout() ? new DokusTimeoutError(timeoutMs, requestId) : new DokusAbortError(requestId);
|
|
1231
|
+
}
|
|
1232
|
+
if (attempt === attempts) throw new DokusConnectionError(requestId);
|
|
1233
|
+
await sleep(
|
|
1234
|
+
retryDelayMs(attempt, void 0, config.maxDelayMs),
|
|
1235
|
+
deadline.signal
|
|
1236
|
+
);
|
|
1237
|
+
continue;
|
|
1238
|
+
}
|
|
1239
|
+
if (RETRYABLE_STATUSES.has(response.status) && attempt < attempts) {
|
|
1240
|
+
const retryAfter = parseRetryAfter(
|
|
1241
|
+
response.headers.get("retry-after")
|
|
1242
|
+
);
|
|
1243
|
+
await response.body?.cancel().catch(() => void 0);
|
|
1244
|
+
await sleep(
|
|
1245
|
+
retryDelayMs(attempt, retryAfter, config.maxDelayMs),
|
|
1246
|
+
deadline.signal
|
|
1247
|
+
);
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
return await decodeResponse(
|
|
1251
|
+
response,
|
|
1252
|
+
init.responseKind ?? "json",
|
|
1253
|
+
requestId,
|
|
1254
|
+
apiKey,
|
|
1255
|
+
init.parseResponse
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
throw new DokusConnectionError(requestId);
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
if (error instanceof DokusTimeoutError || error instanceof DokusAbortError)
|
|
1261
|
+
throw error;
|
|
1262
|
+
if (deadline.signal.aborted) {
|
|
1263
|
+
throw deadline.didTimeout() ? new DokusTimeoutError(timeoutMs, requestId) : new DokusAbortError(requestId);
|
|
1264
|
+
}
|
|
1265
|
+
throw error;
|
|
1266
|
+
} finally {
|
|
1267
|
+
deadline.dispose();
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// src/workflows.ts
|
|
1274
|
+
var GENERATE_INPUT_KEYS = /* @__PURE__ */ new Set([
|
|
1275
|
+
"documentId",
|
|
1276
|
+
"data",
|
|
1277
|
+
"versionId",
|
|
1278
|
+
"versionSpec",
|
|
1279
|
+
"outputFileNameOverride",
|
|
1280
|
+
"generatePdf",
|
|
1281
|
+
"generateDocx"
|
|
1282
|
+
]);
|
|
1283
|
+
var GENERATE_ALL_INPUT_KEYS = /* @__PURE__ */ new Set([
|
|
1284
|
+
"data",
|
|
1285
|
+
"versionSpec",
|
|
1286
|
+
"generatePdf",
|
|
1287
|
+
"generateDocx",
|
|
1288
|
+
"documentIds"
|
|
1289
|
+
]);
|
|
1290
|
+
function requestOptions(options = {}) {
|
|
1291
|
+
return {
|
|
1292
|
+
signal: options.signal,
|
|
1293
|
+
timeoutMs: options.timeoutMs,
|
|
1294
|
+
requestId: options.requestId
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
function writeOptions(options, label) {
|
|
1298
|
+
assertWriteOptions(options, label);
|
|
1299
|
+
return {
|
|
1300
|
+
...requestOptions(options),
|
|
1301
|
+
idempotencyKey: options.idempotencyKey
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
function assertGenerateInput(input) {
|
|
1305
|
+
assertExactDataObject(input, GENERATE_INPUT_KEYS, "workflows.generate input");
|
|
1306
|
+
pathSegment(input.documentId, "documentId");
|
|
1307
|
+
if (input.versionId !== void 0) pathSegment(input.versionId, "versionId");
|
|
1308
|
+
assertOptionalEnum(input.versionSpec, ["latest", "draft"], "versionSpec");
|
|
1309
|
+
assertOptionalString(input.outputFileNameOverride, "outputFileNameOverride");
|
|
1310
|
+
assertOptionalBoolean(input.generatePdf, "generatePdf");
|
|
1311
|
+
assertOptionalBoolean(input.generateDocx, "generateDocx");
|
|
1312
|
+
if (input.data !== void 0) assertPlainObject(input.data, "data");
|
|
1313
|
+
if (input.versionSpec !== void 0 && input.versionId !== void 0) {
|
|
1314
|
+
throw new DokusValidationError(
|
|
1315
|
+
"Choose either versionSpec or versionId, not both."
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
if (input.generatePdf === false && input.generateDocx !== true) {
|
|
1319
|
+
throw new DokusValidationError(
|
|
1320
|
+
"At least one output format must be enabled."
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
function assertGenerateAllInput(input) {
|
|
1325
|
+
if (input === void 0) return;
|
|
1326
|
+
assertExactDataObject(
|
|
1327
|
+
input,
|
|
1328
|
+
GENERATE_ALL_INPUT_KEYS,
|
|
1329
|
+
"workflows.generateAll input"
|
|
1330
|
+
);
|
|
1331
|
+
assertOptionalEnum(input.versionSpec, ["latest", "draft"], "versionSpec");
|
|
1332
|
+
assertOptionalBoolean(input.generatePdf, "generatePdf");
|
|
1333
|
+
assertOptionalBoolean(input.generateDocx, "generateDocx");
|
|
1334
|
+
if (input.data !== void 0) assertPlainObject(input.data, "data");
|
|
1335
|
+
if (input.documentIds !== void 0) {
|
|
1336
|
+
if (!Array.isArray(input.documentIds)) {
|
|
1337
|
+
throw new DokusValidationError("documentIds must be an array.");
|
|
1338
|
+
}
|
|
1339
|
+
encodeJsonRequestBody(input.documentIds);
|
|
1340
|
+
if (input.documentIds.length === 0) {
|
|
1341
|
+
throw new DokusValidationError("documentIds must not be empty.");
|
|
1342
|
+
}
|
|
1343
|
+
for (const [index, documentId] of input.documentIds.entries()) {
|
|
1344
|
+
pathSegment(documentId, `documentIds[${index}]`);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
function generateBody(input, mode) {
|
|
1349
|
+
return {
|
|
1350
|
+
documentId: input.documentId,
|
|
1351
|
+
data: input.data ?? {},
|
|
1352
|
+
generatePdf: input.generatePdf ?? true,
|
|
1353
|
+
mode,
|
|
1354
|
+
...input.versionId !== void 0 ? { versionId: input.versionId } : {},
|
|
1355
|
+
...input.versionSpec !== void 0 ? { versionSpec: input.versionSpec } : {},
|
|
1356
|
+
...input.outputFileNameOverride !== void 0 ? { outputFileNameOverride: input.outputFileNameOverride } : {},
|
|
1357
|
+
...input.generateDocx !== void 0 ? { generateDocx: input.generateDocx } : {}
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
function createWorkflows(transport) {
|
|
1361
|
+
const generatePath = (workflowId) => `/api/workflows/${pathSegment(workflowId, "workflowId")}/generate`;
|
|
1362
|
+
const generationRequest = (workflowId, input, options, mode) => {
|
|
1363
|
+
assertGenerateInput(input);
|
|
1364
|
+
return {
|
|
1365
|
+
path: generatePath(workflowId),
|
|
1366
|
+
init: {
|
|
1367
|
+
...writeOptions(options, "workflows.generate options"),
|
|
1368
|
+
body: { kind: "json", value: generateBody(input, mode) }
|
|
1369
|
+
}
|
|
1370
|
+
};
|
|
1371
|
+
};
|
|
1372
|
+
return {
|
|
1373
|
+
generate: async (workflowId, input, options) => {
|
|
1374
|
+
const request = generationRequest(workflowId, input, options, "async");
|
|
1375
|
+
return transport.request("POST", request.path, {
|
|
1376
|
+
...request.init,
|
|
1377
|
+
parseResponse: parseGenerateStartedResponse
|
|
1378
|
+
});
|
|
1379
|
+
},
|
|
1380
|
+
generateSync: async (workflowId, input, options) => {
|
|
1381
|
+
const request = generationRequest(workflowId, input, options, "sync");
|
|
1382
|
+
return transport.request("POST", request.path, {
|
|
1383
|
+
...request.init,
|
|
1384
|
+
parseResponse: parseRunResultResponse
|
|
1385
|
+
});
|
|
1386
|
+
},
|
|
1387
|
+
generateAll: async (workflowId, input, options) => {
|
|
1388
|
+
assertGenerateAllInput(input);
|
|
1389
|
+
return transport.request(
|
|
1390
|
+
"POST",
|
|
1391
|
+
`/api/workflows/${pathSegment(workflowId, "workflowId")}/generate-all`,
|
|
1392
|
+
{
|
|
1393
|
+
...writeOptions(options, "workflows.generateAll options"),
|
|
1394
|
+
parseResponse: parseGenerateAllResponse,
|
|
1395
|
+
body: { kind: "json", value: input ?? {} }
|
|
1396
|
+
}
|
|
1397
|
+
);
|
|
1398
|
+
},
|
|
1399
|
+
documentRuns: async (workflowId, documentId, options) => {
|
|
1400
|
+
assertDocumentRunsOptions(options);
|
|
1401
|
+
return transport.request(
|
|
1402
|
+
"GET",
|
|
1403
|
+
`/api/workflows/${pathSegment(workflowId, "workflowId")}/documents/${pathSegment(documentId, "documentId")}/runs`,
|
|
1404
|
+
{
|
|
1405
|
+
...requestOptions(options),
|
|
1406
|
+
parseResponse: parseDocumentRunsResponse,
|
|
1407
|
+
query: { limit: options?.limit }
|
|
1408
|
+
}
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// src/index.ts
|
|
1415
|
+
function createDokusClient(options) {
|
|
1416
|
+
const transport = createTransport(options);
|
|
1417
|
+
return {
|
|
1418
|
+
documents: createDocuments(transport),
|
|
1419
|
+
runs: createRuns(transport),
|
|
1420
|
+
workflows: createWorkflows(transport)
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
export { DOKUS_API_BASE_URL, createDokusClient };
|