cynx-lib 1.3.40 → 1.3.42
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/index.cjs +18 -0
- package/package.json +31 -7
- package/ui/index.cjs +182 -0
- package/utils/index.cjs +80 -0
- package/utils/utils/db.cjs +779 -0
- package/utils/utils/duration.cjs +119 -0
- package/utils/utils/oidc.cjs +164 -0
- package/utils/utils/realtime.cjs +881 -0
- package/utils/utils/session.cjs +61 -0
- package/utils/utils/storage.cjs +344 -0
- package/utils/utils/storage_manager.cjs +1177 -0
- package/utils/utils/storage_manager.js +9 -2
- package/utils/utils/tz.cjs +542 -0
- package/utils/utils/ui.cjs +105 -0
- package/utils/utils/uid.cjs +187 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var session_exports = {};
|
|
19
|
+
__export(session_exports, {
|
|
20
|
+
default: () => session_default,
|
|
21
|
+
deriveDeviceName: () => deriveDeviceName,
|
|
22
|
+
genSessionToken: () => genSessionToken
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(session_exports);
|
|
25
|
+
var import_uid = require("./uid.js");
|
|
26
|
+
function genSessionToken(byteLength = 32) {
|
|
27
|
+
const bytes = (0, import_uid.getRandomBytes)(byteLength);
|
|
28
|
+
let hex = "";
|
|
29
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
30
|
+
hex += bytes[i].toString(16).padStart(2, "0");
|
|
31
|
+
}
|
|
32
|
+
return `st_${hex}`;
|
|
33
|
+
}
|
|
34
|
+
function deriveDeviceName(req, userAgent = "") {
|
|
35
|
+
const headers = req?.headers || {};
|
|
36
|
+
const fromHeader = headers["x-device-name"] || headers["x-pc-name"] || headers["x-computer-name"] || "";
|
|
37
|
+
if (typeof fromHeader === "string" && fromHeader.trim()) {
|
|
38
|
+
return fromHeader.trim().slice(0, 120);
|
|
39
|
+
}
|
|
40
|
+
const fromBody = req?.body?.deviceName || req?.body?.device_name || req?.body?.pcName || req?.body?.pc_name;
|
|
41
|
+
if (typeof fromBody === "string" && fromBody.trim()) {
|
|
42
|
+
return fromBody.trim().slice(0, 120);
|
|
43
|
+
}
|
|
44
|
+
const ua = userAgent || headers["user-agent"] || "";
|
|
45
|
+
if (/windows/i.test(ua)) return "Windows PC";
|
|
46
|
+
if (/macintosh|mac os/i.test(ua)) return "Mac";
|
|
47
|
+
if (/iphone/i.test(ua)) return "iPhone";
|
|
48
|
+
if (/ipad/i.test(ua)) return "iPad";
|
|
49
|
+
if (/android/i.test(ua)) return "Android Device";
|
|
50
|
+
if (/linux/i.test(ua)) return "Linux PC";
|
|
51
|
+
return "Desktop PC";
|
|
52
|
+
}
|
|
53
|
+
var session_default = {
|
|
54
|
+
genSessionToken,
|
|
55
|
+
deriveDeviceName
|
|
56
|
+
};
|
|
57
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
58
|
+
0 && (module.exports = {
|
|
59
|
+
deriveDeviceName,
|
|
60
|
+
genSessionToken
|
|
61
|
+
});
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var storage_exports = {};
|
|
19
|
+
__export(storage_exports, {
|
|
20
|
+
StorageClient: () => StorageClient,
|
|
21
|
+
createStorageClient: () => createStorageClient,
|
|
22
|
+
default: () => storage_default,
|
|
23
|
+
formatBytes: () => formatBytes,
|
|
24
|
+
getCdnUrl: () => getCdnUrl,
|
|
25
|
+
getFileTypeCategory: () => getFileTypeCategory
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(storage_exports);
|
|
28
|
+
const isNode = typeof process !== "undefined" && Boolean(process.versions?.node);
|
|
29
|
+
function getDefaultBaseUrl() {
|
|
30
|
+
if (isNode && process.env?.STORAGE_SERVER_URL) {
|
|
31
|
+
return process.env.STORAGE_SERVER_URL;
|
|
32
|
+
}
|
|
33
|
+
if (typeof window !== "undefined" && window.location?.origin) {
|
|
34
|
+
return window.location.origin;
|
|
35
|
+
}
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
function getDefaultApiKey() {
|
|
39
|
+
if (isNode && (process.env?.STORAGE_SERVER_API_KEY || process.env?.STORAGE_API_KEY)) {
|
|
40
|
+
return process.env.STORAGE_SERVER_API_KEY || process.env.STORAGE_API_KEY;
|
|
41
|
+
}
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
function formatBytes(bytes) {
|
|
45
|
+
const num = Number(bytes) || 0;
|
|
46
|
+
if (num === 0) return "0 B";
|
|
47
|
+
const k = 1024;
|
|
48
|
+
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
49
|
+
const i = Math.floor(Math.log(num) / Math.log(k));
|
|
50
|
+
const val = (num / Math.pow(k, i)).toFixed(2);
|
|
51
|
+
return `${val} ${sizes[i]}`;
|
|
52
|
+
}
|
|
53
|
+
function getFileTypeCategory(mimeType = "", filename = "") {
|
|
54
|
+
const mt = (mimeType || "").toLowerCase();
|
|
55
|
+
const fn = (filename || "").toLowerCase();
|
|
56
|
+
if (mt.startsWith("image/") || /\.(jpg|jpeg|png|gif|webp|bmp|svg|avif|ico)$/i.test(fn)) {
|
|
57
|
+
return "image";
|
|
58
|
+
}
|
|
59
|
+
if (mt === "application/pdf" || /\.pdf$/i.test(fn)) {
|
|
60
|
+
return "pdf";
|
|
61
|
+
}
|
|
62
|
+
if (mt.startsWith("video/") || /\.(mp4|webm|mkv|mov|avi|flv|wmv|m4v)$/i.test(fn)) {
|
|
63
|
+
return "video";
|
|
64
|
+
}
|
|
65
|
+
if (mt.startsWith("audio/") || /\.(mp3|wav|ogg|m4a|aac|flac)$/i.test(fn)) {
|
|
66
|
+
return "audio";
|
|
67
|
+
}
|
|
68
|
+
if (mt.includes("word") || mt.includes("excel") || mt.includes("spreadsheet") || mt.includes("presentation") || mt.includes("csv") || /\.(doc|docx|xls|xlsx|csv|ppt|pptx|txt|rtf|md)$/i.test(fn)) {
|
|
69
|
+
return "document";
|
|
70
|
+
}
|
|
71
|
+
if (mt.includes("zip") || mt.includes("tar") || mt.includes("compressed") || /\.(zip|tar|gz|7z|rar)$/i.test(fn)) {
|
|
72
|
+
return "archive";
|
|
73
|
+
}
|
|
74
|
+
return "other";
|
|
75
|
+
}
|
|
76
|
+
function getCdnUrl(fileId, filename = "", baseUrl = "") {
|
|
77
|
+
if (!fileId) return "";
|
|
78
|
+
const base = (baseUrl || getDefaultBaseUrl() || "").replace(/\/+$/, "");
|
|
79
|
+
const cleanId = String(fileId).trim();
|
|
80
|
+
const suffix = filename ? `/${encodeURIComponent(filename)}` : "";
|
|
81
|
+
return `${base}/cdn/${encodeURIComponent(cleanId)}${suffix}`;
|
|
82
|
+
}
|
|
83
|
+
class StorageClient {
|
|
84
|
+
/**
|
|
85
|
+
* @param {object} [options={}]
|
|
86
|
+
* @param {string} [options.baseUrl] Base URL of the storage server (e.g. "https://storage.domain.com" or "http://localhost:5000")
|
|
87
|
+
* @param {string} [options.apiKey] API Key with upload/read/delete permissions
|
|
88
|
+
* @param {number} [options.timeout=30000] Request timeout in milliseconds
|
|
89
|
+
* @param {Function} [options.fetch] Custom fetch implementation (optional)
|
|
90
|
+
*/
|
|
91
|
+
constructor(options = {}) {
|
|
92
|
+
this.baseUrl = (options.baseUrl || getDefaultBaseUrl() || "").replace(/\/+$/, "");
|
|
93
|
+
this.apiKey = options.apiKey || getDefaultApiKey() || "";
|
|
94
|
+
this.timeout = options.timeout || 3e4;
|
|
95
|
+
this.fetchFn = options.fetch || (typeof globalThis !== "undefined" ? globalThis.fetch?.bind(globalThis) : null);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Update configuration options.
|
|
99
|
+
* @param {object} options
|
|
100
|
+
*/
|
|
101
|
+
configure(options = {}) {
|
|
102
|
+
if (options.baseUrl !== void 0) this.baseUrl = String(options.baseUrl || "").replace(/\/+$/, "");
|
|
103
|
+
if (options.apiKey !== void 0) this.apiKey = String(options.apiKey || "");
|
|
104
|
+
if (options.timeout !== void 0) this.timeout = Number(options.timeout) || 3e4;
|
|
105
|
+
if (options.fetch !== void 0) this.fetchFn = options.fetch;
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Internal HTTP request helper.
|
|
110
|
+
* @private
|
|
111
|
+
*/
|
|
112
|
+
async _request(path, { method = "GET", headers = {}, body, apiKey, signal, timeout } = {}) {
|
|
113
|
+
if (!this.fetchFn) {
|
|
114
|
+
throw new Error("[cynx/storage] No fetch implementation available in current environment.");
|
|
115
|
+
}
|
|
116
|
+
const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
117
|
+
const key = apiKey !== void 0 ? apiKey : this.apiKey;
|
|
118
|
+
const reqHeaders = { ...headers };
|
|
119
|
+
if (key) {
|
|
120
|
+
reqHeaders["x-api-key"] = key;
|
|
121
|
+
}
|
|
122
|
+
const abortCtrl = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
123
|
+
const reqTimeout = timeout || this.timeout;
|
|
124
|
+
let timer = null;
|
|
125
|
+
if (abortCtrl && reqTimeout > 0) {
|
|
126
|
+
timer = setTimeout(() => abortCtrl.abort(new Error(`Storage request timeout after ${reqTimeout}ms`)), reqTimeout);
|
|
127
|
+
}
|
|
128
|
+
const activeSignal = signal || abortCtrl?.signal;
|
|
129
|
+
try {
|
|
130
|
+
const response = await this.fetchFn(url, {
|
|
131
|
+
method,
|
|
132
|
+
headers: reqHeaders,
|
|
133
|
+
body,
|
|
134
|
+
signal: activeSignal
|
|
135
|
+
});
|
|
136
|
+
if (timer) clearTimeout(timer);
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
let errData = null;
|
|
139
|
+
try {
|
|
140
|
+
errData = await response.json();
|
|
141
|
+
} catch {
|
|
142
|
+
errData = { error: response.statusText || `HTTP ${response.status}` };
|
|
143
|
+
}
|
|
144
|
+
const error = new Error(errData.error || errData.message || `Storage Error: ${response.status}`);
|
|
145
|
+
error.status = response.status;
|
|
146
|
+
error.response = errData;
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
return await response.json();
|
|
150
|
+
} catch (err) {
|
|
151
|
+
if (timer) clearTimeout(timer);
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Upload one or multiple files to the storage server.
|
|
157
|
+
*
|
|
158
|
+
* @param {object} params
|
|
159
|
+
* @param {File|Blob|Buffer|ArrayBuffer|Array<File|Blob|Buffer|object>} [params.files] File or array of files to upload
|
|
160
|
+
* @param {File|Blob|Buffer|ArrayBuffer} [params.file] Single file alias
|
|
161
|
+
* @param {string} [params.folder] Target subfolder in cloud storage
|
|
162
|
+
* @param {string} [params.entityType] Associated entity type (e.g. 'company', 'employee', 'inspection')
|
|
163
|
+
* @param {string|number} [params.entityId] Associated entity ID
|
|
164
|
+
* @param {string} [params.apiKey] Override API Key for this upload
|
|
165
|
+
* @param {AbortSignal} [params.signal] AbortSignal for cancellation
|
|
166
|
+
* @returns {Promise<{ files: Array<object>, file: object|null }>} Formatted upload result
|
|
167
|
+
*/
|
|
168
|
+
async upload({
|
|
169
|
+
files,
|
|
170
|
+
file,
|
|
171
|
+
folder,
|
|
172
|
+
entityType,
|
|
173
|
+
entityId,
|
|
174
|
+
entity_type,
|
|
175
|
+
entity_id,
|
|
176
|
+
apiKey,
|
|
177
|
+
signal
|
|
178
|
+
} = {}) {
|
|
179
|
+
if (typeof FormData === "undefined") {
|
|
180
|
+
throw new Error("[cynx/storage] FormData is not available in the current environment.");
|
|
181
|
+
}
|
|
182
|
+
const formData = new FormData();
|
|
183
|
+
const rawFiles = files ? Array.isArray(files) ? files : [files] : file ? [file] : [];
|
|
184
|
+
if (rawFiles.length === 0) {
|
|
185
|
+
throw new Error("[cynx/storage] No file provided for upload.");
|
|
186
|
+
}
|
|
187
|
+
for (let i = 0; i < rawFiles.length; i++) {
|
|
188
|
+
const item = rawFiles[i];
|
|
189
|
+
if (!item) continue;
|
|
190
|
+
if (typeof File !== "undefined" && item instanceof File) {
|
|
191
|
+
formData.append("files", item, item.name);
|
|
192
|
+
} else if (typeof Blob !== "undefined" && item instanceof Blob) {
|
|
193
|
+
const name = item.name || `file_${Date.now()}_${i}`;
|
|
194
|
+
formData.append("files", item, name);
|
|
195
|
+
} else if (isNode && (Buffer.isBuffer(item) || item instanceof Uint8Array || item instanceof ArrayBuffer)) {
|
|
196
|
+
const name = item.name || item.filename || `file_${Date.now()}_${i}`;
|
|
197
|
+
const blob = new Blob([item], { type: item.type || item.mimeType || "application/octet-stream" });
|
|
198
|
+
formData.append("files", blob, name);
|
|
199
|
+
} else if (item && typeof item === "object" && item.data) {
|
|
200
|
+
const name = item.name || item.filename || `file_${Date.now()}_${i}`;
|
|
201
|
+
const blob = item.data instanceof Blob ? item.data : new Blob([item.data], { type: item.type || item.mimeType || "application/octet-stream" });
|
|
202
|
+
formData.append("files", blob, name);
|
|
203
|
+
} else {
|
|
204
|
+
formData.append("files", item);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (folder) formData.append("folder", folder);
|
|
208
|
+
const resolvedEntityType = entityType || entity_type;
|
|
209
|
+
const resolvedEntityId = entityId || entity_id;
|
|
210
|
+
if (resolvedEntityType) formData.append("entityType", resolvedEntityType);
|
|
211
|
+
if (resolvedEntityId) formData.append("entityId", String(resolvedEntityId));
|
|
212
|
+
const res = await this._request("/api/v1/upload", {
|
|
213
|
+
method: "POST",
|
|
214
|
+
body: formData,
|
|
215
|
+
apiKey,
|
|
216
|
+
signal
|
|
217
|
+
});
|
|
218
|
+
const fileList = res?.files ? res.files : Array.isArray(res) ? res : res ? [res] : [];
|
|
219
|
+
return {
|
|
220
|
+
files: fileList,
|
|
221
|
+
file: fileList[0] || null,
|
|
222
|
+
...res
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get metadata and CDN URLs for a specific file by its ID.
|
|
227
|
+
*
|
|
228
|
+
* @param {string} fileId ID of the file (e.g. "sf_abc123")
|
|
229
|
+
* @param {object} [options]
|
|
230
|
+
* @param {string} [options.apiKey] Override API Key
|
|
231
|
+
* @param {AbortSignal} [options.signal] AbortSignal
|
|
232
|
+
* @returns {Promise<object>} File metadata record
|
|
233
|
+
*/
|
|
234
|
+
async getFile(fileId, options = {}) {
|
|
235
|
+
if (!fileId) throw new Error("[cynx/storage] fileId is required.");
|
|
236
|
+
const cleanId = String(fileId).trim().replace(/\.[^/.]+$/, "");
|
|
237
|
+
return this._request(`/api/v1/files/${encodeURIComponent(cleanId)}`, {
|
|
238
|
+
method: "GET",
|
|
239
|
+
...options
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get all files attached to a specific entity.
|
|
244
|
+
*
|
|
245
|
+
* @param {string} entityType Entity type (e.g. "company", "employee")
|
|
246
|
+
* @param {string|number} entityId Entity identifier
|
|
247
|
+
* @param {object} [options]
|
|
248
|
+
* @param {string} [options.apiKey] Override API Key
|
|
249
|
+
* @param {AbortSignal} [options.signal] AbortSignal
|
|
250
|
+
* @returns {Promise<Array<object>>} List of file metadata records
|
|
251
|
+
*/
|
|
252
|
+
async getEntityFiles(entityType, entityId, options = {}) {
|
|
253
|
+
if (!entityType || entityId === void 0 || entityId === null) {
|
|
254
|
+
throw new Error("[cynx/storage] entityType and entityId are required.");
|
|
255
|
+
}
|
|
256
|
+
const res = await this._request(
|
|
257
|
+
`/api/v1/entity/${encodeURIComponent(entityType)}/${encodeURIComponent(entityId)}`,
|
|
258
|
+
{ method: "GET", ...options }
|
|
259
|
+
);
|
|
260
|
+
return Array.isArray(res) ? res : [];
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Delete a single file by ID.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} fileId ID of the file to delete
|
|
266
|
+
* @param {object} [options]
|
|
267
|
+
* @param {string} [options.apiKey] Override API Key
|
|
268
|
+
* @returns {Promise<{ message: string, fileId: string }>}
|
|
269
|
+
*/
|
|
270
|
+
async deleteFile(fileId, options = {}) {
|
|
271
|
+
if (!fileId) throw new Error("[cynx/storage] fileId is required.");
|
|
272
|
+
const cleanId = String(fileId).trim().replace(/\.[^/.]+$/, "");
|
|
273
|
+
return this._request(`/api/v1/files/${encodeURIComponent(cleanId)}`, {
|
|
274
|
+
method: "DELETE",
|
|
275
|
+
...options
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Delete all files belonging to a specific entity.
|
|
280
|
+
*
|
|
281
|
+
* @param {string} entityType Entity type
|
|
282
|
+
* @param {string|number} entityId Entity identifier
|
|
283
|
+
* @param {object} [options]
|
|
284
|
+
* @param {string} [options.apiKey] Override API Key
|
|
285
|
+
* @returns {Promise<{ message: string, deletedCount: number }>}
|
|
286
|
+
*/
|
|
287
|
+
async deleteEntityFiles(entityType, entityId, options = {}) {
|
|
288
|
+
if (!entityType || entityId === void 0 || entityId === null) {
|
|
289
|
+
throw new Error("[cynx/storage] entityType and entityId are required.");
|
|
290
|
+
}
|
|
291
|
+
return this._request(
|
|
292
|
+
`/api/v1/entity/${encodeURIComponent(entityType)}/${encodeURIComponent(entityId)}`,
|
|
293
|
+
{ method: "DELETE", ...options }
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Generate a public CDN streaming/viewing URL for a file.
|
|
298
|
+
*
|
|
299
|
+
* @param {string} fileId File ID
|
|
300
|
+
* @param {string} [filename] Optional clean filename for browser save/view
|
|
301
|
+
* @returns {string} Complete CDN URL
|
|
302
|
+
*/
|
|
303
|
+
getCdnUrl(fileId, filename = "") {
|
|
304
|
+
return getCdnUrl(fileId, filename, this.baseUrl);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Download a file from CDN as a standard Fetch Response.
|
|
308
|
+
*
|
|
309
|
+
* @param {string} fileId File ID
|
|
310
|
+
* @param {object} [options]
|
|
311
|
+
* @param {string} [options.filename]
|
|
312
|
+
* @param {AbortSignal} [options.signal]
|
|
313
|
+
* @returns {Promise<Response>}
|
|
314
|
+
*/
|
|
315
|
+
async download(fileId, options = {}) {
|
|
316
|
+
if (!this.fetchFn) {
|
|
317
|
+
throw new Error("[cynx/storage] No fetch implementation available.");
|
|
318
|
+
}
|
|
319
|
+
const url = this.getCdnUrl(fileId, options.filename);
|
|
320
|
+
const res = await this.fetchFn(url, { signal: options.signal });
|
|
321
|
+
if (!res.ok) {
|
|
322
|
+
throw new Error(`Failed to download file: HTTP ${res.status} ${res.statusText}`);
|
|
323
|
+
}
|
|
324
|
+
return res;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function createStorageClient(options = {}) {
|
|
328
|
+
return new StorageClient(options);
|
|
329
|
+
}
|
|
330
|
+
var storage_default = {
|
|
331
|
+
StorageClient,
|
|
332
|
+
createStorageClient,
|
|
333
|
+
getCdnUrl,
|
|
334
|
+
getFileTypeCategory,
|
|
335
|
+
formatBytes
|
|
336
|
+
};
|
|
337
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
338
|
+
0 && (module.exports = {
|
|
339
|
+
StorageClient,
|
|
340
|
+
createStorageClient,
|
|
341
|
+
formatBytes,
|
|
342
|
+
getCdnUrl,
|
|
343
|
+
getFileTypeCategory
|
|
344
|
+
});
|