@liqhtworks/sophon-sdk 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/.github/workflows/publish.yml +56 -0
- package/.openapi-generator/FILES +73 -0
- package/.openapi-generator/VERSION +1 -0
- package/.openapi-generator-ignore +23 -0
- package/LICENSE +12 -0
- package/README.md +164 -0
- package/dist/apis/DownloadsApi.d.ts +63 -0
- package/dist/apis/DownloadsApi.js +58 -0
- package/dist/apis/HealthApi.d.ts +92 -0
- package/dist/apis/HealthApi.js +85 -0
- package/dist/apis/JobsApi.d.ts +225 -0
- package/dist/apis/JobsApi.js +245 -0
- package/dist/apis/UploadsApi.d.ts +228 -0
- package/dist/apis/UploadsApi.js +255 -0
- package/dist/apis/WebhooksApi.d.ts +138 -0
- package/dist/apis/WebhooksApi.js +152 -0
- package/dist/apis/index.d.ts +5 -0
- package/dist/apis/index.js +23 -0
- package/dist/esm/apis/DownloadsApi.d.ts +63 -0
- package/dist/esm/apis/DownloadsApi.js +54 -0
- package/dist/esm/apis/HealthApi.d.ts +92 -0
- package/dist/esm/apis/HealthApi.js +81 -0
- package/dist/esm/apis/JobsApi.d.ts +225 -0
- package/dist/esm/apis/JobsApi.js +241 -0
- package/dist/esm/apis/UploadsApi.d.ts +228 -0
- package/dist/esm/apis/UploadsApi.js +251 -0
- package/dist/esm/apis/WebhooksApi.d.ts +138 -0
- package/dist/esm/apis/WebhooksApi.js +148 -0
- package/dist/esm/apis/index.d.ts +5 -0
- package/dist/esm/apis/index.js +7 -0
- package/dist/esm/helpers/index.d.ts +3 -0
- package/dist/esm/helpers/index.js +3 -0
- package/dist/esm/helpers/jobs.d.ts +48 -0
- package/dist/esm/helpers/jobs.js +61 -0
- package/dist/esm/helpers/uploads.d.ts +71 -0
- package/dist/esm/helpers/uploads.js +146 -0
- package/dist/esm/helpers/webhooks.d.ts +23 -0
- package/dist/esm/helpers/webhooks.js +84 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/models/CompleteUploadResponse.d.ts +57 -0
- package/dist/esm/models/CompleteUploadResponse.js +63 -0
- package/dist/esm/models/CreateJobOutputOptions.d.ts +55 -0
- package/dist/esm/models/CreateJobOutputOptions.js +46 -0
- package/dist/esm/models/CreateJobRequest.d.ts +61 -0
- package/dist/esm/models/CreateJobRequest.js +56 -0
- package/dist/esm/models/CreateUploadRequest.d.ts +44 -0
- package/dist/esm/models/CreateUploadRequest.js +51 -0
- package/dist/esm/models/CreateUploadResponse.d.ts +52 -0
- package/dist/esm/models/CreateUploadResponse.js +55 -0
- package/dist/esm/models/CreateWebhookRequest.d.ts +40 -0
- package/dist/esm/models/CreateWebhookRequest.js +45 -0
- package/dist/esm/models/ErrorBody.d.ts +72 -0
- package/dist/esm/models/ErrorBody.js +74 -0
- package/dist/esm/models/ErrorEnvelope.d.ts +33 -0
- package/dist/esm/models/ErrorEnvelope.js +44 -0
- package/dist/esm/models/JobOutputInfo.d.ts +95 -0
- package/dist/esm/models/JobOutputInfo.js +72 -0
- package/dist/esm/models/JobProfile.d.ts +49 -0
- package/dist/esm/models/JobProfile.js +69 -0
- package/dist/esm/models/JobProgress.d.ts +75 -0
- package/dist/esm/models/JobProgress.js +60 -0
- package/dist/esm/models/JobResponse.d.ts +134 -0
- package/dist/esm/models/JobResponse.js +94 -0
- package/dist/esm/models/JobSourceInfo.d.ts +62 -0
- package/dist/esm/models/JobSourceInfo.js +53 -0
- package/dist/esm/models/JobSourceType.d.ts +24 -0
- package/dist/esm/models/JobSourceType.js +44 -0
- package/dist/esm/models/JobStatus.d.ts +31 -0
- package/dist/esm/models/JobStatus.js +51 -0
- package/dist/esm/models/ListJobsResponse.d.ts +45 -0
- package/dist/esm/models/ListJobsResponse.js +50 -0
- package/dist/esm/models/OutputContainer.d.ts +27 -0
- package/dist/esm/models/OutputContainer.js +47 -0
- package/dist/esm/models/ReadyResponse.d.ts +38 -0
- package/dist/esm/models/ReadyResponse.js +45 -0
- package/dist/esm/models/UploadJobSource.d.ts +39 -0
- package/dist/esm/models/UploadJobSource.js +48 -0
- package/dist/esm/models/UploadPartResponse.d.ts +38 -0
- package/dist/esm/models/UploadPartResponse.js +47 -0
- package/dist/esm/models/UploadStatusResponse.d.ts +96 -0
- package/dist/esm/models/UploadStatusResponse.js +80 -0
- package/dist/esm/models/WebhookDeliveryPayload.d.ts +85 -0
- package/dist/esm/models/WebhookDeliveryPayload.js +83 -0
- package/dist/esm/models/WebhookListItem.d.ts +50 -0
- package/dist/esm/models/WebhookListItem.js +55 -0
- package/dist/esm/models/WebhookListResponse.d.ts +33 -0
- package/dist/esm/models/WebhookListResponse.js +44 -0
- package/dist/esm/models/WebhookResponse.d.ts +58 -0
- package/dist/esm/models/WebhookResponse.js +59 -0
- package/dist/esm/models/index.d.ts +25 -0
- package/dist/esm/models/index.js +27 -0
- package/dist/esm/runtime.d.ts +184 -0
- package/dist/esm/runtime.js +348 -0
- package/dist/helpers/index.d.ts +3 -0
- package/dist/helpers/index.js +19 -0
- package/dist/helpers/jobs.d.ts +48 -0
- package/dist/helpers/jobs.js +67 -0
- package/dist/helpers/uploads.d.ts +71 -0
- package/dist/helpers/uploads.js +149 -0
- package/dist/helpers/webhooks.d.ts +23 -0
- package/dist/helpers/webhooks.js +89 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +22 -0
- package/dist/models/CompleteUploadResponse.d.ts +57 -0
- package/dist/models/CompleteUploadResponse.js +71 -0
- package/dist/models/CreateJobOutputOptions.d.ts +55 -0
- package/dist/models/CreateJobOutputOptions.js +53 -0
- package/dist/models/CreateJobRequest.d.ts +61 -0
- package/dist/models/CreateJobRequest.js +63 -0
- package/dist/models/CreateUploadRequest.d.ts +44 -0
- package/dist/models/CreateUploadRequest.js +58 -0
- package/dist/models/CreateUploadResponse.d.ts +52 -0
- package/dist/models/CreateUploadResponse.js +62 -0
- package/dist/models/CreateWebhookRequest.d.ts +40 -0
- package/dist/models/CreateWebhookRequest.js +52 -0
- package/dist/models/ErrorBody.d.ts +72 -0
- package/dist/models/ErrorBody.js +82 -0
- package/dist/models/ErrorEnvelope.d.ts +33 -0
- package/dist/models/ErrorEnvelope.js +51 -0
- package/dist/models/JobOutputInfo.d.ts +95 -0
- package/dist/models/JobOutputInfo.js +80 -0
- package/dist/models/JobProfile.d.ts +49 -0
- package/dist/models/JobProfile.js +77 -0
- package/dist/models/JobProgress.d.ts +75 -0
- package/dist/models/JobProgress.js +67 -0
- package/dist/models/JobResponse.d.ts +134 -0
- package/dist/models/JobResponse.js +101 -0
- package/dist/models/JobSourceInfo.d.ts +62 -0
- package/dist/models/JobSourceInfo.js +60 -0
- package/dist/models/JobSourceType.d.ts +24 -0
- package/dist/models/JobSourceType.js +52 -0
- package/dist/models/JobStatus.d.ts +31 -0
- package/dist/models/JobStatus.js +59 -0
- package/dist/models/ListJobsResponse.d.ts +45 -0
- package/dist/models/ListJobsResponse.js +57 -0
- package/dist/models/OutputContainer.d.ts +27 -0
- package/dist/models/OutputContainer.js +55 -0
- package/dist/models/ReadyResponse.d.ts +38 -0
- package/dist/models/ReadyResponse.js +52 -0
- package/dist/models/UploadJobSource.d.ts +39 -0
- package/dist/models/UploadJobSource.js +55 -0
- package/dist/models/UploadPartResponse.d.ts +38 -0
- package/dist/models/UploadPartResponse.js +54 -0
- package/dist/models/UploadStatusResponse.d.ts +96 -0
- package/dist/models/UploadStatusResponse.js +88 -0
- package/dist/models/WebhookDeliveryPayload.d.ts +85 -0
- package/dist/models/WebhookDeliveryPayload.js +91 -0
- package/dist/models/WebhookListItem.d.ts +50 -0
- package/dist/models/WebhookListItem.js +62 -0
- package/dist/models/WebhookListResponse.d.ts +33 -0
- package/dist/models/WebhookListResponse.js +51 -0
- package/dist/models/WebhookResponse.d.ts +58 -0
- package/dist/models/WebhookResponse.js +66 -0
- package/dist/models/index.d.ts +25 -0
- package/dist/models/index.js +43 -0
- package/dist/runtime.d.ts +184 -0
- package/dist/runtime.js +364 -0
- package/docs/CompleteUploadResponse.md +40 -0
- package/docs/CreateJobOutputOptions.md +39 -0
- package/docs/CreateJobRequest.md +42 -0
- package/docs/CreateUploadRequest.md +38 -0
- package/docs/CreateUploadResponse.md +40 -0
- package/docs/CreateWebhookRequest.md +36 -0
- package/docs/DownloadsApi.md +78 -0
- package/docs/ErrorBody.md +40 -0
- package/docs/ErrorEnvelope.md +34 -0
- package/docs/HealthApi.md +129 -0
- package/docs/JobOutputInfo.md +50 -0
- package/docs/JobProfile.md +33 -0
- package/docs/JobProgress.md +48 -0
- package/docs/JobResponse.md +62 -0
- package/docs/JobSourceInfo.md +44 -0
- package/docs/JobSourceType.md +33 -0
- package/docs/JobStatus.md +33 -0
- package/docs/JobsApi.md +407 -0
- package/docs/ListJobsResponse.md +38 -0
- package/docs/OutputContainer.md +33 -0
- package/docs/ReadyResponse.md +36 -0
- package/docs/UploadJobSource.md +37 -0
- package/docs/UploadPartResponse.md +36 -0
- package/docs/UploadStatusResponse.md +50 -0
- package/docs/UploadsApi.md +415 -0
- package/docs/WebhookDeliveryPayload.md +45 -0
- package/docs/WebhookEventsApi.md +91 -0
- package/docs/WebhookListItem.md +40 -0
- package/docs/WebhookListResponse.md +34 -0
- package/docs/WebhookResponse.md +42 -0
- package/docs/WebhooksApi.md +235 -0
- package/package.json +24 -0
- package/src/apis/DownloadsApi.ts +114 -0
- package/src/apis/HealthApi.ts +160 -0
- package/src/apis/JobsApi.ts +491 -0
- package/src/apis/UploadsApi.ts +522 -0
- package/src/apis/WebhooksApi.ts +298 -0
- package/src/apis/index.ts +7 -0
- package/src/helpers/index.ts +3 -0
- package/src/helpers/jobs.ts +112 -0
- package/src/helpers/uploads.ts +243 -0
- package/src/helpers/webhooks.ts +134 -0
- package/src/index.ts +7 -0
- package/src/models/CompleteUploadResponse.ts +102 -0
- package/src/models/CreateJobOutputOptions.ts +101 -0
- package/src/models/CreateJobRequest.ts +123 -0
- package/src/models/CreateUploadRequest.ts +84 -0
- package/src/models/CreateUploadResponse.ts +95 -0
- package/src/models/CreateWebhookRequest.ts +76 -0
- package/src/models/ErrorBody.ts +116 -0
- package/src/models/ErrorEnvelope.ts +74 -0
- package/src/models/JobOutputInfo.ts +149 -0
- package/src/models/JobProfile.ts +76 -0
- package/src/models/JobProgress.ts +133 -0
- package/src/models/JobResponse.ts +236 -0
- package/src/models/JobSourceInfo.ts +106 -0
- package/src/models/JobSourceType.ts +51 -0
- package/src/models/JobStatus.ts +58 -0
- package/src/models/ListJobsResponse.ts +91 -0
- package/src/models/OutputContainer.ts +54 -0
- package/src/models/ReadyResponse.ts +74 -0
- package/src/models/UploadJobSource.ts +85 -0
- package/src/models/UploadPartResponse.ts +75 -0
- package/src/models/UploadStatusResponse.ts +153 -0
- package/src/models/WebhookDeliveryPayload.ts +134 -0
- package/src/models/WebhookListItem.ts +93 -0
- package/src/models/WebhookListResponse.ts +74 -0
- package/src/models/WebhookResponse.ts +104 -0
- package/src/models/index.ts +27 -0
- package/src/runtime.ts +450 -0
- package/tsconfig.esm.json +7 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
* SOPHON Encoding API
|
|
5
|
+
* REST API for submitting, monitoring, and retrieving SOPHON encoding jobs. Authentication is via Bearer API key or session cookie. All POST endpoints require an Idempotency-Key header. List endpoints use opaque cursor-based pagination.
|
|
6
|
+
*
|
|
7
|
+
* The version of the OpenAPI document: 1.0.0
|
|
8
|
+
*
|
|
9
|
+
*
|
|
10
|
+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
11
|
+
* https://openapi-generator.tech
|
|
12
|
+
* Do not edit the class manually.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
import * as runtime from '../runtime';
|
|
17
|
+
import type {
|
|
18
|
+
CreateWebhookRequest,
|
|
19
|
+
ErrorEnvelope,
|
|
20
|
+
WebhookListResponse,
|
|
21
|
+
WebhookResponse,
|
|
22
|
+
} from '../models/index';
|
|
23
|
+
import {
|
|
24
|
+
CreateWebhookRequestFromJSON,
|
|
25
|
+
CreateWebhookRequestToJSON,
|
|
26
|
+
ErrorEnvelopeFromJSON,
|
|
27
|
+
ErrorEnvelopeToJSON,
|
|
28
|
+
WebhookListResponseFromJSON,
|
|
29
|
+
WebhookListResponseToJSON,
|
|
30
|
+
WebhookResponseFromJSON,
|
|
31
|
+
WebhookResponseToJSON,
|
|
32
|
+
} from '../models/index';
|
|
33
|
+
|
|
34
|
+
export interface CreateWebhookOperationRequest {
|
|
35
|
+
idempotencyKey: string;
|
|
36
|
+
createWebhookRequest: CreateWebhookRequest;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DeleteWebhookRequest {
|
|
40
|
+
id: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* WebhooksApi - interface
|
|
45
|
+
*
|
|
46
|
+
* @export
|
|
47
|
+
* @interface WebhooksApiInterface
|
|
48
|
+
*/
|
|
49
|
+
export interface WebhooksApiInterface {
|
|
50
|
+
/**
|
|
51
|
+
* Creates request options for createWebhook without sending the request
|
|
52
|
+
* @param {string} idempotencyKey Client-generated UUID or string for exactly-once semantics. Required on all POST endpoints. Replaying the same key with the same request body returns the original response without side effects.
|
|
53
|
+
* @param {CreateWebhookRequest} createWebhookRequest
|
|
54
|
+
* @throws {RequiredError}
|
|
55
|
+
* @memberof WebhooksApiInterface
|
|
56
|
+
*/
|
|
57
|
+
createWebhookRequestOpts(requestParameters: CreateWebhookOperationRequest): Promise<runtime.RequestOpts>;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Registers an HTTPS endpoint for terminal job events and returns the HMAC signing secret once at creation time.
|
|
61
|
+
* @summary Register a webhook endpoint
|
|
62
|
+
* @param {string} idempotencyKey Client-generated UUID or string for exactly-once semantics. Required on all POST endpoints. Replaying the same key with the same request body returns the original response without side effects.
|
|
63
|
+
* @param {CreateWebhookRequest} createWebhookRequest
|
|
64
|
+
* @param {*} [options] Override http request option.
|
|
65
|
+
* @throws {RequiredError}
|
|
66
|
+
* @memberof WebhooksApiInterface
|
|
67
|
+
*/
|
|
68
|
+
createWebhookRaw(requestParameters: CreateWebhookOperationRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<WebhookResponse>>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Registers an HTTPS endpoint for terminal job events and returns the HMAC signing secret once at creation time.
|
|
72
|
+
* Register a webhook endpoint
|
|
73
|
+
*/
|
|
74
|
+
createWebhook(requestParameters: CreateWebhookOperationRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<WebhookResponse>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Creates request options for deleteWebhook without sending the request
|
|
78
|
+
* @param {string} id
|
|
79
|
+
* @throws {RequiredError}
|
|
80
|
+
* @memberof WebhooksApiInterface
|
|
81
|
+
*/
|
|
82
|
+
deleteWebhookRequestOpts(requestParameters: DeleteWebhookRequest): Promise<runtime.RequestOpts>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Sets the webhook to inactive. It will no longer receive deliveries.
|
|
86
|
+
* @summary Soft-delete a webhook endpoint
|
|
87
|
+
* @param {string} id
|
|
88
|
+
* @param {*} [options] Override http request option.
|
|
89
|
+
* @throws {RequiredError}
|
|
90
|
+
* @memberof WebhooksApiInterface
|
|
91
|
+
*/
|
|
92
|
+
deleteWebhookRaw(requestParameters: DeleteWebhookRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Sets the webhook to inactive. It will no longer receive deliveries.
|
|
96
|
+
* Soft-delete a webhook endpoint
|
|
97
|
+
*/
|
|
98
|
+
deleteWebhook(requestParameters: DeleteWebhookRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Creates request options for listWebhooks without sending the request
|
|
102
|
+
* @throws {RequiredError}
|
|
103
|
+
* @memberof WebhooksApiInterface
|
|
104
|
+
*/
|
|
105
|
+
listWebhooksRequestOpts(): Promise<runtime.RequestOpts>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Lists active webhook endpoints for the authenticated organization.
|
|
109
|
+
* @summary List active webhook endpoints
|
|
110
|
+
* @param {*} [options] Override http request option.
|
|
111
|
+
* @throws {RequiredError}
|
|
112
|
+
* @memberof WebhooksApiInterface
|
|
113
|
+
*/
|
|
114
|
+
listWebhooksRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<WebhookListResponse>>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Lists active webhook endpoints for the authenticated organization.
|
|
118
|
+
* List active webhook endpoints
|
|
119
|
+
*/
|
|
120
|
+
listWebhooks(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<WebhookListResponse>;
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
*
|
|
126
|
+
*/
|
|
127
|
+
export class WebhooksApi extends runtime.BaseAPI implements WebhooksApiInterface {
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates request options for createWebhook without sending the request
|
|
131
|
+
*/
|
|
132
|
+
async createWebhookRequestOpts(requestParameters: CreateWebhookOperationRequest): Promise<runtime.RequestOpts> {
|
|
133
|
+
if (requestParameters['idempotencyKey'] == null) {
|
|
134
|
+
throw new runtime.RequiredError(
|
|
135
|
+
'idempotencyKey',
|
|
136
|
+
'Required parameter "idempotencyKey" was null or undefined when calling createWebhook().'
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (requestParameters['createWebhookRequest'] == null) {
|
|
141
|
+
throw new runtime.RequiredError(
|
|
142
|
+
'createWebhookRequest',
|
|
143
|
+
'Required parameter "createWebhookRequest" was null or undefined when calling createWebhook().'
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const queryParameters: any = {};
|
|
148
|
+
|
|
149
|
+
const headerParameters: runtime.HTTPHeaders = {};
|
|
150
|
+
|
|
151
|
+
headerParameters['Content-Type'] = 'application/json';
|
|
152
|
+
|
|
153
|
+
if (requestParameters['idempotencyKey'] != null) {
|
|
154
|
+
headerParameters['Idempotency-Key'] = String(requestParameters['idempotencyKey']);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (this.configuration && this.configuration.accessToken) {
|
|
158
|
+
const token = this.configuration.accessToken;
|
|
159
|
+
const tokenString = await token("bearerApiKey", []);
|
|
160
|
+
|
|
161
|
+
if (tokenString) {
|
|
162
|
+
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let urlPath = `/v1/webhooks`;
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
path: urlPath,
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: headerParameters,
|
|
172
|
+
query: queryParameters,
|
|
173
|
+
body: CreateWebhookRequestToJSON(requestParameters['createWebhookRequest']),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Registers an HTTPS endpoint for terminal job events and returns the HMAC signing secret once at creation time.
|
|
179
|
+
* Register a webhook endpoint
|
|
180
|
+
*/
|
|
181
|
+
async createWebhookRaw(requestParameters: CreateWebhookOperationRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<WebhookResponse>> {
|
|
182
|
+
const requestOptions = await this.createWebhookRequestOpts(requestParameters);
|
|
183
|
+
const response = await this.request(requestOptions, initOverrides);
|
|
184
|
+
|
|
185
|
+
return new runtime.JSONApiResponse(response, (jsonValue) => WebhookResponseFromJSON(jsonValue));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Registers an HTTPS endpoint for terminal job events and returns the HMAC signing secret once at creation time.
|
|
190
|
+
* Register a webhook endpoint
|
|
191
|
+
*/
|
|
192
|
+
async createWebhook(requestParameters: CreateWebhookOperationRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<WebhookResponse> {
|
|
193
|
+
const response = await this.createWebhookRaw(requestParameters, initOverrides);
|
|
194
|
+
return await response.value();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Creates request options for deleteWebhook without sending the request
|
|
199
|
+
*/
|
|
200
|
+
async deleteWebhookRequestOpts(requestParameters: DeleteWebhookRequest): Promise<runtime.RequestOpts> {
|
|
201
|
+
if (requestParameters['id'] == null) {
|
|
202
|
+
throw new runtime.RequiredError(
|
|
203
|
+
'id',
|
|
204
|
+
'Required parameter "id" was null or undefined when calling deleteWebhook().'
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const queryParameters: any = {};
|
|
209
|
+
|
|
210
|
+
const headerParameters: runtime.HTTPHeaders = {};
|
|
211
|
+
|
|
212
|
+
if (this.configuration && this.configuration.accessToken) {
|
|
213
|
+
const token = this.configuration.accessToken;
|
|
214
|
+
const tokenString = await token("bearerApiKey", []);
|
|
215
|
+
|
|
216
|
+
if (tokenString) {
|
|
217
|
+
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
let urlPath = `/v1/webhooks/{id}`;
|
|
222
|
+
urlPath = urlPath.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id'])));
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
path: urlPath,
|
|
226
|
+
method: 'DELETE',
|
|
227
|
+
headers: headerParameters,
|
|
228
|
+
query: queryParameters,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Sets the webhook to inactive. It will no longer receive deliveries.
|
|
234
|
+
* Soft-delete a webhook endpoint
|
|
235
|
+
*/
|
|
236
|
+
async deleteWebhookRaw(requestParameters: DeleteWebhookRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
|
|
237
|
+
const requestOptions = await this.deleteWebhookRequestOpts(requestParameters);
|
|
238
|
+
const response = await this.request(requestOptions, initOverrides);
|
|
239
|
+
|
|
240
|
+
return new runtime.VoidApiResponse(response);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Sets the webhook to inactive. It will no longer receive deliveries.
|
|
245
|
+
* Soft-delete a webhook endpoint
|
|
246
|
+
*/
|
|
247
|
+
async deleteWebhook(requestParameters: DeleteWebhookRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
|
|
248
|
+
await this.deleteWebhookRaw(requestParameters, initOverrides);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Creates request options for listWebhooks without sending the request
|
|
253
|
+
*/
|
|
254
|
+
async listWebhooksRequestOpts(): Promise<runtime.RequestOpts> {
|
|
255
|
+
const queryParameters: any = {};
|
|
256
|
+
|
|
257
|
+
const headerParameters: runtime.HTTPHeaders = {};
|
|
258
|
+
|
|
259
|
+
if (this.configuration && this.configuration.accessToken) {
|
|
260
|
+
const token = this.configuration.accessToken;
|
|
261
|
+
const tokenString = await token("bearerApiKey", []);
|
|
262
|
+
|
|
263
|
+
if (tokenString) {
|
|
264
|
+
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let urlPath = `/v1/webhooks`;
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
path: urlPath,
|
|
272
|
+
method: 'GET',
|
|
273
|
+
headers: headerParameters,
|
|
274
|
+
query: queryParameters,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Lists active webhook endpoints for the authenticated organization.
|
|
280
|
+
* List active webhook endpoints
|
|
281
|
+
*/
|
|
282
|
+
async listWebhooksRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<WebhookListResponse>> {
|
|
283
|
+
const requestOptions = await this.listWebhooksRequestOpts();
|
|
284
|
+
const response = await this.request(requestOptions, initOverrides);
|
|
285
|
+
|
|
286
|
+
return new runtime.JSONApiResponse(response, (jsonValue) => WebhookListResponseFromJSON(jsonValue));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Lists active webhook endpoints for the authenticated organization.
|
|
291
|
+
* List active webhook endpoints
|
|
292
|
+
*/
|
|
293
|
+
async listWebhooks(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<WebhookListResponse> {
|
|
294
|
+
const response = await this.listWebhooksRaw(initOverrides);
|
|
295
|
+
return await response.value();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Polling helper that resolves when a job hits a terminal state.
|
|
2
|
+
|
|
3
|
+
export type JobTerminalStatus = "completed" | "failed" | "canceled";
|
|
4
|
+
export type JobStatusLike = JobTerminalStatus | "queued" | "probing" | "encoding" | "muxing" | "uploading_output";
|
|
5
|
+
|
|
6
|
+
export interface JobLike {
|
|
7
|
+
id: string;
|
|
8
|
+
status: JobStatusLike;
|
|
9
|
+
error?: string | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface JobsApiLike {
|
|
13
|
+
getJob(params: { id: string }): Promise<JobLike>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface WaitForJobParams<T extends JobLike = JobLike> {
|
|
17
|
+
api: { getJob: (p: { id: string }) => Promise<T> };
|
|
18
|
+
jobId: string;
|
|
19
|
+
/** Resolve only on these statuses. Default: the three terminal ones. */
|
|
20
|
+
until?: readonly JobStatusLike[];
|
|
21
|
+
/** Initial poll interval (ms). Default 1000. */
|
|
22
|
+
pollMinMs?: number;
|
|
23
|
+
/** Cap on poll interval (ms). Default 15000. */
|
|
24
|
+
pollMaxMs?: number;
|
|
25
|
+
/** Exponential backoff multiplier per poll. Default 1.5. */
|
|
26
|
+
pollBackoff?: number;
|
|
27
|
+
/** Abort and throw after this many ms. Default 3600000 (1h). */
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
/** Called on every poll with the freshly fetched job. */
|
|
30
|
+
onProgress?: (job: T) => void;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class JobTerminalError<T extends JobLike = JobLike> extends Error {
|
|
35
|
+
readonly job: T;
|
|
36
|
+
constructor(job: T) {
|
|
37
|
+
super(job.error ?? `job ${job.id} ended in status ${job.status}`);
|
|
38
|
+
this.name = "JobTerminalError";
|
|
39
|
+
this.job = job;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class JobTimeoutError extends Error {
|
|
44
|
+
readonly jobId: string;
|
|
45
|
+
constructor(jobId: string, waitedMs: number) {
|
|
46
|
+
super(`job ${jobId} did not finish within ${waitedMs}ms`);
|
|
47
|
+
this.name = "JobTimeoutError";
|
|
48
|
+
this.jobId = jobId;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const DEFAULT_TERMINAL: readonly JobTerminalStatus[] = ["completed", "failed", "canceled"];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Polls `getJob` until the job hits a terminal status (or the requested
|
|
56
|
+
* `until` list), then returns the final job. Throws `JobTerminalError` on
|
|
57
|
+
* `failed` / `canceled` unless those are explicitly requested in `until`.
|
|
58
|
+
* Throws `JobTimeoutError` if the timeout elapses.
|
|
59
|
+
*/
|
|
60
|
+
export async function waitForJob<T extends JobLike = JobLike>(
|
|
61
|
+
params: WaitForJobParams<T>,
|
|
62
|
+
): Promise<T> {
|
|
63
|
+
const {
|
|
64
|
+
api,
|
|
65
|
+
jobId,
|
|
66
|
+
until = DEFAULT_TERMINAL,
|
|
67
|
+
pollMinMs = 1000,
|
|
68
|
+
pollMaxMs = 15000,
|
|
69
|
+
pollBackoff = 1.5,
|
|
70
|
+
timeoutMs = 60 * 60 * 1000,
|
|
71
|
+
onProgress,
|
|
72
|
+
signal,
|
|
73
|
+
} = params;
|
|
74
|
+
|
|
75
|
+
const start = Date.now();
|
|
76
|
+
let interval = pollMinMs;
|
|
77
|
+
|
|
78
|
+
while (true) {
|
|
79
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
80
|
+
if (Date.now() - start > timeoutMs) throw new JobTimeoutError(jobId, Date.now() - start);
|
|
81
|
+
|
|
82
|
+
const job = await api.getJob({ id: jobId });
|
|
83
|
+
onProgress?.(job);
|
|
84
|
+
|
|
85
|
+
if (until.some((s) => s === job.status)) {
|
|
86
|
+
// The caller opted into this status; only synthesize a JobTerminalError
|
|
87
|
+
// when they are waiting for the default-terminal set and we landed on a
|
|
88
|
+
// failed/canceled status.
|
|
89
|
+
if (until === DEFAULT_TERMINAL && (job.status === "failed" || job.status === "canceled")) {
|
|
90
|
+
throw new JobTerminalError(job);
|
|
91
|
+
}
|
|
92
|
+
return job;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await sleep(interval, signal);
|
|
96
|
+
interval = Math.min(Math.ceil(interval * pollBackoff), pollMaxMs);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const t = setTimeout(() => {
|
|
103
|
+
signal?.removeEventListener("abort", onAbort);
|
|
104
|
+
resolve();
|
|
105
|
+
}, ms);
|
|
106
|
+
const onAbort = () => {
|
|
107
|
+
clearTimeout(t);
|
|
108
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
109
|
+
};
|
|
110
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
111
|
+
});
|
|
112
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// Upload orchestration on top of the generated UploadsApi.
|
|
2
|
+
//
|
|
3
|
+
// The generated SDK exposes createUpload / uploadPart / completeUpload as
|
|
4
|
+
// separate calls; this wrapper handles chunk slicing, bounded concurrency,
|
|
5
|
+
// per-part retry, resume against existing sessions, and progress reporting.
|
|
6
|
+
|
|
7
|
+
export interface UploadsApiLike {
|
|
8
|
+
createUpload(params: {
|
|
9
|
+
createUploadRequest: { file_name: string; file_size: number; mime_type: string };
|
|
10
|
+
idempotencyKey: string;
|
|
11
|
+
}): Promise<{ id: string; chunk_size: number; total_chunks: number; expires_at: string }>;
|
|
12
|
+
|
|
13
|
+
uploadPart(params: {
|
|
14
|
+
id: string;
|
|
15
|
+
partNumber: number;
|
|
16
|
+
body: Blob;
|
|
17
|
+
}): Promise<{ part_number: number; received: boolean }>;
|
|
18
|
+
|
|
19
|
+
completeUpload(params: {
|
|
20
|
+
id: string;
|
|
21
|
+
idempotencyKey: string;
|
|
22
|
+
}): Promise<{ id: string; status: string; sha256: string; bytes: number }>;
|
|
23
|
+
|
|
24
|
+
getUpload(params: { id: string }): Promise<{
|
|
25
|
+
id: string;
|
|
26
|
+
status: string;
|
|
27
|
+
total_chunks: number;
|
|
28
|
+
received_chunks: number[];
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface UploadProgress {
|
|
33
|
+
bytesUploaded: number;
|
|
34
|
+
bytesTotal: number;
|
|
35
|
+
partsDone: number;
|
|
36
|
+
partsTotal: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface UploadFileParams {
|
|
40
|
+
api: UploadsApiLike;
|
|
41
|
+
source: Blob;
|
|
42
|
+
fileName: string;
|
|
43
|
+
mimeType: string;
|
|
44
|
+
/** Resume a prior session instead of creating a new one. */
|
|
45
|
+
uploadId?: string;
|
|
46
|
+
/** Parallel in-flight chunks. Default 4. */
|
|
47
|
+
concurrency?: number;
|
|
48
|
+
/** Retries per chunk before aborting. Default 3. */
|
|
49
|
+
retries?: number;
|
|
50
|
+
/** Base backoff in ms; doubles each attempt. Default 500. */
|
|
51
|
+
retryBaseMs?: number;
|
|
52
|
+
/** Idempotency key reused for createUpload + completeUpload. Auto-generated if omitted. */
|
|
53
|
+
idempotencyKey?: string;
|
|
54
|
+
onProgress?: (p: UploadProgress) => void;
|
|
55
|
+
/** Abort the whole upload. Chunks in flight will still settle. */
|
|
56
|
+
signal?: AbortSignal;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface UploadFileResult {
|
|
60
|
+
uploadId: string;
|
|
61
|
+
sha256: string;
|
|
62
|
+
bytes: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function uploadFile(params: UploadFileParams): Promise<UploadFileResult> {
|
|
66
|
+
const {
|
|
67
|
+
api,
|
|
68
|
+
source,
|
|
69
|
+
fileName,
|
|
70
|
+
mimeType,
|
|
71
|
+
uploadId: resumeId,
|
|
72
|
+
concurrency = 4,
|
|
73
|
+
retries = 3,
|
|
74
|
+
retryBaseMs = 500,
|
|
75
|
+
idempotencyKey = randomIdempotencyKey(),
|
|
76
|
+
onProgress,
|
|
77
|
+
signal,
|
|
78
|
+
} = params;
|
|
79
|
+
|
|
80
|
+
if (concurrency < 1) throw new RangeError("concurrency must be >= 1");
|
|
81
|
+
if (retries < 0) throw new RangeError("retries must be >= 0");
|
|
82
|
+
|
|
83
|
+
let uploadId: string;
|
|
84
|
+
let chunkSize: number;
|
|
85
|
+
let totalChunks: number;
|
|
86
|
+
let alreadyReceived = new Set<number>();
|
|
87
|
+
|
|
88
|
+
if (resumeId) {
|
|
89
|
+
const status = await api.getUpload({ id: resumeId });
|
|
90
|
+
uploadId = status.id;
|
|
91
|
+
totalChunks = status.total_chunks;
|
|
92
|
+
alreadyReceived = new Set(status.received_chunks);
|
|
93
|
+
// Derive chunk size from file size / totalChunks. Last chunk may be smaller;
|
|
94
|
+
// we only need the head size to slice, so use ceil.
|
|
95
|
+
chunkSize = Math.ceil(source.size / totalChunks);
|
|
96
|
+
} else {
|
|
97
|
+
const session = await api.createUpload({
|
|
98
|
+
createUploadRequest: {
|
|
99
|
+
file_name: fileName,
|
|
100
|
+
file_size: source.size,
|
|
101
|
+
mime_type: mimeType,
|
|
102
|
+
},
|
|
103
|
+
idempotencyKey,
|
|
104
|
+
});
|
|
105
|
+
uploadId = session.id;
|
|
106
|
+
chunkSize = session.chunk_size;
|
|
107
|
+
totalChunks = session.total_chunks;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const progress: UploadProgress = {
|
|
111
|
+
bytesUploaded: 0,
|
|
112
|
+
bytesTotal: source.size,
|
|
113
|
+
partsDone: 0,
|
|
114
|
+
partsTotal: totalChunks,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Seed progress from any resumed parts so callers see accurate counts.
|
|
118
|
+
for (const part of alreadyReceived) {
|
|
119
|
+
progress.partsDone += 1;
|
|
120
|
+
progress.bytesUploaded += partBytes(source.size, chunkSize, totalChunks, part);
|
|
121
|
+
}
|
|
122
|
+
onProgress?.({ ...progress });
|
|
123
|
+
|
|
124
|
+
const pending: number[] = [];
|
|
125
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
126
|
+
if (!alreadyReceived.has(i)) pending.push(i);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let nextIdx = 0;
|
|
130
|
+
const workers: Promise<void>[] = [];
|
|
131
|
+
|
|
132
|
+
for (let w = 0; w < Math.min(concurrency, pending.length); w++) {
|
|
133
|
+
workers.push(
|
|
134
|
+
(async () => {
|
|
135
|
+
while (true) {
|
|
136
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
137
|
+
const idx = nextIdx++;
|
|
138
|
+
if (idx >= pending.length) return;
|
|
139
|
+
|
|
140
|
+
const partNumber = pending[idx]!;
|
|
141
|
+
const start = partNumber * chunkSize;
|
|
142
|
+
const end = Math.min(start + chunkSize, source.size);
|
|
143
|
+
const chunk = source.slice(start, end, "application/octet-stream");
|
|
144
|
+
|
|
145
|
+
await withRetry(
|
|
146
|
+
() => api.uploadPart({ id: uploadId, partNumber, body: chunk }),
|
|
147
|
+
retries,
|
|
148
|
+
retryBaseMs,
|
|
149
|
+
signal,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
progress.partsDone += 1;
|
|
153
|
+
progress.bytesUploaded += chunk.size;
|
|
154
|
+
onProgress?.({ ...progress });
|
|
155
|
+
}
|
|
156
|
+
})(),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await Promise.all(workers);
|
|
161
|
+
|
|
162
|
+
const done = await api.completeUpload({ id: uploadId, idempotencyKey });
|
|
163
|
+
|
|
164
|
+
return { uploadId: done.id, sha256: done.sha256, bytes: done.bytes };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function partBytes(total: number, chunkSize: number, totalChunks: number, part: number): number {
|
|
168
|
+
if (part < totalChunks - 1) return chunkSize;
|
|
169
|
+
return total - chunkSize * (totalChunks - 1);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function withRetry<T>(
|
|
173
|
+
fn: () => Promise<T>,
|
|
174
|
+
retries: number,
|
|
175
|
+
baseMs: number,
|
|
176
|
+
signal: AbortSignal | undefined,
|
|
177
|
+
): Promise<T> {
|
|
178
|
+
let attempt = 0;
|
|
179
|
+
// One initial try + `retries` follow-ups.
|
|
180
|
+
while (true) {
|
|
181
|
+
try {
|
|
182
|
+
return await fn();
|
|
183
|
+
} catch (err) {
|
|
184
|
+
if (signal?.aborted) throw err;
|
|
185
|
+
if (attempt >= retries || !isRetryable(err)) throw err;
|
|
186
|
+
const delay = baseMs * 2 ** attempt + Math.floor(Math.random() * baseMs);
|
|
187
|
+
await sleep(delay, signal);
|
|
188
|
+
attempt += 1;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function isRetryable(err: unknown): boolean {
|
|
194
|
+
if (err instanceof TypeError) return true; // network-level fetch errors
|
|
195
|
+
const maybeResponse = (err as { response?: { status?: number } }).response;
|
|
196
|
+
const status = maybeResponse?.status;
|
|
197
|
+
if (typeof status !== "number") return false;
|
|
198
|
+
return status === 408 || status === 429 || (status >= 500 && status < 600);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
const t = setTimeout(() => {
|
|
204
|
+
signal?.removeEventListener("abort", onAbort);
|
|
205
|
+
resolve();
|
|
206
|
+
}, ms);
|
|
207
|
+
const onAbort = () => {
|
|
208
|
+
clearTimeout(t);
|
|
209
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
210
|
+
};
|
|
211
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function randomIdempotencyKey(): string {
|
|
216
|
+
// Single capture of the global `crypto` object so the TS narrowing from
|
|
217
|
+
// one `in` check doesn't bleed into the next branch.
|
|
218
|
+
const c =
|
|
219
|
+
typeof crypto !== "undefined"
|
|
220
|
+
? (crypto as unknown as {
|
|
221
|
+
randomUUID?: () => string;
|
|
222
|
+
getRandomValues?: (arr: Uint8Array) => Uint8Array;
|
|
223
|
+
})
|
|
224
|
+
: undefined;
|
|
225
|
+
|
|
226
|
+
if (c?.randomUUID) return c.randomUUID();
|
|
227
|
+
|
|
228
|
+
// Fallback for very old runtimes without crypto.randomUUID. Web Crypto's
|
|
229
|
+
// getRandomValues has been in Node since 15 and all evergreen browsers, so
|
|
230
|
+
// this almost never runs — but we avoid Math.random so idempotency keys
|
|
231
|
+
// stay uncorrelated across callers even on ancient targets.
|
|
232
|
+
if (c?.getRandomValues) {
|
|
233
|
+
const bytes = new Uint8Array(16);
|
|
234
|
+
c.getRandomValues(bytes);
|
|
235
|
+
let hex = "";
|
|
236
|
+
for (const b of bytes) hex += b.toString(16).padStart(2, "0");
|
|
237
|
+
return `idem_${hex}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
throw new Error(
|
|
241
|
+
"crypto API unavailable; pass an explicit idempotencyKey to uploadFile",
|
|
242
|
+
);
|
|
243
|
+
}
|