bannerify-js 0.0.28 → 0.1.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/dist/index.cjs +199 -162
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +714 -440
- package/dist/index.d.ts +714 -440
- package/dist/index.js +196 -159
- package/dist/index.js.map +1 -1
- package/package.json +17 -18
package/dist/index.js
CHANGED
|
@@ -1,29 +1,14 @@
|
|
|
1
|
-
// node_modules
|
|
1
|
+
// ../../../node_modules/ky/distribution/errors/HTTPError.js
|
|
2
2
|
var HTTPError = class extends Error {
|
|
3
|
+
response;
|
|
4
|
+
request;
|
|
5
|
+
options;
|
|
3
6
|
constructor(response, request, options) {
|
|
4
7
|
const code = response.status || response.status === 0 ? response.status : "";
|
|
5
8
|
const title = response.statusText || "";
|
|
6
9
|
const status = `${code} ${title}`.trim();
|
|
7
10
|
const reason = status ? `status code ${status}` : "an unknown error";
|
|
8
|
-
super(`Request failed with ${reason}`);
|
|
9
|
-
Object.defineProperty(this, "response", {
|
|
10
|
-
enumerable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
writable: true,
|
|
13
|
-
value: void 0
|
|
14
|
-
});
|
|
15
|
-
Object.defineProperty(this, "request", {
|
|
16
|
-
enumerable: true,
|
|
17
|
-
configurable: true,
|
|
18
|
-
writable: true,
|
|
19
|
-
value: void 0
|
|
20
|
-
});
|
|
21
|
-
Object.defineProperty(this, "options", {
|
|
22
|
-
enumerable: true,
|
|
23
|
-
configurable: true,
|
|
24
|
-
writable: true,
|
|
25
|
-
value: void 0
|
|
26
|
-
});
|
|
11
|
+
super(`Request failed with ${reason}: ${request.method} ${request.url}`);
|
|
27
12
|
this.name = "HTTPError";
|
|
28
13
|
this.response = response;
|
|
29
14
|
this.request = request;
|
|
@@ -31,25 +16,20 @@ var HTTPError = class extends Error {
|
|
|
31
16
|
}
|
|
32
17
|
};
|
|
33
18
|
|
|
34
|
-
// node_modules
|
|
19
|
+
// ../../../node_modules/ky/distribution/errors/TimeoutError.js
|
|
35
20
|
var TimeoutError = class extends Error {
|
|
21
|
+
request;
|
|
36
22
|
constructor(request) {
|
|
37
|
-
super(
|
|
38
|
-
Object.defineProperty(this, "request", {
|
|
39
|
-
enumerable: true,
|
|
40
|
-
configurable: true,
|
|
41
|
-
writable: true,
|
|
42
|
-
value: void 0
|
|
43
|
-
});
|
|
23
|
+
super(`Request timed out: ${request.method} ${request.url}`);
|
|
44
24
|
this.name = "TimeoutError";
|
|
45
25
|
this.request = request;
|
|
46
26
|
}
|
|
47
27
|
};
|
|
48
28
|
|
|
49
|
-
// node_modules
|
|
29
|
+
// ../../../node_modules/ky/distribution/utils/is.js
|
|
50
30
|
var isObject = (value) => value !== null && typeof value === "object";
|
|
51
31
|
|
|
52
|
-
// node_modules
|
|
32
|
+
// ../../../node_modules/ky/distribution/utils/merge.js
|
|
53
33
|
var validateAndMerge = (...sources) => {
|
|
54
34
|
for (const source of sources) {
|
|
55
35
|
if ((!isObject(source) || Array.isArray(source)) && source !== void 0) {
|
|
@@ -71,9 +51,19 @@ var mergeHeaders = (source1 = {}, source2 = {}) => {
|
|
|
71
51
|
}
|
|
72
52
|
return result;
|
|
73
53
|
};
|
|
54
|
+
function newHookValue(original, incoming, property) {
|
|
55
|
+
return Object.hasOwn(incoming, property) && incoming[property] === void 0 ? [] : deepMerge(original[property] ?? [], incoming[property] ?? []);
|
|
56
|
+
}
|
|
57
|
+
var mergeHooks = (original = {}, incoming = {}) => ({
|
|
58
|
+
beforeRequest: newHookValue(original, incoming, "beforeRequest"),
|
|
59
|
+
beforeRetry: newHookValue(original, incoming, "beforeRetry"),
|
|
60
|
+
afterResponse: newHookValue(original, incoming, "afterResponse"),
|
|
61
|
+
beforeError: newHookValue(original, incoming, "beforeError")
|
|
62
|
+
});
|
|
74
63
|
var deepMerge = (...sources) => {
|
|
75
64
|
let returnValue = {};
|
|
76
65
|
let headers = {};
|
|
66
|
+
let hooks = {};
|
|
77
67
|
for (const source of sources) {
|
|
78
68
|
if (Array.isArray(source)) {
|
|
79
69
|
if (!Array.isArray(returnValue)) {
|
|
@@ -87,6 +77,10 @@ var deepMerge = (...sources) => {
|
|
|
87
77
|
}
|
|
88
78
|
returnValue = { ...returnValue, [key]: value };
|
|
89
79
|
}
|
|
80
|
+
if (isObject(source.hooks)) {
|
|
81
|
+
hooks = mergeHooks(hooks, source.hooks);
|
|
82
|
+
returnValue.hooks = hooks;
|
|
83
|
+
}
|
|
90
84
|
if (isObject(source.headers)) {
|
|
91
85
|
headers = mergeHeaders(headers, source.headers);
|
|
92
86
|
returnValue.headers = headers;
|
|
@@ -96,22 +90,29 @@ var deepMerge = (...sources) => {
|
|
|
96
90
|
return returnValue;
|
|
97
91
|
};
|
|
98
92
|
|
|
99
|
-
// node_modules
|
|
93
|
+
// ../../../node_modules/ky/distribution/core/constants.js
|
|
100
94
|
var supportsRequestStreams = (() => {
|
|
101
95
|
let duplexAccessed = false;
|
|
102
96
|
let hasContentType = false;
|
|
103
97
|
const supportsReadableStream = typeof globalThis.ReadableStream === "function";
|
|
104
98
|
const supportsRequest = typeof globalThis.Request === "function";
|
|
105
99
|
if (supportsReadableStream && supportsRequest) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
100
|
+
try {
|
|
101
|
+
hasContentType = new globalThis.Request("https://empty.invalid", {
|
|
102
|
+
body: new globalThis.ReadableStream(),
|
|
103
|
+
method: "POST",
|
|
104
|
+
// @ts-expect-error - Types are outdated.
|
|
105
|
+
get duplex() {
|
|
106
|
+
duplexAccessed = true;
|
|
107
|
+
return "half";
|
|
108
|
+
}
|
|
109
|
+
}).headers.has("Content-Type");
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof Error && error.message === "unsupported BodyInit type") {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
115
116
|
}
|
|
116
117
|
return duplexAccessed && !hasContentType;
|
|
117
118
|
})();
|
|
@@ -133,6 +134,7 @@ var stop = Symbol("stop");
|
|
|
133
134
|
var kyOptionKeys = {
|
|
134
135
|
json: true,
|
|
135
136
|
parseJson: true,
|
|
137
|
+
stringifyJson: true,
|
|
136
138
|
searchParams: true,
|
|
137
139
|
prefixUrl: true,
|
|
138
140
|
retry: true,
|
|
@@ -157,10 +159,11 @@ var requestOptionsRegistry = {
|
|
|
157
159
|
signal: true,
|
|
158
160
|
window: true,
|
|
159
161
|
dispatcher: true,
|
|
160
|
-
duplex: true
|
|
162
|
+
duplex: true,
|
|
163
|
+
priority: true
|
|
161
164
|
};
|
|
162
165
|
|
|
163
|
-
// node_modules
|
|
166
|
+
// ../../../node_modules/ky/distribution/utils/normalize.js
|
|
164
167
|
var normalizeRequestMethod = (input) => requestMethods.includes(input) ? input.toUpperCase() : input;
|
|
165
168
|
var retryMethods = ["get", "put", "head", "delete", "options", "trace"];
|
|
166
169
|
var retryStatusCodes = [408, 413, 429, 500, 502, 503, 504];
|
|
@@ -189,12 +192,11 @@ var normalizeRetryOptions = (retry = {}) => {
|
|
|
189
192
|
}
|
|
190
193
|
return {
|
|
191
194
|
...defaultRetryOptions,
|
|
192
|
-
...retry
|
|
193
|
-
afterStatusCodes: retryAfterStatusCodes
|
|
195
|
+
...retry
|
|
194
196
|
};
|
|
195
197
|
};
|
|
196
198
|
|
|
197
|
-
// node_modules
|
|
199
|
+
// ../../../node_modules/ky/distribution/utils/timeout.js
|
|
198
200
|
async function timeout(request, init, abortController, options) {
|
|
199
201
|
return new Promise((resolve, reject) => {
|
|
200
202
|
const timeoutId = setTimeout(() => {
|
|
@@ -209,7 +211,7 @@ async function timeout(request, init, abortController, options) {
|
|
|
209
211
|
});
|
|
210
212
|
}
|
|
211
213
|
|
|
212
|
-
// node_modules
|
|
214
|
+
// ../../../node_modules/ky/distribution/utils/delay.js
|
|
213
215
|
async function delay(ms, { signal }) {
|
|
214
216
|
return new Promise((resolve, reject) => {
|
|
215
217
|
if (signal) {
|
|
@@ -227,7 +229,7 @@ async function delay(ms, { signal }) {
|
|
|
227
229
|
});
|
|
228
230
|
}
|
|
229
231
|
|
|
230
|
-
// node_modules
|
|
232
|
+
// ../../../node_modules/ky/distribution/utils/options.js
|
|
231
233
|
var findUnknownOptions = (request, options) => {
|
|
232
234
|
const unknownOptions = {};
|
|
233
235
|
for (const key in options) {
|
|
@@ -238,11 +240,11 @@ var findUnknownOptions = (request, options) => {
|
|
|
238
240
|
return unknownOptions;
|
|
239
241
|
};
|
|
240
242
|
|
|
241
|
-
// node_modules
|
|
243
|
+
// ../../../node_modules/ky/distribution/core/Ky.js
|
|
242
244
|
var Ky = class _Ky {
|
|
243
245
|
static create(input, options) {
|
|
244
246
|
const ky2 = new _Ky(input, options);
|
|
245
|
-
const
|
|
247
|
+
const function_ = async () => {
|
|
246
248
|
if (typeof ky2._options.timeout === "number" && ky2._options.timeout > maxSafeTimeout) {
|
|
247
249
|
throw new RangeError(`The \`timeout\` option cannot be greater than ${maxSafeTimeout}`);
|
|
248
250
|
}
|
|
@@ -274,12 +276,11 @@ var Ky = class _Ky {
|
|
|
274
276
|
return response;
|
|
275
277
|
};
|
|
276
278
|
const isRetriableMethod = ky2._options.retry.methods.includes(ky2.request.method.toLowerCase());
|
|
277
|
-
const result = isRetriableMethod ? ky2._retry(
|
|
279
|
+
const result = isRetriableMethod ? ky2._retry(function_) : function_();
|
|
278
280
|
for (const [type, mimeType] of Object.entries(responseTypes)) {
|
|
279
281
|
result[type] = async () => {
|
|
280
282
|
ky2.request.headers.set("accept", ky2.request.headers.get("accept") || mimeType);
|
|
281
|
-
const
|
|
282
|
-
const response = awaitedResult.clone();
|
|
283
|
+
const response = await result;
|
|
283
284
|
if (type === "json") {
|
|
284
285
|
if (response.status === 204) {
|
|
285
286
|
return "";
|
|
@@ -298,51 +299,24 @@ var Ky = class _Ky {
|
|
|
298
299
|
}
|
|
299
300
|
return result;
|
|
300
301
|
}
|
|
302
|
+
request;
|
|
303
|
+
abortController;
|
|
304
|
+
_retryCount = 0;
|
|
305
|
+
_input;
|
|
306
|
+
_options;
|
|
301
307
|
// eslint-disable-next-line complexity
|
|
302
308
|
constructor(input, options = {}) {
|
|
303
|
-
Object.defineProperty(this, "request", {
|
|
304
|
-
enumerable: true,
|
|
305
|
-
configurable: true,
|
|
306
|
-
writable: true,
|
|
307
|
-
value: void 0
|
|
308
|
-
});
|
|
309
|
-
Object.defineProperty(this, "abortController", {
|
|
310
|
-
enumerable: true,
|
|
311
|
-
configurable: true,
|
|
312
|
-
writable: true,
|
|
313
|
-
value: void 0
|
|
314
|
-
});
|
|
315
|
-
Object.defineProperty(this, "_retryCount", {
|
|
316
|
-
enumerable: true,
|
|
317
|
-
configurable: true,
|
|
318
|
-
writable: true,
|
|
319
|
-
value: 0
|
|
320
|
-
});
|
|
321
|
-
Object.defineProperty(this, "_input", {
|
|
322
|
-
enumerable: true,
|
|
323
|
-
configurable: true,
|
|
324
|
-
writable: true,
|
|
325
|
-
value: void 0
|
|
326
|
-
});
|
|
327
|
-
Object.defineProperty(this, "_options", {
|
|
328
|
-
enumerable: true,
|
|
329
|
-
configurable: true,
|
|
330
|
-
writable: true,
|
|
331
|
-
value: void 0
|
|
332
|
-
});
|
|
333
309
|
this._input = input;
|
|
334
310
|
this._options = {
|
|
335
|
-
// TODO: credentials can be removed when the spec change is implemented in all browsers. Context: https://www.chromestatus.com/feature/4539473312350208
|
|
336
|
-
credentials: this._input.credentials || "same-origin",
|
|
337
311
|
...options,
|
|
338
312
|
headers: mergeHeaders(this._input.headers, options.headers),
|
|
339
|
-
hooks:
|
|
313
|
+
hooks: mergeHooks({
|
|
340
314
|
beforeRequest: [],
|
|
341
315
|
beforeRetry: [],
|
|
342
316
|
beforeError: [],
|
|
343
317
|
afterResponse: []
|
|
344
318
|
}, options.hooks),
|
|
345
|
-
method: normalizeRequestMethod(options.method ?? this._input.method),
|
|
319
|
+
method: normalizeRequestMethod(options.method ?? this._input.method ?? "GET"),
|
|
346
320
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
347
321
|
prefixUrl: String(options.prefixUrl || ""),
|
|
348
322
|
retry: normalizeRetryOptions(options.retry),
|
|
@@ -364,17 +338,22 @@ var Ky = class _Ky {
|
|
|
364
338
|
}
|
|
365
339
|
if (supportsAbortController) {
|
|
366
340
|
this.abortController = new globalThis.AbortController();
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
this.
|
|
370
|
-
this.abortController.abort(originalSignal.reason);
|
|
371
|
-
});
|
|
341
|
+
const originalSignal = this._options.signal ?? this._input.signal;
|
|
342
|
+
if (originalSignal?.aborted) {
|
|
343
|
+
this.abortController.abort(originalSignal?.reason);
|
|
372
344
|
}
|
|
345
|
+
originalSignal?.addEventListener("abort", () => {
|
|
346
|
+
this.abortController.abort(originalSignal.reason);
|
|
347
|
+
});
|
|
373
348
|
this._options.signal = this.abortController.signal;
|
|
374
349
|
}
|
|
375
350
|
if (supportsRequestStreams) {
|
|
376
351
|
this._options.duplex = "half";
|
|
377
352
|
}
|
|
353
|
+
if (this._options.json !== void 0) {
|
|
354
|
+
this._options.body = this._options.stringifyJson?.(this._options.json) ?? JSON.stringify(this._options.json);
|
|
355
|
+
this._options.headers.set("content-type", this._options.headers.get("content-type") ?? "application/json");
|
|
356
|
+
}
|
|
378
357
|
this.request = new globalThis.Request(this._input, this._options);
|
|
379
358
|
if (this._options.searchParams) {
|
|
380
359
|
const textSearchParams = typeof this._options.searchParams === "string" ? this._options.searchParams.replace(/^\?/, "") : new URLSearchParams(this._options.searchParams).toString();
|
|
@@ -385,40 +364,33 @@ var Ky = class _Ky {
|
|
|
385
364
|
}
|
|
386
365
|
this.request = new globalThis.Request(new globalThis.Request(url, { ...this.request }), this._options);
|
|
387
366
|
}
|
|
388
|
-
if (this._options.json !== void 0) {
|
|
389
|
-
this._options.body = JSON.stringify(this._options.json);
|
|
390
|
-
this.request.headers.set("content-type", this._options.headers.get("content-type") ?? "application/json");
|
|
391
|
-
this.request = new globalThis.Request(this.request, { body: this._options.body });
|
|
392
|
-
}
|
|
393
367
|
}
|
|
394
368
|
_calculateRetryDelay(error) {
|
|
395
369
|
this._retryCount++;
|
|
396
|
-
if (this._retryCount
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
return 0;
|
|
411
|
-
}
|
|
412
|
-
return after;
|
|
413
|
-
}
|
|
414
|
-
if (error.response.status === 413) {
|
|
415
|
-
return 0;
|
|
370
|
+
if (this._retryCount > this._options.retry.limit || error instanceof TimeoutError) {
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
if (error instanceof HTTPError) {
|
|
374
|
+
if (!this._options.retry.statusCodes.includes(error.response.status)) {
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
const retryAfter = error.response.headers.get("Retry-After") ?? error.response.headers.get("RateLimit-Reset") ?? error.response.headers.get("X-RateLimit-Reset") ?? error.response.headers.get("X-Rate-Limit-Reset");
|
|
378
|
+
if (retryAfter && this._options.retry.afterStatusCodes.includes(error.response.status)) {
|
|
379
|
+
let after = Number(retryAfter) * 1e3;
|
|
380
|
+
if (Number.isNaN(after)) {
|
|
381
|
+
after = Date.parse(retryAfter) - Date.now();
|
|
382
|
+
} else if (after >= Date.parse("2024-01-01")) {
|
|
383
|
+
after -= Date.now();
|
|
416
384
|
}
|
|
385
|
+
const max = this._options.retry.maxRetryAfter ?? after;
|
|
386
|
+
return after < max ? after : max;
|
|
387
|
+
}
|
|
388
|
+
if (error.response.status === 413) {
|
|
389
|
+
throw error;
|
|
417
390
|
}
|
|
418
|
-
const retryDelay = this._options.retry.delay(this._retryCount);
|
|
419
|
-
return Math.min(this._options.retry.backoffLimit, retryDelay);
|
|
420
391
|
}
|
|
421
|
-
|
|
392
|
+
const retryDelay = this._options.retry.delay(this._retryCount);
|
|
393
|
+
return Math.min(this._options.retry.backoffLimit, retryDelay);
|
|
422
394
|
}
|
|
423
395
|
_decorateResponse(response) {
|
|
424
396
|
if (this._options.parseJson) {
|
|
@@ -426,27 +398,27 @@ var Ky = class _Ky {
|
|
|
426
398
|
}
|
|
427
399
|
return response;
|
|
428
400
|
}
|
|
429
|
-
async _retry(
|
|
401
|
+
async _retry(function_) {
|
|
430
402
|
try {
|
|
431
|
-
return await
|
|
403
|
+
return await function_();
|
|
432
404
|
} catch (error) {
|
|
433
405
|
const ms = Math.min(this._calculateRetryDelay(error), maxSafeTimeout);
|
|
434
|
-
if (
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
406
|
+
if (this._retryCount < 1) {
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
await delay(ms, { signal: this._options.signal });
|
|
410
|
+
for (const hook of this._options.hooks.beforeRetry) {
|
|
411
|
+
const hookResult = await hook({
|
|
412
|
+
request: this.request,
|
|
413
|
+
options: this._options,
|
|
414
|
+
error,
|
|
415
|
+
retryCount: this._retryCount
|
|
416
|
+
});
|
|
417
|
+
if (hookResult === stop) {
|
|
418
|
+
return;
|
|
446
419
|
}
|
|
447
|
-
return this._retry(fn);
|
|
448
420
|
}
|
|
449
|
-
|
|
421
|
+
return this._retry(function_);
|
|
450
422
|
}
|
|
451
423
|
}
|
|
452
424
|
async _fetch() {
|
|
@@ -461,10 +433,12 @@ var Ky = class _Ky {
|
|
|
461
433
|
}
|
|
462
434
|
}
|
|
463
435
|
const nonRequestOptions = findUnknownOptions(this.request, this._options);
|
|
436
|
+
const mainRequest = this.request;
|
|
437
|
+
this.request = mainRequest.clone();
|
|
464
438
|
if (this._options.timeout === false) {
|
|
465
|
-
return this._options.fetch(
|
|
439
|
+
return this._options.fetch(mainRequest, nonRequestOptions);
|
|
466
440
|
}
|
|
467
|
-
return timeout(
|
|
441
|
+
return timeout(mainRequest, nonRequestOptions, this.abortController, this._options);
|
|
468
442
|
}
|
|
469
443
|
/* istanbul ignore next */
|
|
470
444
|
_stream(response, onDownloadProgress) {
|
|
@@ -510,14 +484,19 @@ var Ky = class _Ky {
|
|
|
510
484
|
}
|
|
511
485
|
};
|
|
512
486
|
|
|
513
|
-
// node_modules
|
|
487
|
+
// ../../../node_modules/ky/distribution/index.js
|
|
514
488
|
var createInstance = (defaults) => {
|
|
515
489
|
const ky2 = (input, options) => Ky.create(input, validateAndMerge(defaults, options));
|
|
516
490
|
for (const method of requestMethods) {
|
|
517
491
|
ky2[method] = (input, options) => Ky.create(input, validateAndMerge(defaults, options, { method }));
|
|
518
492
|
}
|
|
519
493
|
ky2.create = (newDefaults) => createInstance(validateAndMerge(newDefaults));
|
|
520
|
-
ky2.extend = (newDefaults) =>
|
|
494
|
+
ky2.extend = (newDefaults) => {
|
|
495
|
+
if (typeof newDefaults === "function") {
|
|
496
|
+
newDefaults = newDefaults(defaults ?? {});
|
|
497
|
+
}
|
|
498
|
+
return createInstance(validateAndMerge(defaults, newDefaults));
|
|
499
|
+
};
|
|
521
500
|
ky2.stop = stop;
|
|
522
501
|
return ky2;
|
|
523
502
|
};
|
|
@@ -551,6 +530,24 @@ function getTelemetry() {
|
|
|
551
530
|
return { platform, runtime, sdkVersions };
|
|
552
531
|
}
|
|
553
532
|
|
|
533
|
+
// src/format.ts
|
|
534
|
+
var SUPPORTED_FORMATS = ["png", "jpeg", "webp"];
|
|
535
|
+
var isSupportedFormat = (value) => SUPPORTED_FORMATS.includes(value);
|
|
536
|
+
var validateImageFormat = (value) => {
|
|
537
|
+
if (!value) {
|
|
538
|
+
return { ok: true, format: "png" };
|
|
539
|
+
}
|
|
540
|
+
if (isSupportedFormat(value)) {
|
|
541
|
+
return { ok: true, format: value };
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
ok: false,
|
|
545
|
+
error: {
|
|
546
|
+
message: `Unsupported format "${value}". Valid formats are png, jpeg, or webp.`
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
|
|
554
551
|
// src/types.ts
|
|
555
552
|
var timeoutError = {
|
|
556
553
|
error: {
|
|
@@ -563,6 +560,15 @@ var timeoutError = {
|
|
|
563
560
|
};
|
|
564
561
|
|
|
565
562
|
// src/client.ts
|
|
563
|
+
var invalidFormatResult = (value) => ({
|
|
564
|
+
error: {
|
|
565
|
+
// @ts-ignore – local validation error
|
|
566
|
+
code: "INVALID_FORMAT",
|
|
567
|
+
docs: "https://bannerify.co/docs",
|
|
568
|
+
message: `Unsupported format "${value ?? "undefined"}". Valid formats are png, jpeg, or webp.`,
|
|
569
|
+
requestId: "local"
|
|
570
|
+
}
|
|
571
|
+
});
|
|
566
572
|
function createClient(apiKey, opts) {
|
|
567
573
|
return new Bannerify(apiKey, opts);
|
|
568
574
|
}
|
|
@@ -581,32 +587,35 @@ var Bannerify = class {
|
|
|
581
587
|
"X-Platform": telemetry?.platform,
|
|
582
588
|
"X-Runtime": telemetry?.runtime
|
|
583
589
|
},
|
|
584
|
-
timeout: opts?.timeout ??
|
|
590
|
+
timeout: opts?.timeout ?? 6e4
|
|
585
591
|
});
|
|
586
592
|
}
|
|
587
593
|
client;
|
|
588
594
|
baseUrl;
|
|
589
595
|
async createImage(templateId, options) {
|
|
590
596
|
try {
|
|
597
|
+
const normalizedFormat = validateImageFormat(options?.format);
|
|
598
|
+
if (!normalizedFormat.ok) {
|
|
599
|
+
return invalidFormatResult(options?.format);
|
|
600
|
+
}
|
|
591
601
|
const res = await this.client.post("templates/createImage", {
|
|
592
602
|
json: {
|
|
593
603
|
modifications: options?.modifications ?? [],
|
|
594
604
|
// template: JSON.stringify(options?.template ?? {}),
|
|
595
605
|
templateId,
|
|
596
606
|
apiKey: this.apiKey,
|
|
597
|
-
format:
|
|
607
|
+
format: normalizedFormat.format,
|
|
608
|
+
thumbnail: options?.thumbnail ?? false
|
|
598
609
|
}
|
|
599
610
|
});
|
|
600
|
-
if (options?.format === "svg") {
|
|
601
|
-
return { result: await res.text() };
|
|
602
|
-
}
|
|
603
611
|
return { result: await res.arrayBuffer() };
|
|
604
612
|
} catch (e) {
|
|
605
613
|
if (e instanceof HTTPError) {
|
|
606
|
-
|
|
614
|
+
const json = await e.response.json();
|
|
615
|
+
return { error: json.error };
|
|
607
616
|
}
|
|
608
617
|
if (e instanceof TimeoutError) {
|
|
609
|
-
return timeoutError;
|
|
618
|
+
return { error: timeoutError.error };
|
|
610
619
|
}
|
|
611
620
|
throw e;
|
|
612
621
|
}
|
|
@@ -618,40 +627,47 @@ var Bannerify = class {
|
|
|
618
627
|
modifications: options?.modifications ?? [],
|
|
619
628
|
// template: JSON.stringify(options?.template ?? {}),
|
|
620
629
|
templateId,
|
|
621
|
-
apiKey: this.apiKey
|
|
622
|
-
format: options?.format
|
|
630
|
+
apiKey: this.apiKey
|
|
623
631
|
}
|
|
624
632
|
});
|
|
625
633
|
return { result: await res.arrayBuffer() };
|
|
626
634
|
} catch (e) {
|
|
627
635
|
if (e instanceof HTTPError) {
|
|
628
|
-
|
|
636
|
+
const json = await e.response.json();
|
|
637
|
+
return { error: json.error };
|
|
629
638
|
}
|
|
630
639
|
if (e instanceof TimeoutError) {
|
|
631
|
-
return timeoutError;
|
|
640
|
+
return { error: timeoutError.error };
|
|
632
641
|
}
|
|
633
642
|
throw e;
|
|
634
643
|
}
|
|
635
644
|
}
|
|
636
645
|
async createStoredImage(templateId, options) {
|
|
637
646
|
try {
|
|
647
|
+
const normalizedFormat = validateImageFormat(options?.format);
|
|
648
|
+
if (!normalizedFormat.ok) {
|
|
649
|
+
return invalidFormatResult(options?.format);
|
|
650
|
+
}
|
|
638
651
|
const res = await this.client.post("templates/createStoredImage", {
|
|
639
652
|
json: {
|
|
640
653
|
modifications: options?.modifications ?? [],
|
|
641
654
|
// template: JSON.stringify(options?.template ?? {}),
|
|
642
655
|
templateId,
|
|
643
656
|
apiKey: this.apiKey,
|
|
644
|
-
format:
|
|
657
|
+
format: normalizedFormat.format,
|
|
658
|
+
thumbnail: options?.thumbnail ?? false,
|
|
659
|
+
s3Config: options?.s3Config
|
|
645
660
|
}
|
|
646
661
|
});
|
|
647
662
|
const json = await res.json();
|
|
648
663
|
return { result: json.url };
|
|
649
664
|
} catch (e) {
|
|
650
665
|
if (e instanceof HTTPError) {
|
|
651
|
-
|
|
666
|
+
const json = await e.response.json();
|
|
667
|
+
return { error: json.error };
|
|
652
668
|
}
|
|
653
669
|
if (e instanceof TimeoutError) {
|
|
654
|
-
return timeoutError;
|
|
670
|
+
return { error: timeoutError.error };
|
|
655
671
|
}
|
|
656
672
|
throw e;
|
|
657
673
|
}
|
|
@@ -663,12 +679,33 @@ var Bannerify = class {
|
|
|
663
679
|
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
664
680
|
return hashHex;
|
|
665
681
|
};
|
|
682
|
+
// The signature is an HMAC keyed with the API key itself, so a signed URL can
|
|
683
|
+
// be shared without exposing anything that can sign a different one. The
|
|
684
|
+
// apiKeyHashed in the URL only tells the server which key to verify with.
|
|
685
|
+
#signText = async (text) => {
|
|
686
|
+
const key = await crypto.subtle.importKey(
|
|
687
|
+
"raw",
|
|
688
|
+
new TextEncoder().encode(this.apiKey),
|
|
689
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
690
|
+
false,
|
|
691
|
+
["sign"]
|
|
692
|
+
);
|
|
693
|
+
const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(text));
|
|
694
|
+
return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
695
|
+
};
|
|
666
696
|
async generateImageSignedUrl(templateId, options) {
|
|
667
697
|
const apiKeyHashed = await this.#hashText(this.apiKey);
|
|
668
698
|
const searchParams = new URLSearchParams();
|
|
669
699
|
searchParams.set("apiKeyHashed", apiKeyHashed);
|
|
670
|
-
if (options?.format
|
|
671
|
-
|
|
700
|
+
if (options?.format) {
|
|
701
|
+
const normalizedFormat = validateImageFormat(options.format);
|
|
702
|
+
if (!normalizedFormat.ok) {
|
|
703
|
+
throw new Error(normalizedFormat.error.message);
|
|
704
|
+
}
|
|
705
|
+
searchParams.set("format", normalizedFormat.format);
|
|
706
|
+
}
|
|
707
|
+
if (options?.quality !== void 0) {
|
|
708
|
+
searchParams.set("quality", String(options.quality));
|
|
672
709
|
}
|
|
673
710
|
if (options?.modifications) {
|
|
674
711
|
searchParams.set("modifications", JSON.stringify(options?.modifications));
|
|
@@ -676,12 +713,12 @@ var Bannerify = class {
|
|
|
676
713
|
if (options?.nocache) {
|
|
677
714
|
searchParams.set("nocache", "true");
|
|
678
715
|
}
|
|
716
|
+
if (options?.thumbnail) {
|
|
717
|
+
searchParams.set("thumbnail", "true");
|
|
718
|
+
}
|
|
679
719
|
searchParams.set("templateId", templateId);
|
|
680
720
|
searchParams.sort();
|
|
681
|
-
searchParams.set(
|
|
682
|
-
"sign",
|
|
683
|
-
await this.#hashText(searchParams.toString() + searchParams.get("apiKeyHashed"))
|
|
684
|
-
);
|
|
721
|
+
searchParams.set("sign", await this.#signText(searchParams.toString()));
|
|
685
722
|
return `${this.baseUrl}/templates/signedurl?${searchParams.toString()}`;
|
|
686
723
|
}
|
|
687
724
|
};
|