@headroom-cms/admin-api 0.1.1

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.js ADDED
@@ -0,0 +1,601 @@
1
+ // src/error.ts
2
+ var HeadroomApiError = class extends Error {
3
+ status;
4
+ code;
5
+ constructor(status, code, message) {
6
+ super(message || code);
7
+ this.name = "HeadroomApiError";
8
+ this.status = status;
9
+ this.code = code;
10
+ }
11
+ /** Alias for `message` — eases migration from admin's ApiError which used `detail`. */
12
+ get detail() {
13
+ return this.message;
14
+ }
15
+ };
16
+
17
+ // src/mime.ts
18
+ var MIME_MAP = {
19
+ ".jpg": "image/jpeg",
20
+ ".jpeg": "image/jpeg",
21
+ ".png": "image/png",
22
+ ".gif": "image/gif",
23
+ ".webp": "image/webp",
24
+ ".svg": "image/svg+xml",
25
+ ".mp4": "video/mp4",
26
+ ".pdf": "application/pdf"
27
+ };
28
+ function mimeFromFilename(filename) {
29
+ const ext = filename.includes(".") ? "." + filename.split(".").pop().toLowerCase() : "";
30
+ return MIME_MAP[ext] || "application/octet-stream";
31
+ }
32
+
33
+ // src/client.ts
34
+ var HeadroomAdminClient = class {
35
+ baseUrl;
36
+ tokenProvider;
37
+ constructor(baseUrl, tokenProvider) {
38
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
39
+ this.tokenProvider = tokenProvider;
40
+ }
41
+ /**
42
+ * Low-level fetch — public so admin UI hooks can migrate incrementally.
43
+ * Prefer typed methods (listSites, createContent, etc.) in new code.
44
+ */
45
+ async apiFetch(path, options) {
46
+ const token = await this.tokenProvider.getToken();
47
+ const headers = {
48
+ "Content-Type": "application/json",
49
+ Authorization: `Bearer ${token}`,
50
+ ...options?.headers
51
+ };
52
+ const res = await fetch(`${this.baseUrl}${path}`, {
53
+ ...options,
54
+ headers
55
+ });
56
+ if (res.status === 401 && this.tokenProvider.onUnauthorized) {
57
+ const newToken = await this.tokenProvider.onUnauthorized();
58
+ headers["Authorization"] = `Bearer ${newToken}`;
59
+ const retry = await fetch(`${this.baseUrl}${path}`, {
60
+ ...options,
61
+ headers
62
+ });
63
+ return this.handleResponse(retry);
64
+ }
65
+ return this.handleResponse(res);
66
+ }
67
+ async handleResponse(res) {
68
+ if (!res.ok) {
69
+ let code = "UNKNOWN";
70
+ let message = `HTTP ${res.status}`;
71
+ try {
72
+ const body = await res.json();
73
+ code = body.code || body.error || code;
74
+ message = body.message || body.error || message;
75
+ } catch {
76
+ }
77
+ throw new HeadroomApiError(res.status, code, message);
78
+ }
79
+ if (res.status === 204) return void 0;
80
+ return res.json();
81
+ }
82
+ // ── Sites ──────────────────────────────────────────
83
+ async listSites(includeArchived = false) {
84
+ const qs = includeArchived ? "?includeArchived=true" : "";
85
+ const res = await this.apiFetch(
86
+ `/v1/admin/sites${qs}`
87
+ );
88
+ return res.items;
89
+ }
90
+ async createSite(host, name) {
91
+ return this.apiFetch("/v1/admin/sites", {
92
+ method: "POST",
93
+ body: JSON.stringify({ host, name })
94
+ });
95
+ }
96
+ async getSite(host) {
97
+ return this.apiFetch(
98
+ `/v1/admin/sites/${encodeURIComponent(host)}`
99
+ );
100
+ }
101
+ async updateSite(host, data) {
102
+ return this.apiFetch(
103
+ `/v1/admin/sites/${encodeURIComponent(host)}`,
104
+ { method: "PUT", body: JSON.stringify(data) }
105
+ );
106
+ }
107
+ async deleteSite(host) {
108
+ await this.apiFetch(
109
+ `/v1/admin/sites/${encodeURIComponent(host)}`,
110
+ { method: "DELETE" }
111
+ );
112
+ }
113
+ async updateSiteAdmins(host, admins) {
114
+ await this.apiFetch(
115
+ `/v1/admin/sites/${encodeURIComponent(host)}/admins`,
116
+ { method: "PUT", body: JSON.stringify({ admins }) }
117
+ );
118
+ }
119
+ async purgeSite(host) {
120
+ await this.apiFetch(
121
+ `/v1/admin/sites/${encodeURIComponent(host)}/purge`,
122
+ { method: "POST" }
123
+ );
124
+ }
125
+ async inviteToSite(host, email, adminUrl) {
126
+ return this.apiFetch(
127
+ `/v1/admin/sites/${encodeURIComponent(host)}/invite`,
128
+ { method: "POST", body: JSON.stringify({ email, adminUrl }) }
129
+ );
130
+ }
131
+ // ── Collections ────────────────────────────────────
132
+ async listCollections(host) {
133
+ const res = await this.apiFetch(
134
+ `/v1/admin/sites/${encodeURIComponent(host)}/collections`
135
+ );
136
+ return res.collections;
137
+ }
138
+ async createCollection(host, input) {
139
+ return this.apiFetch(
140
+ `/v1/admin/sites/${encodeURIComponent(host)}/collections`,
141
+ { method: "POST", body: JSON.stringify(input) }
142
+ );
143
+ }
144
+ async getCollection(host, name) {
145
+ return this.apiFetch(
146
+ `/v1/admin/sites/${encodeURIComponent(host)}/collections/${encodeURIComponent(name)}`
147
+ );
148
+ }
149
+ async updateCollection(host, name, input) {
150
+ return this.apiFetch(
151
+ `/v1/admin/sites/${encodeURIComponent(host)}/collections/${encodeURIComponent(name)}`,
152
+ { method: "PUT", body: JSON.stringify(input) }
153
+ );
154
+ }
155
+ async deleteCollection(host, name) {
156
+ await this.apiFetch(
157
+ `/v1/admin/sites/${encodeURIComponent(host)}/collections/${encodeURIComponent(name)}`,
158
+ { method: "DELETE" }
159
+ );
160
+ }
161
+ // ── Block Types ────────────────────────────────────
162
+ async listBlockTypes(host) {
163
+ const res = await this.apiFetch(
164
+ `/v1/admin/sites/${encodeURIComponent(host)}/block-types`
165
+ );
166
+ return res.blockTypes;
167
+ }
168
+ async createBlockType(host, input) {
169
+ return this.apiFetch(
170
+ `/v1/admin/sites/${encodeURIComponent(host)}/block-types`,
171
+ { method: "POST", body: JSON.stringify(input) }
172
+ );
173
+ }
174
+ async getBlockType(host, name) {
175
+ return this.apiFetch(
176
+ `/v1/admin/sites/${encodeURIComponent(host)}/block-types/${encodeURIComponent(name)}`
177
+ );
178
+ }
179
+ async updateBlockType(host, name, input) {
180
+ return this.apiFetch(
181
+ `/v1/admin/sites/${encodeURIComponent(host)}/block-types/${encodeURIComponent(name)}`,
182
+ { method: "PUT", body: JSON.stringify(input) }
183
+ );
184
+ }
185
+ async deleteBlockType(host, name) {
186
+ await this.apiFetch(
187
+ `/v1/admin/sites/${encodeURIComponent(host)}/block-types/${encodeURIComponent(name)}`,
188
+ { method: "DELETE" }
189
+ );
190
+ }
191
+ // ── Content ────────────────────────────────────────
192
+ async listContent(host, params) {
193
+ const qs = new URLSearchParams();
194
+ if (params?.collection) qs.set("collection", params.collection);
195
+ if (params?.q) qs.set("q", params.q);
196
+ if (params?.search) qs.set("search", params.search);
197
+ if (params?.tag) qs.set("tag", params.tag);
198
+ if (params?.status) qs.set("status", params.status);
199
+ if (params?.sort) qs.set("sort", params.sort);
200
+ if (params?.relatedTo) qs.set("relatedTo", params.relatedTo);
201
+ if (params?.limit) qs.set("limit", String(params.limit));
202
+ if (params?.cursor) qs.set("cursor", params.cursor);
203
+ const q = qs.toString();
204
+ return this.apiFetch(
205
+ `/v1/admin/sites/${encodeURIComponent(host)}/content${q ? `?${q}` : ""}`
206
+ );
207
+ }
208
+ async createContent(host, params) {
209
+ return this.apiFetch(
210
+ `/v1/admin/sites/${encodeURIComponent(host)}/content`,
211
+ { method: "POST", body: JSON.stringify(params) }
212
+ );
213
+ }
214
+ async getContent(host, contentId) {
215
+ return this.apiFetch(
216
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}`
217
+ );
218
+ }
219
+ async deleteContent(host, contentId) {
220
+ await this.apiFetch(
221
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}`,
222
+ { method: "DELETE" }
223
+ );
224
+ }
225
+ async saveDraft(host, contentId, draft) {
226
+ return this.apiFetch(
227
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/draft`,
228
+ { method: "PUT", body: JSON.stringify(draft) }
229
+ );
230
+ }
231
+ async publishContent(host, contentId) {
232
+ return this.apiFetch(
233
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/publish`,
234
+ { method: "POST" }
235
+ );
236
+ }
237
+ async unpublishContent(host, contentId) {
238
+ await this.apiFetch(
239
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/unpublish`,
240
+ { method: "POST" }
241
+ );
242
+ }
243
+ async discardDraft(host, contentId) {
244
+ await this.apiFetch(
245
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/discard`,
246
+ { method: "POST" }
247
+ );
248
+ }
249
+ async getPublishedContent(host, contentId) {
250
+ return this.apiFetch(
251
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/published`
252
+ );
253
+ }
254
+ async listVersions(host, contentId) {
255
+ return this.apiFetch(
256
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/versions`
257
+ );
258
+ }
259
+ async getVersion(host, contentId, blockId) {
260
+ return this.apiFetch(
261
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/versions/${blockId}`
262
+ );
263
+ }
264
+ async getReferences(host, contentId) {
265
+ return this.apiFetch(
266
+ `/v1/admin/sites/${encodeURIComponent(host)}/content/${contentId}/references`
267
+ );
268
+ }
269
+ // ── Media ──────────────────────────────────────────
270
+ async listMedia(host, params) {
271
+ const qs = new URLSearchParams();
272
+ if (params?.tag) qs.set("tag", params.tag);
273
+ if (params?.folderId) qs.set("folderId", params.folderId);
274
+ if (params?.q) qs.set("q", params.q);
275
+ if (params?.sort) qs.set("sort", params.sort);
276
+ if (params?.limit) qs.set("limit", String(params.limit));
277
+ if (params?.cursor) qs.set("cursor", params.cursor);
278
+ const q = qs.toString();
279
+ return this.apiFetch(
280
+ `/v1/admin/sites/${encodeURIComponent(host)}/media${q ? `?${q}` : ""}`
281
+ );
282
+ }
283
+ async getMedia(host, mediaId) {
284
+ return this.apiFetch(
285
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/${mediaId}`
286
+ );
287
+ }
288
+ async updateMedia(host, mediaId, data) {
289
+ return this.apiFetch(
290
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/${mediaId}`,
291
+ { method: "PUT", body: JSON.stringify(data) }
292
+ );
293
+ }
294
+ async deleteMedia(host, mediaId) {
295
+ await this.apiFetch(
296
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/${mediaId}`,
297
+ { method: "DELETE" }
298
+ );
299
+ }
300
+ async getUploadUrl(host, params) {
301
+ return this.apiFetch(
302
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/upload-url`,
303
+ { method: "POST", body: JSON.stringify(params) }
304
+ );
305
+ }
306
+ async completeUpload(host, mediaId, params) {
307
+ return this.apiFetch(
308
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/${mediaId}/complete`,
309
+ { method: "POST", body: JSON.stringify(params) }
310
+ );
311
+ }
312
+ /**
313
+ * Convenience: download from URL and upload through the media pipeline.
314
+ * Works in both Node.js and browsers (uses fetch + Uint8Array, no Node APIs).
315
+ */
316
+ async uploadFromUrl(host, url, filename, alt) {
317
+ const res = await fetch(url);
318
+ if (!res.ok) throw new Error(`Failed to fetch ${url}: ${res.status}`);
319
+ const buffer = new Uint8Array(await res.arrayBuffer());
320
+ let contentType = res.headers.get("content-type")?.split(";")[0]?.trim() || "";
321
+ if (!contentType || contentType === "application/octet-stream") {
322
+ contentType = mimeFromFilename(filename);
323
+ }
324
+ const { mediaId, uploadUrl } = await this.getUploadUrl(host, {
325
+ filename,
326
+ contentType,
327
+ size: buffer.length
328
+ });
329
+ const uploadRes = await fetch(uploadUrl, {
330
+ method: "PUT",
331
+ body: buffer,
332
+ headers: { "Content-Type": contentType }
333
+ });
334
+ if (!uploadRes.ok)
335
+ throw new Error(`S3 upload failed: ${uploadRes.status}`);
336
+ return this.completeUpload(host, mediaId, { filename, alt });
337
+ }
338
+ // Media folders
339
+ async listMediaFolders(host) {
340
+ const res = await this.apiFetch(
341
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/folders`
342
+ );
343
+ return res.items;
344
+ }
345
+ async createMediaFolder(host, name) {
346
+ return this.apiFetch(
347
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/folders`,
348
+ { method: "POST", body: JSON.stringify({ name }) }
349
+ );
350
+ }
351
+ async updateMediaFolder(host, folderId, name) {
352
+ return this.apiFetch(
353
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/folders/${folderId}`,
354
+ { method: "PUT", body: JSON.stringify({ name }) }
355
+ );
356
+ }
357
+ async deleteMediaFolder(host, folderId) {
358
+ await this.apiFetch(
359
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/folders/${folderId}`,
360
+ { method: "DELETE" }
361
+ );
362
+ }
363
+ async bulkMediaOperation(host, params) {
364
+ return this.apiFetch(
365
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/bulk`,
366
+ { method: "POST", body: JSON.stringify(params) }
367
+ );
368
+ }
369
+ async checkDuplicate(host, filename, size) {
370
+ const qs = new URLSearchParams({ filename, size: String(size) });
371
+ return this.apiFetch(
372
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/check-duplicate?${qs}`
373
+ );
374
+ }
375
+ async getTransformUrl(host, mediaId, params) {
376
+ const qs = new URLSearchParams();
377
+ for (const [k, v] of Object.entries(params)) {
378
+ if (v !== void 0) qs.set(k, String(v));
379
+ }
380
+ return this.apiFetch(
381
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/${mediaId}/transform-url?${qs}`
382
+ );
383
+ }
384
+ async saveTransform(host, mediaId, params) {
385
+ return this.apiFetch(
386
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/${mediaId}/save-transform`,
387
+ { method: "POST", body: JSON.stringify(params) }
388
+ );
389
+ }
390
+ async getMediaUsage(host, mediaId) {
391
+ return this.apiFetch(
392
+ `/v1/admin/sites/${encodeURIComponent(host)}/media/${mediaId}/usage`
393
+ );
394
+ }
395
+ // ── API Keys ───────────────────────────────────────
396
+ async listApiKeys(host) {
397
+ const res = await this.apiFetch(
398
+ `/v1/admin/sites/${encodeURIComponent(host)}/api-keys`
399
+ );
400
+ return res.keys;
401
+ }
402
+ async createApiKey(host, label) {
403
+ return this.apiFetch(
404
+ `/v1/admin/sites/${encodeURIComponent(host)}/api-keys`,
405
+ { method: "POST", body: JSON.stringify({ label }) }
406
+ );
407
+ }
408
+ async updateApiKey(host, keyId, label) {
409
+ return this.apiFetch(
410
+ `/v1/admin/sites/${encodeURIComponent(host)}/api-keys/${keyId}`,
411
+ { method: "PUT", body: JSON.stringify({ label }) }
412
+ );
413
+ }
414
+ async deleteApiKey(host, keyId) {
415
+ await this.apiFetch(
416
+ `/v1/admin/sites/${encodeURIComponent(host)}/api-keys/${keyId}`,
417
+ { method: "DELETE" }
418
+ );
419
+ }
420
+ // ── Webhooks ───────────────────────────────────────
421
+ async listWebhooks(host) {
422
+ const res = await this.apiFetch(
423
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks`
424
+ );
425
+ return res.webhooks;
426
+ }
427
+ async createWebhook(host, data) {
428
+ return this.apiFetch(
429
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks`,
430
+ { method: "POST", body: JSON.stringify(data) }
431
+ );
432
+ }
433
+ async getWebhook(host, webhookId) {
434
+ return this.apiFetch(
435
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}`
436
+ );
437
+ }
438
+ async updateWebhook(host, webhookId, data) {
439
+ return this.apiFetch(
440
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}`,
441
+ { method: "PUT", body: JSON.stringify(data) }
442
+ );
443
+ }
444
+ async deleteWebhook(host, webhookId) {
445
+ await this.apiFetch(
446
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}`,
447
+ { method: "DELETE" }
448
+ );
449
+ }
450
+ async testWebhook(host, webhookId) {
451
+ await this.apiFetch(
452
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}/test`,
453
+ { method: "POST" }
454
+ );
455
+ }
456
+ async rotateWebhookSecret(host, webhookId) {
457
+ return this.apiFetch(
458
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}/rotate-secret`,
459
+ { method: "POST" }
460
+ );
461
+ }
462
+ async listWebhookDeliveries(host, webhookId) {
463
+ return this.apiFetch(
464
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}/deliveries`
465
+ );
466
+ }
467
+ async getWebhookDelivery(host, webhookId, deliveryId) {
468
+ return this.apiFetch(
469
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}/deliveries/${deliveryId}`
470
+ );
471
+ }
472
+ async retryDelivery(host, webhookId, deliveryId) {
473
+ await this.apiFetch(
474
+ `/v1/admin/sites/${encodeURIComponent(host)}/webhooks/${webhookId}/deliveries/${deliveryId}/retry`,
475
+ { method: "POST" }
476
+ );
477
+ }
478
+ // ── Tags ───────────────────────────────────────────
479
+ async listTags(host) {
480
+ return this.apiFetch(
481
+ `/v1/admin/sites/${encodeURIComponent(host)}/tags`
482
+ );
483
+ }
484
+ async createTag(host, tag) {
485
+ await this.apiFetch(
486
+ `/v1/admin/sites/${encodeURIComponent(host)}/tags`,
487
+ { method: "POST", body: JSON.stringify({ tag }) }
488
+ );
489
+ }
490
+ async deleteTag(host, tag) {
491
+ await this.apiFetch(
492
+ `/v1/admin/sites/${encodeURIComponent(host)}/tags/${encodeURIComponent(tag)}`,
493
+ { method: "DELETE" }
494
+ );
495
+ }
496
+ // ── Audit ──────────────────────────────────────────
497
+ async listAuditEvents(host, params) {
498
+ const qs = new URLSearchParams();
499
+ if (params?.action) qs.set("action", params.action);
500
+ if (params?.before) qs.set("before", String(params.before));
501
+ const q = qs.toString();
502
+ return this.apiFetch(
503
+ `/v1/admin/sites/${encodeURIComponent(host)}/audit${q ? `?${q}` : ""}`
504
+ );
505
+ }
506
+ // ── Users (global, not site-scoped) ────────────────
507
+ async listUsers() {
508
+ return this.apiFetch("/v1/admin/users");
509
+ }
510
+ async deleteUser(sub) {
511
+ await this.apiFetch(`/v1/admin/users/${sub}`, {
512
+ method: "DELETE"
513
+ });
514
+ }
515
+ async disableUserMfa(sub) {
516
+ await this.apiFetch(`/v1/admin/users/${sub}/mfa`, {
517
+ method: "DELETE"
518
+ });
519
+ }
520
+ async resolveAdmins(subs) {
521
+ return this.apiFetch("/v1/admin/users/resolve", {
522
+ method: "POST",
523
+ body: JSON.stringify({ subs })
524
+ });
525
+ }
526
+ async listSuperAdmins() {
527
+ return this.apiFetch("/v1/admin/super-admins");
528
+ }
529
+ async updateSuperAdmins(superAdminIds) {
530
+ await this.apiFetch("/v1/admin/super-admins", {
531
+ method: "PUT",
532
+ body: JSON.stringify({ superAdminIds })
533
+ });
534
+ }
535
+ };
536
+
537
+ // src/token-provider.ts
538
+ var StaticTokenProvider = class {
539
+ constructor(token) {
540
+ this.token = token;
541
+ }
542
+ async getToken() {
543
+ return this.token;
544
+ }
545
+ };
546
+
547
+ // src/blocks.ts
548
+ function text(t, styles) {
549
+ return { type: "text", text: t, styles: styles || {} };
550
+ }
551
+ function link(href, label) {
552
+ return { type: "link", href, content: [text(label)] };
553
+ }
554
+ function block(type, content, props, children) {
555
+ return {
556
+ id: crypto.randomUUID().slice(0, 8),
557
+ type,
558
+ props: { textAlignment: "left", ...props },
559
+ content: content || [],
560
+ children: children || []
561
+ };
562
+ }
563
+ function heading(level, ...content) {
564
+ return block("heading", content, { level });
565
+ }
566
+ function paragraph(...content) {
567
+ return block("paragraph", content);
568
+ }
569
+ function bulletItem(...content) {
570
+ return block("bulletListItem", content);
571
+ }
572
+ function numberedItem(...content) {
573
+ return block("numberedListItem", content);
574
+ }
575
+ function checkItem(checked, ...content) {
576
+ return block("checkListItem", content, { checked });
577
+ }
578
+ function codeBlock(language, code) {
579
+ return block("codeBlock", [text(code)], { language });
580
+ }
581
+ function image(props) {
582
+ return block("image", void 0, {
583
+ ...props,
584
+ textAlignment: "center"
585
+ });
586
+ }
587
+ export {
588
+ HeadroomAdminClient,
589
+ HeadroomApiError,
590
+ StaticTokenProvider,
591
+ block,
592
+ bulletItem,
593
+ checkItem,
594
+ codeBlock,
595
+ heading,
596
+ image,
597
+ link,
598
+ numberedItem,
599
+ paragraph,
600
+ text
601
+ };
package/dist/node.cjs ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/node.ts
31
+ var node_exports = {};
32
+ __export(node_exports, {
33
+ uploadFile: () => uploadFile
34
+ });
35
+ module.exports = __toCommonJS(node_exports);
36
+
37
+ // src/mime.ts
38
+ var MIME_MAP = {
39
+ ".jpg": "image/jpeg",
40
+ ".jpeg": "image/jpeg",
41
+ ".png": "image/png",
42
+ ".gif": "image/gif",
43
+ ".webp": "image/webp",
44
+ ".svg": "image/svg+xml",
45
+ ".mp4": "video/mp4",
46
+ ".pdf": "application/pdf"
47
+ };
48
+ function mimeFromFilename(filename) {
49
+ const ext = filename.includes(".") ? "." + filename.split(".").pop().toLowerCase() : "";
50
+ return MIME_MAP[ext] || "application/octet-stream";
51
+ }
52
+
53
+ // src/node.ts
54
+ async function uploadFile(client, host, filePath, alt) {
55
+ const fs = await import("fs/promises");
56
+ const path = await import("path");
57
+ const data = await fs.readFile(filePath);
58
+ const filename = path.basename(filePath);
59
+ const contentType = mimeFromFilename(filename);
60
+ const { mediaId, uploadUrl } = await client.getUploadUrl(host, {
61
+ filename,
62
+ contentType,
63
+ size: data.length
64
+ });
65
+ const uploadRes = await fetch(uploadUrl, {
66
+ method: "PUT",
67
+ body: data,
68
+ headers: { "Content-Type": contentType }
69
+ });
70
+ if (!uploadRes.ok) {
71
+ throw new Error(`S3 upload failed: ${uploadRes.status}`);
72
+ }
73
+ return client.completeUpload(host, mediaId, { filename, alt });
74
+ }
75
+ // Annotate the CommonJS export names for ESM import in node:
76
+ 0 && (module.exports = {
77
+ uploadFile
78
+ });