@viewrium/sdk 0.1.0 → 2.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/LICENSE +202 -0
- package/README.md +194 -87
- package/dist/index.cjs +295 -409
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3505 -320
- package/dist/index.d.ts +3505 -320
- package/dist/index.js +257 -400
- package/dist/index.js.map +1 -1
- package/package.json +33 -23
package/dist/index.js
CHANGED
|
@@ -1,438 +1,295 @@
|
|
|
1
1
|
// src/errors.ts
|
|
2
2
|
var ViewriumError = class extends Error {
|
|
3
|
+
/** HTTP status, or `null` for transport/connection failures. */
|
|
4
|
+
status;
|
|
5
|
+
/** Machine-readable code from the error envelope. */
|
|
6
|
+
code;
|
|
7
|
+
/** Optional structured details from the error envelope. */
|
|
8
|
+
details;
|
|
3
9
|
constructor(message, options = {}) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.name =
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
10
|
+
super(message, options.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
11
|
+
this.name = new.target.name;
|
|
12
|
+
this.status = options.status ?? null;
|
|
13
|
+
this.code = options.code ?? "error";
|
|
14
|
+
this.details = options.details;
|
|
8
15
|
}
|
|
9
16
|
};
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
var BadRequestError = class extends ViewriumError {
|
|
18
|
+
};
|
|
19
|
+
var AuthenticationError = class extends ViewriumError {
|
|
20
|
+
};
|
|
21
|
+
var PaymentRequiredError = class extends ViewriumError {
|
|
22
|
+
};
|
|
23
|
+
var PermissionError = class extends ViewriumError {
|
|
15
24
|
};
|
|
16
25
|
var NotFoundError = class extends ViewriumError {
|
|
17
|
-
constructor(message, options = {}) {
|
|
18
|
-
super(message, options);
|
|
19
|
-
this.name = "NotFoundError";
|
|
20
|
-
}
|
|
21
26
|
};
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this.name = "ValidationError";
|
|
26
|
-
}
|
|
27
|
+
var ConflictError = class extends ViewriumError {
|
|
28
|
+
};
|
|
29
|
+
var UnprocessableEntityError = class extends ViewriumError {
|
|
27
30
|
};
|
|
28
31
|
var RateLimitError = class extends ViewriumError {
|
|
29
|
-
constructor(message, options = {}) {
|
|
30
|
-
super(message, options);
|
|
31
|
-
this.name = "RateLimitError";
|
|
32
|
-
this.retryAfter = options.retryAfter;
|
|
33
|
-
}
|
|
34
32
|
};
|
|
35
|
-
var
|
|
36
|
-
constructor(message, options = {}) {
|
|
37
|
-
super(message, options);
|
|
38
|
-
this.name = "APIError";
|
|
39
|
-
}
|
|
33
|
+
var ServerError = class extends ViewriumError {
|
|
40
34
|
};
|
|
41
|
-
|
|
42
|
-
// src/resources/models.ts
|
|
43
|
-
var BASE = "/v1/models";
|
|
44
|
-
var ModelsResource = class {
|
|
45
|
-
constructor(client) {
|
|
46
|
-
this.client = client;
|
|
47
|
-
}
|
|
48
|
-
async create(params) {
|
|
49
|
-
const hasImages = Array.isArray(params.images) && params.images.length > 0;
|
|
50
|
-
const hasSource = typeof params.sourceUrl === "string" && params.sourceUrl.length > 0;
|
|
51
|
-
if (hasImages === hasSource) {
|
|
52
|
-
throw new Error(
|
|
53
|
-
"Provide exactly one of `images` (URL list) or `sourceUrl` to models.create()."
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
const body = stripUndefined({
|
|
57
|
-
custom_id: params.customId,
|
|
58
|
-
title: params.title,
|
|
59
|
-
description: params.description,
|
|
60
|
-
image_urls: params.images,
|
|
61
|
-
source_url: params.sourceUrl,
|
|
62
|
-
height: params.height,
|
|
63
|
-
size_unit: params.sizeUnit,
|
|
64
|
-
tags: params.tags,
|
|
65
|
-
price: params.price,
|
|
66
|
-
currency: params.currency,
|
|
67
|
-
metadata: params.metadata,
|
|
68
|
-
display_enabled: params.displayEnabled
|
|
69
|
-
});
|
|
70
|
-
return this.client.request({ method: "POST", path: BASE, json: body });
|
|
71
|
-
}
|
|
72
|
-
async createFromImages(images, params = {}) {
|
|
73
|
-
if (!Array.isArray(images) || images.length < 1) {
|
|
74
|
-
throw new Error("At least 1 image is required.");
|
|
75
|
-
}
|
|
76
|
-
const form = new FormData();
|
|
77
|
-
for (const image of images) {
|
|
78
|
-
const { blob, filename } = await toBlob(image, "image");
|
|
79
|
-
form.append("images", blob, filename);
|
|
80
|
-
}
|
|
81
|
-
appendMultipartCommon(form, params);
|
|
82
|
-
return this.client.request({
|
|
83
|
-
method: "POST",
|
|
84
|
-
path: `${BASE}/from-images`,
|
|
85
|
-
body: form
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
async createFromVideo(video, params = {}) {
|
|
89
|
-
const { blob, filename } = await toBlob(video, "video");
|
|
90
|
-
const form = new FormData();
|
|
91
|
-
form.append("video", blob, filename);
|
|
92
|
-
appendMultipartCommon(form, params);
|
|
93
|
-
return this.client.request({
|
|
94
|
-
method: "POST",
|
|
95
|
-
path: `${BASE}/from-video`,
|
|
96
|
-
body: form
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
async retrieve(modelId) {
|
|
100
|
-
return this.client.request({ method: "GET", path: `${BASE}/${encodeURIComponent(modelId)}` });
|
|
101
|
-
}
|
|
102
|
-
async list(params = {}) {
|
|
103
|
-
const query = {};
|
|
104
|
-
if (params.tag !== void 0) query.tag = params.tag;
|
|
105
|
-
if (params.tags !== void 0) {
|
|
106
|
-
query.tags = Array.isArray(params.tags) ? params.tags.join(",") : params.tags;
|
|
107
|
-
}
|
|
108
|
-
if (params.customId !== void 0) query.custom_id = params.customId;
|
|
109
|
-
if (params.status !== void 0) query.status = params.status;
|
|
110
|
-
if (params.limit !== void 0) query.limit = params.limit;
|
|
111
|
-
if (params.offset !== void 0) query.offset = params.offset;
|
|
112
|
-
return this.client.request({
|
|
113
|
-
method: "GET",
|
|
114
|
-
path: BASE,
|
|
115
|
-
query
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
async modify(modelId, params) {
|
|
119
|
-
const body = stripUndefined({
|
|
120
|
-
custom_id: params.customId,
|
|
121
|
-
title: params.title,
|
|
122
|
-
description: params.description,
|
|
123
|
-
price: params.price,
|
|
124
|
-
currency: params.currency,
|
|
125
|
-
height: params.height,
|
|
126
|
-
size_unit: params.sizeUnit,
|
|
127
|
-
tags: params.tags,
|
|
128
|
-
metadata: params.metadata,
|
|
129
|
-
display_enabled: params.displayEnabled
|
|
130
|
-
});
|
|
131
|
-
return this.client.request({
|
|
132
|
-
method: "PATCH",
|
|
133
|
-
path: `${BASE}/${encodeURIComponent(modelId)}`,
|
|
134
|
-
json: body
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
async delete(modelId) {
|
|
138
|
-
return this.client.request({
|
|
139
|
-
method: "DELETE",
|
|
140
|
-
path: `${BASE}/${encodeURIComponent(modelId)}`
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
async listEvents(modelId, params = {}) {
|
|
144
|
-
const query = {};
|
|
145
|
-
if (params.limit !== void 0) query.limit = params.limit;
|
|
146
|
-
if (params.offset !== void 0) query.offset = params.offset;
|
|
147
|
-
return this.client.request({
|
|
148
|
-
method: "GET",
|
|
149
|
-
path: `${BASE}/${encodeURIComponent(modelId)}/events`,
|
|
150
|
-
query
|
|
151
|
-
});
|
|
152
|
-
}
|
|
35
|
+
var ConnectionError = class extends ViewriumError {
|
|
153
36
|
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (params.customId !== void 0) form.append("custom_id", params.customId);
|
|
164
|
-
if (params.description !== void 0) form.append("description", params.description);
|
|
165
|
-
if (params.height !== void 0) form.append("height", String(params.height));
|
|
166
|
-
if (params.sizeUnit !== void 0) form.append("size_unit", params.sizeUnit);
|
|
167
|
-
if (params.tags !== void 0) form.append("tags", JSON.stringify(params.tags));
|
|
168
|
-
if (params.displayEnabled !== void 0) {
|
|
169
|
-
form.append("display_enabled", params.displayEnabled ? "true" : "false");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
async function toBlob(input, fallbackKind) {
|
|
173
|
-
if (typeof input === "string") {
|
|
174
|
-
const { readFile } = await import('fs/promises');
|
|
175
|
-
const { basename } = await import('path');
|
|
176
|
-
const data = await readFile(input);
|
|
177
|
-
const blob = new Blob([data]);
|
|
178
|
-
return { blob, filename: basename(input) };
|
|
179
|
-
}
|
|
180
|
-
if (input instanceof Blob) {
|
|
181
|
-
const filename = input.name && typeof input.name === "string" ? input.name : defaultFilename(fallbackKind);
|
|
182
|
-
return { blob: input, filename };
|
|
183
|
-
}
|
|
184
|
-
if (input && typeof input === "object" && "data" in input) {
|
|
185
|
-
const { data, filename, contentType } = input;
|
|
186
|
-
const part = data instanceof Blob ? data : data instanceof ArrayBuffer ? data : data;
|
|
187
|
-
const blob = new Blob([part], contentType ? { type: contentType } : void 0);
|
|
188
|
-
return { blob, filename: filename ?? defaultFilename(fallbackKind) };
|
|
189
|
-
}
|
|
190
|
-
throw new Error("Unsupported file input: expected string path, Blob, File, or {data, filename}.");
|
|
191
|
-
}
|
|
192
|
-
function defaultFilename(kind) {
|
|
193
|
-
return kind === "image" ? "image.bin" : "video.bin";
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// src/resources/apiKeys.ts
|
|
197
|
-
var BASE2 = "/v1/api_keys";
|
|
198
|
-
var ApiKeysResource = class {
|
|
199
|
-
constructor(client) {
|
|
200
|
-
this.client = client;
|
|
201
|
-
}
|
|
202
|
-
async create(params = {}) {
|
|
203
|
-
const body = {};
|
|
204
|
-
if (params.name !== void 0) body.name = params.name;
|
|
205
|
-
if (params.keyType !== void 0) body.key_type = params.keyType;
|
|
206
|
-
return this.client.request({
|
|
207
|
-
method: "POST",
|
|
208
|
-
path: BASE2,
|
|
209
|
-
json: body
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
async list() {
|
|
213
|
-
return this.client.request({ method: "GET", path: BASE2 });
|
|
214
|
-
}
|
|
215
|
-
async delete(keyId) {
|
|
216
|
-
return this.client.request({
|
|
217
|
-
method: "DELETE",
|
|
218
|
-
path: `${BASE2}/${encodeURIComponent(keyId)}`
|
|
219
|
-
});
|
|
220
|
-
}
|
|
37
|
+
var BY_STATUS = {
|
|
38
|
+
400: BadRequestError,
|
|
39
|
+
401: AuthenticationError,
|
|
40
|
+
402: PaymentRequiredError,
|
|
41
|
+
403: PermissionError,
|
|
42
|
+
404: NotFoundError,
|
|
43
|
+
409: ConflictError,
|
|
44
|
+
422: UnprocessableEntityError,
|
|
45
|
+
429: RateLimitError
|
|
221
46
|
};
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.client = client;
|
|
47
|
+
function createApiError(status, payload) {
|
|
48
|
+
const options = { status, code: payload.code, details: payload.details };
|
|
49
|
+
const Specific = BY_STATUS[status];
|
|
50
|
+
if (Specific) {
|
|
51
|
+
return new Specific(payload.message, options);
|
|
228
52
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (params.since !== void 0) query.since = params.since;
|
|
232
|
-
if (params.until !== void 0) query.until = params.until;
|
|
233
|
-
return this.client.request({
|
|
234
|
-
method: "GET",
|
|
235
|
-
path: BASE3,
|
|
236
|
-
query
|
|
237
|
-
});
|
|
53
|
+
if (status >= 500) {
|
|
54
|
+
return new ServerError(payload.message, options);
|
|
238
55
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// src/resources/tags.ts
|
|
242
|
-
var BASE4 = "/v1/tags";
|
|
243
|
-
var TagsResource = class {
|
|
244
|
-
constructor(client) {
|
|
245
|
-
this.client = client;
|
|
246
|
-
}
|
|
247
|
-
async list() {
|
|
248
|
-
return this.client.request({ method: "GET", path: BASE4 });
|
|
249
|
-
}
|
|
250
|
-
};
|
|
56
|
+
return new ViewriumError(payload.message, options);
|
|
57
|
+
}
|
|
251
58
|
|
|
252
|
-
// src/
|
|
253
|
-
var
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
var VERSION = "0.1.0";
|
|
258
|
-
var Viewrium = class {
|
|
259
|
-
constructor(apiKey, options = {}) {
|
|
260
|
-
const envKey = typeof process !== "undefined" ? process.env?.VIEWRIUM_API_KEY : void 0;
|
|
261
|
-
const resolvedKey = options.apiKey ?? apiKey ?? envKey;
|
|
262
|
-
if (!resolvedKey) {
|
|
263
|
-
throw new AuthError(
|
|
264
|
-
"No API key configured. Pass `new Viewrium('sk_live_...')` or set VIEWRIUM_API_KEY."
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
this.apiKey = resolvedKey;
|
|
268
|
-
const envBase = typeof process !== "undefined" ? process.env?.VIEWRIUM_API_BASE : void 0;
|
|
269
|
-
this.apiBase = (options.apiBase ?? envBase ?? DEFAULT_API_BASE).replace(/\/+$/, "");
|
|
270
|
-
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
271
|
-
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
272
|
-
const providedFetch = options.fetch;
|
|
273
|
-
if (providedFetch) {
|
|
274
|
-
this.fetchImpl = providedFetch;
|
|
275
|
-
} else if (typeof globalThis.fetch === "function") {
|
|
276
|
-
this.fetchImpl = globalThis.fetch.bind(globalThis);
|
|
277
|
-
} else {
|
|
278
|
-
throw new Error(
|
|
279
|
-
"No `fetch` implementation available. Use Node 18+ or pass `fetch` in options."
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
this.models = new ModelsResource(this);
|
|
283
|
-
this.apiKeys = new ApiKeysResource(this);
|
|
284
|
-
this.usage = new UsageResource(this);
|
|
285
|
-
this.tags = new TagsResource(this);
|
|
286
|
-
}
|
|
287
|
-
/** Low-level request. Resources delegate here. */
|
|
288
|
-
async request(options) {
|
|
289
|
-
const url = this.buildUrl(options.path, options.query);
|
|
290
|
-
const headers = this.buildHeaders(options);
|
|
291
|
-
const body = this.buildBody(options);
|
|
292
|
-
let attempt = 0;
|
|
293
|
-
let lastResponse;
|
|
294
|
-
while (true) {
|
|
295
|
-
lastResponse = void 0;
|
|
296
|
-
const controller = new AbortController();
|
|
297
|
-
const timeoutMs = options.timeoutMs ?? this.timeoutMs;
|
|
298
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
299
|
-
try {
|
|
300
|
-
lastResponse = await this.fetchImpl(url, {
|
|
301
|
-
method: options.method,
|
|
302
|
-
headers,
|
|
303
|
-
body,
|
|
304
|
-
signal: controller.signal
|
|
305
|
-
});
|
|
306
|
-
} catch (err) {
|
|
307
|
-
clearTimeout(timer);
|
|
308
|
-
if (attempt >= this.maxRetries) throw err;
|
|
309
|
-
await sleep(backoffMs(void 0, attempt));
|
|
310
|
-
attempt += 1;
|
|
311
|
-
continue;
|
|
312
|
-
}
|
|
313
|
-
clearTimeout(timer);
|
|
314
|
-
if (RETRYABLE_STATUSES.has(lastResponse.status) && attempt < this.maxRetries) {
|
|
315
|
-
await sleep(backoffMs(lastResponse, attempt));
|
|
316
|
-
attempt += 1;
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
break;
|
|
320
|
-
}
|
|
321
|
-
if (!lastResponse.ok) {
|
|
322
|
-
await raiseForStatus(lastResponse);
|
|
323
|
-
}
|
|
324
|
-
return await parseResponse(lastResponse);
|
|
325
|
-
}
|
|
326
|
-
buildUrl(path, query) {
|
|
327
|
-
const full = path.startsWith("http://") || path.startsWith("https://") ? path : `${this.apiBase}${path.startsWith("/") ? path : `/${path}`}`;
|
|
328
|
-
if (!query) return full;
|
|
329
|
-
const params = new URLSearchParams();
|
|
59
|
+
// src/index.ts
|
|
60
|
+
var DEFAULT_BASE_URL = "https://api.viewrium.com";
|
|
61
|
+
function buildUrl(baseUrl, path, query) {
|
|
62
|
+
const url = new URL(baseUrl + path);
|
|
63
|
+
if (query) {
|
|
330
64
|
for (const [key, value] of Object.entries(query)) {
|
|
331
65
|
if (value === void 0 || value === null) continue;
|
|
332
66
|
if (Array.isArray(value)) {
|
|
333
|
-
for (const
|
|
334
|
-
if (v !== void 0 && v !== null) params.append(key, String(v));
|
|
335
|
-
}
|
|
67
|
+
for (const item of value) url.searchParams.append(key, String(item));
|
|
336
68
|
} else {
|
|
337
|
-
|
|
69
|
+
url.searchParams.append(key, String(value));
|
|
338
70
|
}
|
|
339
71
|
}
|
|
340
|
-
const qs = params.toString();
|
|
341
|
-
return qs ? `${full}?${qs}` : full;
|
|
342
72
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
73
|
+
return url.toString();
|
|
74
|
+
}
|
|
75
|
+
async function parseError(res) {
|
|
76
|
+
let code = "error";
|
|
77
|
+
let message = res.statusText || `HTTP ${res.status}`;
|
|
78
|
+
let details;
|
|
79
|
+
try {
|
|
80
|
+
const data = await res.json();
|
|
81
|
+
if (data && typeof data === "object" && "error" in data) {
|
|
82
|
+
const envelope = data.error;
|
|
83
|
+
if (envelope && typeof envelope === "object") {
|
|
84
|
+
const e = envelope;
|
|
85
|
+
if (typeof e.code === "string") code = e.code;
|
|
86
|
+
if (typeof e.message === "string") message = e.message;
|
|
87
|
+
details = e.details;
|
|
351
88
|
}
|
|
352
89
|
}
|
|
353
|
-
|
|
354
|
-
headers.set("Content-Type", "application/json");
|
|
355
|
-
}
|
|
356
|
-
return headers;
|
|
357
|
-
}
|
|
358
|
-
buildBody(options) {
|
|
359
|
-
if (options.body !== void 0) return options.body;
|
|
360
|
-
if (options.json !== void 0) return JSON.stringify(options.json);
|
|
361
|
-
return void 0;
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
async function parseResponse(response) {
|
|
365
|
-
if (response.status === 204) return {};
|
|
366
|
-
const text = await response.text();
|
|
367
|
-
if (!text) return {};
|
|
368
|
-
try {
|
|
369
|
-
return JSON.parse(text);
|
|
370
|
-
} catch (e) {
|
|
371
|
-
throw new APIError(`Failed to parse JSON response: ${e.message}`, {
|
|
372
|
-
statusCode: response.status,
|
|
373
|
-
responseBody: text
|
|
374
|
-
});
|
|
90
|
+
} catch {
|
|
375
91
|
}
|
|
92
|
+
return createApiError(res.status, { code, message, details });
|
|
376
93
|
}
|
|
377
|
-
async function
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (
|
|
384
|
-
|
|
385
|
-
|
|
94
|
+
async function send(transport, method, path, options) {
|
|
95
|
+
const headers = {
|
|
96
|
+
accept: "application/json",
|
|
97
|
+
authorization: `Bearer ${transport.apiKey}`
|
|
98
|
+
};
|
|
99
|
+
const init = { method, headers };
|
|
100
|
+
if (options?.body !== void 0) {
|
|
101
|
+
headers["content-type"] = "application/json";
|
|
102
|
+
init.body = JSON.stringify(options.body);
|
|
103
|
+
}
|
|
104
|
+
let res;
|
|
105
|
+
try {
|
|
106
|
+
res = await transport.fetch(buildUrl(transport.baseUrl, path, options?.query), init);
|
|
107
|
+
} catch (cause) {
|
|
108
|
+
throw new ConnectionError("The request to the Viewrium API could not be sent.", { cause });
|
|
386
109
|
}
|
|
387
|
-
if (
|
|
388
|
-
throw
|
|
389
|
-
...opts,
|
|
390
|
-
retryAfter: parseRetryAfter(response)
|
|
391
|
-
});
|
|
110
|
+
if (!res.ok) {
|
|
111
|
+
throw await parseError(res);
|
|
392
112
|
}
|
|
393
|
-
|
|
113
|
+
return res;
|
|
394
114
|
}
|
|
395
|
-
async function
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
return JSON.parse(text);
|
|
400
|
-
} catch {
|
|
401
|
-
return text;
|
|
115
|
+
async function doRequest(transport, method, path, options) {
|
|
116
|
+
const res = await send(transport, method, path, options);
|
|
117
|
+
if (res.status === 204) {
|
|
118
|
+
return void 0;
|
|
402
119
|
}
|
|
120
|
+
const text = await res.text();
|
|
121
|
+
return text ? JSON.parse(text) : void 0;
|
|
403
122
|
}
|
|
404
|
-
function
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (typeof candidate === "string" && candidate) return candidate;
|
|
409
|
-
if (candidate !== void 0) return String(candidate);
|
|
410
|
-
}
|
|
411
|
-
if (typeof body === "string" && body) return body;
|
|
412
|
-
return `HTTP ${response.status}`;
|
|
123
|
+
async function doBlobRequest(transport, method, path, options) {
|
|
124
|
+
const res = await send(transport, method, path, options);
|
|
125
|
+
if (res.status === 202) return await res.json();
|
|
126
|
+
return res.blob();
|
|
413
127
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
128
|
+
var encode = encodeURIComponent;
|
|
129
|
+
function createProducts(request, requestBlob) {
|
|
130
|
+
return {
|
|
131
|
+
/**
|
|
132
|
+
* POST /v1/products - the single generation entrypoint. Supply exactly one source
|
|
133
|
+
* (`image_paths` | `image_urls` | `video_url` | `source_url` | `model_url` |
|
|
134
|
+
* `resume_token`). A fresh request ALWAYS parks (200, `status === "parked"`, nothing
|
|
135
|
+
* written): the plan, the model verdict and the price come back inside `resume_token`,
|
|
136
|
+
* which you POST back to commit (202, `ProductCreated`). A `model_url` commits at once.
|
|
137
|
+
*/
|
|
138
|
+
create: (params) => request("POST", "/v1/products", { body: params }),
|
|
139
|
+
/**
|
|
140
|
+
* GET /v1/products - the catalog: one org (`org_id`, or the caller's only org), or
|
|
141
|
+
* `scope: "all"` for every org an agency member or staff reaches. Filters AND together.
|
|
142
|
+
*/
|
|
143
|
+
list: (params) => request("GET", "/v1/products", { query: params }),
|
|
144
|
+
/** GET /v1/products/{id} - the product with its assets (a `pk_` key gets `PublicProduct`). */
|
|
145
|
+
retrieve: (id) => request("GET", `/v1/products/${encode(id)}`),
|
|
146
|
+
/**
|
|
147
|
+
* PATCH /v1/products/{id} - the customer's fields, the user-set status and the publish
|
|
148
|
+
* toggle. 409 on a `custom_id` another product in the org already holds.
|
|
149
|
+
*/
|
|
150
|
+
update: (id, params) => request("PATCH", `/v1/products/${encode(id)}`, { body: params }),
|
|
151
|
+
/** DELETE /v1/products/{id} */
|
|
152
|
+
delete: (id) => request("DELETE", `/v1/products/${encode(id)}`),
|
|
153
|
+
/** DELETE /v1/products?ids=... - per-id affected/not_found/forbidden buckets. */
|
|
154
|
+
batchDelete: (ids) => request("DELETE", "/v1/products", { query: { ids } }),
|
|
155
|
+
/** POST /v1/products/publish - the bulk publish toggle; one product toggles through `update`. */
|
|
156
|
+
publish: (params) => request("POST", "/v1/products/publish", { body: params }),
|
|
157
|
+
/** GET /v1/products/tags - distinct tags across the same scope the list takes. */
|
|
158
|
+
tags: (params) => request("GET", "/v1/products/tags", { query: params }),
|
|
159
|
+
/** POST /v1/products/{id}/review - the review flush: image and model decisions plus the
|
|
160
|
+
* product's user-set status, validated together and applied in order. */
|
|
161
|
+
review: (id, params) => request("POST", `/v1/products/${encode(id)}/review`, { body: params }),
|
|
162
|
+
/** PATCH /v1/products/{id}/images/{image_id} - one image's decision and overrides. */
|
|
163
|
+
updateImage: (id, imageId, params) => request("PATCH", `/v1/products/${encode(id)}/images/${encode(imageId)}`, {
|
|
164
|
+
body: params
|
|
165
|
+
}),
|
|
166
|
+
/** PATCH /v1/products/{id}/model - the model's review decision. */
|
|
167
|
+
updateModel: (id, params) => request("PATCH", `/v1/products/${encode(id)}/model`, { body: params }),
|
|
168
|
+
/**
|
|
169
|
+
* POST /v1/products/{id}/model/rescale - re-apply real-world scale to the GLB in place.
|
|
170
|
+
* Every supplied axis is applied to the geometry; `unit` covers them (omitted = cm) and is
|
|
171
|
+
* remembered as the product's `display_unit`. The result carries the ACHIEVED dimensions.
|
|
172
|
+
*/
|
|
173
|
+
rescale: (id, params) => request("POST", `/v1/products/${encode(id)}/model/rescale`, { body: params }),
|
|
174
|
+
/**
|
|
175
|
+
* POST /v1/products/{id}/tickets - a single-use URL for the product's 3D file, the ONLY way
|
|
176
|
+
* to its bytes (no response carries a model file URL). It works once, until `expires_at`
|
|
177
|
+
* (60 s for `view`, 30 s for `ar`); a `view` ticket only from its bound origin. With a `pk_`
|
|
178
|
+
* key the product must be published and the ticket is bound to the page's Origin; with an
|
|
179
|
+
* `sk_` key pass `origin` (the page that will load the model, one of your allowed domains).
|
|
180
|
+
*/
|
|
181
|
+
createTicket: (id, params) => request("POST", `/v1/products/${encode(id)}/tickets`, { body: params }),
|
|
182
|
+
/** POST /v1/products/{id}/order - park the missing half (images or a model); commit the
|
|
183
|
+
* returned `resume_token` with `create`. */
|
|
184
|
+
order: (id, params) => request("POST", `/v1/products/${encode(id)}/order`, { body: params }),
|
|
185
|
+
/** GET /v1/products/export - a ZIP of finished images (never the 3D model), resolved as a
|
|
186
|
+
* `Blob`; or `ProductExportQueued` (202) when the images are being finished in the
|
|
187
|
+
* background and a download link is emailed - repeat the request later to stream it. */
|
|
188
|
+
export: (params) => requestBlob("GET", "/v1/products/export", { query: params })
|
|
189
|
+
};
|
|
419
190
|
}
|
|
420
|
-
function
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
191
|
+
function createApiKeys(request) {
|
|
192
|
+
return {
|
|
193
|
+
/** GET /v1/api_keys */
|
|
194
|
+
list: () => request("GET", "/v1/api_keys"),
|
|
195
|
+
/** POST /v1/api_keys - the full key is returned exactly once. */
|
|
196
|
+
create: (params) => request("POST", "/v1/api_keys", { body: params }),
|
|
197
|
+
/** DELETE /v1/api_keys/{id} - soft revoke. */
|
|
198
|
+
revoke: (id) => request("DELETE", `/v1/api_keys/${encode(id)}`)
|
|
199
|
+
};
|
|
428
200
|
}
|
|
429
|
-
function
|
|
430
|
-
return
|
|
201
|
+
function createUsage(request) {
|
|
202
|
+
return {
|
|
203
|
+
/** GET /v1/usage - buckets and totals over the window; `group_by: "product"` adds the
|
|
204
|
+
* window's best-performing products in `by_product`. */
|
|
205
|
+
get: (params) => request("GET", "/v1/usage", { query: params })
|
|
206
|
+
};
|
|
431
207
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
208
|
+
function createWebhooks(request) {
|
|
209
|
+
return {
|
|
210
|
+
/** GET /v1/webhooks */
|
|
211
|
+
list: () => request("GET", "/v1/webhooks"),
|
|
212
|
+
/** POST /v1/webhooks - includes the signing secret. */
|
|
213
|
+
create: (params) => request("POST", "/v1/webhooks", { body: params }),
|
|
214
|
+
/** GET /v1/webhooks/{id} */
|
|
215
|
+
retrieve: (id) => request("GET", `/v1/webhooks/${encode(id)}`),
|
|
216
|
+
/** PATCH /v1/webhooks/{id} */
|
|
217
|
+
update: (id, params) => request("PATCH", `/v1/webhooks/${encode(id)}`, { body: params }),
|
|
218
|
+
/** DELETE /v1/webhooks/{id} */
|
|
219
|
+
delete: (id) => request("DELETE", `/v1/webhooks/${encode(id)}`),
|
|
220
|
+
/** GET /v1/webhooks/{id}/deliveries */
|
|
221
|
+
listDeliveries: (id, params) => request("GET", `/v1/webhooks/${encode(id)}/deliveries`, {
|
|
222
|
+
query: params
|
|
223
|
+
})
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function createProjects(request) {
|
|
227
|
+
return {
|
|
228
|
+
/** GET /v1/projects */
|
|
229
|
+
list: () => request("GET", "/v1/projects"),
|
|
230
|
+
/** GET /v1/projects/{id} */
|
|
231
|
+
retrieve: (id) => request("GET", `/v1/projects/${encode(id)}`)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function createBeacon(request) {
|
|
235
|
+
return {
|
|
236
|
+
/** POST /v1/beacon - ingest a view/AR analytics event (204). */
|
|
237
|
+
send: (params) => request("POST", "/v1/beacon", { body: params })
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
var Viewrium = class {
|
|
241
|
+
baseUrl;
|
|
242
|
+
products;
|
|
243
|
+
apiKeys;
|
|
244
|
+
usage;
|
|
245
|
+
webhooks;
|
|
246
|
+
projects;
|
|
247
|
+
beacon;
|
|
248
|
+
#request;
|
|
249
|
+
constructor(options) {
|
|
250
|
+
if (!options || !options.apiKey) {
|
|
251
|
+
throw new ViewriumError("A Viewrium client requires an `apiKey` (sk_ or pk_).");
|
|
252
|
+
}
|
|
253
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
254
|
+
const provided = options.fetch;
|
|
255
|
+
const globalFetch = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
256
|
+
const fetchImpl = provided ?? globalFetch;
|
|
257
|
+
if (!fetchImpl) {
|
|
258
|
+
throw new ViewriumError("No fetch implementation available; pass `options.fetch`.");
|
|
259
|
+
}
|
|
260
|
+
const transport = { baseUrl: this.baseUrl, apiKey: options.apiKey, fetch: fetchImpl };
|
|
261
|
+
const request = (method, path, opts) => doRequest(transport, method, path, opts);
|
|
262
|
+
const requestBlob = (method, path, opts) => doBlobRequest(transport, method, path, opts);
|
|
263
|
+
this.#request = request;
|
|
264
|
+
this.products = createProducts(request, requestBlob);
|
|
265
|
+
this.apiKeys = createApiKeys(request);
|
|
266
|
+
this.usage = createUsage(request);
|
|
267
|
+
this.webhooks = createWebhooks(request);
|
|
268
|
+
this.projects = createProjects(request);
|
|
269
|
+
this.beacon = createBeacon(request);
|
|
270
|
+
}
|
|
271
|
+
/** GET /v1/health */
|
|
272
|
+
health() {
|
|
273
|
+
return this.#request("GET", "/v1/health");
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
function createViewrium(options) {
|
|
277
|
+
return new Viewrium(options);
|
|
278
|
+
}
|
|
279
|
+
export {
|
|
280
|
+
AuthenticationError,
|
|
281
|
+
BadRequestError,
|
|
282
|
+
ConflictError,
|
|
283
|
+
ConnectionError,
|
|
284
|
+
NotFoundError,
|
|
285
|
+
PaymentRequiredError,
|
|
286
|
+
PermissionError,
|
|
287
|
+
RateLimitError,
|
|
288
|
+
ServerError,
|
|
289
|
+
UnprocessableEntityError,
|
|
290
|
+
Viewrium,
|
|
291
|
+
ViewriumError,
|
|
292
|
+
createApiError,
|
|
293
|
+
createViewrium
|
|
294
|
+
};
|
|
438
295
|
//# sourceMappingURL=index.js.map
|