@videxo/sdk 0.0.0-stage → 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.
@@ -0,0 +1,80 @@
1
+ import type { CommandProblem, FieldError, Problem } from './types.ts';
2
+ /** The API's documented error codes (`code` of a problem details answer). */
3
+ export type ApiErrorCode = Problem['code'];
4
+ /**
5
+ * Codes the SDK sets itself, when there is no problem details answer to read:
6
+ *
7
+ * - `network_error`: the request did not get an answer (DNS, TLS, a reset connection).
8
+ * - `timeout`: no answer within `timeoutMs`.
9
+ * - `aborted`: the caller's `AbortSignal` stopped the request or the wait.
10
+ * - `wait_timeout`: `jobs.wait()` gave up before the job ended.
11
+ * - `http_error`: an error answer that is not problem details (a proxy's HTML page, for example).
12
+ * - `invalid_response`: a successful answer the SDK could not read.
13
+ * - `output_not_found`, `output_ambiguous`: `outputs.url()` or `outputs.download()` named an output
14
+ * the job does not have, or a name several of its files share (use the file's alias).
15
+ */
16
+ export declare const SDK_ERROR_CODES: readonly ["network_error", "timeout", "aborted", "wait_timeout", "http_error", "invalid_response", "output_not_found", "output_ambiguous"];
17
+ export type SdkErrorCode = (typeof SDK_ERROR_CODES)[number];
18
+ export type VidexoErrorCode = ApiErrorCode | SdkErrorCode;
19
+ export type VidexoErrorInit = {
20
+ status: number | null;
21
+ code: VidexoErrorCode;
22
+ title: string;
23
+ detail: string;
24
+ type?: string | null;
25
+ errors?: FieldError[];
26
+ problems?: CommandProblem[];
27
+ retryAfter?: number | null;
28
+ reason?: string | null;
29
+ retryable?: boolean | null;
30
+ requestId?: string | null;
31
+ body?: unknown;
32
+ cause?: unknown;
33
+ };
34
+ /**
35
+ * Every failure of a call: a problem details answer of the API (`status`, `code`, `reason`, `title`,
36
+ * `detail`, `type`, `retryable`, `requestId`, `errors`, `problems`), or one of the SDK's own codes
37
+ * with `status` null. Programs branch on `code`, and on `reason` for the finer case. The message
38
+ * never holds the API key.
39
+ */
40
+ export declare class VidexoError extends Error {
41
+ readonly name = "VidexoError";
42
+ /** The HTTP status; null when no answer came (`network_error`, `timeout`, `aborted`, ...). */
43
+ readonly status: number | null;
44
+ readonly code: VidexoErrorCode;
45
+ /** The code's fixed sentence. */
46
+ readonly title: string;
47
+ /** What happened this time, for people; it may change. */
48
+ readonly detail: string;
49
+ /** `https://videxo.io/docs/errors#<code>` for an API error; null otherwise. */
50
+ readonly type: string | null;
51
+ /** With `invalid_request`: one entry per field that failed. */
52
+ readonly errors: FieldError[];
53
+ /** With `command_invalid`: why the command is not accepted. */
54
+ readonly problems: CommandProblem[];
55
+ /** The documented finer case of `code` (the Errors page lists them); null without one. */
56
+ readonly reason: string | null;
57
+ /** The API's hint whether the same request can succeed later; null for the SDK's own codes. */
58
+ readonly retryable: boolean | null;
59
+ /** The answer's `Request-Id` (body or header); quote it to support. Null when no answer came. */
60
+ readonly requestId: string | null;
61
+ /** Seconds from the answer's `Retry-After` header (429, 503); null without one. */
62
+ readonly retryAfter: number | null;
63
+ /** The answer's body as received (parsed JSON or text); undefined when no answer came. */
64
+ readonly body: unknown;
65
+ constructor(init: VidexoErrorInit);
66
+ }
67
+ /** An error with one of the SDK's own codes. */
68
+ export declare function sdkError(code: SdkErrorCode, detail: string, extra?: Partial<VidexoErrorInit>): VidexoError;
69
+ /** Seconds of a `Retry-After` header, as a number of seconds or an HTTP date; null when absent or unreadable. */
70
+ export declare function retryAfterSeconds(value: string | null, now?: number): number | null;
71
+ /** The error of a non-2xx answer whose body was read as `body` (parsed JSON, or the text when it was not JSON). */
72
+ export declare function errorFromResponse(response: Response, body: unknown): VidexoError;
73
+ /** Why a webhook was refused by `verifyWebhook`. */
74
+ export type VidexoWebhookErrorCode = 'missing_headers' | 'invalid_secret' | 'invalid_timestamp' | 'invalid_signature' | 'invalid_payload';
75
+ /** A webhook that did not pass verification: answer it with a 400 and do not act on it. */
76
+ export declare class VidexoWebhookError extends Error {
77
+ readonly name = "VidexoWebhookError";
78
+ readonly code: VidexoWebhookErrorCode;
79
+ constructor(code: VidexoWebhookErrorCode, message: string);
80
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Codes the SDK sets itself, when there is no problem details answer to read:
3
+ *
4
+ * - `network_error`: the request did not get an answer (DNS, TLS, a reset connection).
5
+ * - `timeout`: no answer within `timeoutMs`.
6
+ * - `aborted`: the caller's `AbortSignal` stopped the request or the wait.
7
+ * - `wait_timeout`: `jobs.wait()` gave up before the job ended.
8
+ * - `http_error`: an error answer that is not problem details (a proxy's HTML page, for example).
9
+ * - `invalid_response`: a successful answer the SDK could not read.
10
+ * - `output_not_found`, `output_ambiguous`: `outputs.url()` or `outputs.download()` named an output
11
+ * the job does not have, or a name several of its files share (use the file's alias).
12
+ */
13
+ export const SDK_ERROR_CODES = [
14
+ 'network_error',
15
+ 'timeout',
16
+ 'aborted',
17
+ 'wait_timeout',
18
+ 'http_error',
19
+ 'invalid_response',
20
+ 'output_not_found',
21
+ 'output_ambiguous',
22
+ ];
23
+ /**
24
+ * Every failure of a call: a problem details answer of the API (`status`, `code`, `reason`, `title`,
25
+ * `detail`, `type`, `retryable`, `requestId`, `errors`, `problems`), or one of the SDK's own codes
26
+ * with `status` null. Programs branch on `code`, and on `reason` for the finer case. The message
27
+ * never holds the API key.
28
+ */
29
+ export class VidexoError extends Error {
30
+ name = 'VidexoError';
31
+ /** The HTTP status; null when no answer came (`network_error`, `timeout`, `aborted`, ...). */
32
+ status;
33
+ code;
34
+ /** The code's fixed sentence. */
35
+ title;
36
+ /** What happened this time, for people; it may change. */
37
+ detail;
38
+ /** `https://videxo.io/docs/errors#<code>` for an API error; null otherwise. */
39
+ type;
40
+ /** With `invalid_request`: one entry per field that failed. */
41
+ errors;
42
+ /** With `command_invalid`: why the command is not accepted. */
43
+ problems;
44
+ /** The documented finer case of `code` (the Errors page lists them); null without one. */
45
+ reason;
46
+ /** The API's hint whether the same request can succeed later; null for the SDK's own codes. */
47
+ retryable;
48
+ /** The answer's `Request-Id` (body or header); quote it to support. Null when no answer came. */
49
+ requestId;
50
+ /** Seconds from the answer's `Retry-After` header (429, 503); null without one. */
51
+ retryAfter;
52
+ /** The answer's body as received (parsed JSON or text); undefined when no answer came. */
53
+ body;
54
+ constructor(init) {
55
+ super(`${init.code}${init.status ? ` (${init.status})` : ''}: ${init.detail}`, init.cause === undefined ? undefined : { cause: init.cause });
56
+ this.status = init.status;
57
+ this.code = init.code;
58
+ this.title = init.title;
59
+ this.detail = init.detail;
60
+ this.type = init.type ?? null;
61
+ this.errors = init.errors ?? [];
62
+ this.problems = init.problems ?? [];
63
+ this.retryAfter = init.retryAfter ?? null;
64
+ this.reason = init.reason ?? null;
65
+ this.retryable = init.retryable ?? null;
66
+ this.requestId = init.requestId ?? null;
67
+ this.body = init.body;
68
+ }
69
+ }
70
+ const SDK_TITLES = {
71
+ network_error: 'The request did not get an answer.',
72
+ timeout: 'The request timed out.',
73
+ aborted: 'The request was aborted.',
74
+ wait_timeout: 'The job did not end within the wait.',
75
+ http_error: 'The API answered with an error that is not problem details.',
76
+ invalid_response: 'The API answered with a body the SDK could not read.',
77
+ output_not_found: 'The job has no output with this alias or name.',
78
+ output_ambiguous: 'Several files of the job have this name. Use the alias of one.',
79
+ };
80
+ /** An error with one of the SDK's own codes. */
81
+ export function sdkError(code, detail, extra = {}) {
82
+ return new VidexoError({ status: null, title: SDK_TITLES[code], detail, ...extra, code });
83
+ }
84
+ /** Seconds of a `Retry-After` header, as a number of seconds or an HTTP date; null when absent or unreadable. */
85
+ export function retryAfterSeconds(value, now = Date.now()) {
86
+ if (value === null || value.trim() === '')
87
+ return null;
88
+ const text = value.trim();
89
+ if (/^\d+$/.test(text))
90
+ return Number(text);
91
+ const date = Date.parse(text);
92
+ if (Number.isNaN(date))
93
+ return null;
94
+ return Math.max(0, Math.ceil((date - now) / 1000));
95
+ }
96
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
97
+ /** The error of a non-2xx answer whose body was read as `body` (parsed JSON, or the text when it was not JSON). */
98
+ export function errorFromResponse(response, body) {
99
+ const retryAfter = retryAfterSeconds(response.headers.get('retry-after'));
100
+ const headerId = response.headers.get('request-id');
101
+ if (isRecord(body) && typeof body.code === 'string' && typeof body.title === 'string') {
102
+ return new VidexoError({
103
+ status: response.status,
104
+ code: body.code,
105
+ title: body.title,
106
+ detail: typeof body.detail === 'string' ? body.detail : body.title,
107
+ type: typeof body.type === 'string' ? body.type : null,
108
+ errors: Array.isArray(body.errors) ? body.errors : [],
109
+ problems: Array.isArray(body.problems) ? body.problems : [],
110
+ reason: typeof body.reason === 'string' ? body.reason : null,
111
+ retryable: typeof body.retryable === 'boolean' ? body.retryable : null,
112
+ requestId: typeof body.request_id === 'string' ? body.request_id : headerId,
113
+ retryAfter,
114
+ body,
115
+ });
116
+ }
117
+ return sdkError('http_error', `The API answered ${response.status}${response.statusText ? ` ${response.statusText}` : ''}.`, {
118
+ status: response.status,
119
+ retryAfter,
120
+ requestId: headerId,
121
+ body,
122
+ });
123
+ }
124
+ /** A webhook that did not pass verification: answer it with a 400 and do not act on it. */
125
+ export class VidexoWebhookError extends Error {
126
+ name = 'VidexoWebhookError';
127
+ code;
128
+ constructor(code, message) {
129
+ super(message);
130
+ this.code = code;
131
+ }
132
+ }