@calmlens/sdk 0.0.0-stage → 0.5.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/cjs/testing.js ADDED
@@ -0,0 +1,702 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_CalmLensUtils = require("./CalmLensUtils-0QaxbI3A.js");
3
+ let zod = require("zod");
4
+ zod = require_CalmLensUtils.__toESM(zod);
5
+ //#region ../shared/src/Permissions.ts
6
+ const ACTION_SCHEMA = zod.enum([
7
+ "assets:read",
8
+ "assets:download",
9
+ "assets:create",
10
+ "assets:update",
11
+ "assets:delete",
12
+ "assets:share",
13
+ "folders:read",
14
+ "folders:create",
15
+ "folders:update",
16
+ "folders:delete",
17
+ "project:manage"
18
+ ]);
19
+ const GRANT_SCHEMA = zod.object({
20
+ actions: zod.array(ACTION_SCHEMA),
21
+ folderId: zod.string().uuid().nullable(),
22
+ includeSubfolders: zod.boolean()
23
+ }).strict().refine((g) => g.folderId === null || !g.actions.includes("project:manage"), "Project management requires project scope");
24
+ const GRANTS_SCHEMA = zod.array(GRANT_SCHEMA).max(100);
25
+ zod.enum([
26
+ "admin",
27
+ "member",
28
+ "viewer",
29
+ "custom"
30
+ ]);
31
+ const permits = (grants, action, folderId, folders) => grants.some((grant) => {
32
+ if (!grant.actions.includes(action)) return false;
33
+ if (grant.folderId === null) return true;
34
+ let current = folderId;
35
+ const visited = /* @__PURE__ */ new Set();
36
+ while (current && !visited.has(current)) {
37
+ var _folders$find$parentI, _folders$find;
38
+ if (current === grant.folderId) return true;
39
+ if (!grant.includeSubfolders) return false;
40
+ visited.add(current);
41
+ current = (_folders$find$parentI = (_folders$find = folders.find((folder) => folder.id === current)) === null || _folders$find === void 0 ? void 0 : _folders$find.parentId) !== null && _folders$find$parentI !== void 0 ? _folders$find$parentI : null;
42
+ }
43
+ return false;
44
+ });
45
+ const SYSTEM_PERMISSION_SCHEMA = zod.enum([
46
+ "system:admin",
47
+ "system:assets:read-all",
48
+ "system:uploads:unlimited"
49
+ ]);
50
+ zod.array(SYSTEM_PERMISSION_SCHEMA);
51
+ zod.enum(["active", "banned"]);
52
+ //#endregion
53
+ //#region src/testing/MockApiKey.ts
54
+ const MOCK_API_KEY_PREFIX = "sk_test_";
55
+ const toBase64Url = (value) => btoa(value).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
56
+ const fromBase64Url = (value) => {
57
+ const padded = value.padEnd(value.length + (4 - value.length % 4) % 4, "=");
58
+ return atob(padded.replaceAll("-", "+").replaceAll("_", "/"));
59
+ };
60
+ const createMockApiKey = (grants = []) => `${MOCK_API_KEY_PREFIX}${toBase64Url(JSON.stringify(GRANTS_SCHEMA.parse(grants)))}`;
61
+ const getMockApiKeyGrants = (apiKey) => {
62
+ if (!apiKey.startsWith("sk_test_")) return [];
63
+ try {
64
+ return GRANTS_SCHEMA.parse(JSON.parse(fromBase64Url(apiKey.slice(8))));
65
+ } catch (_unused) {
66
+ return [];
67
+ }
68
+ };
69
+ //#endregion
70
+ //#region src/testing/MockStorage.ts
71
+ var InMemoryMockImageStorage = class {
72
+ constructor() {
73
+ this.content = /* @__PURE__ */ new Map();
74
+ }
75
+ putContent(assetId, content) {
76
+ var _this = this;
77
+ return require_CalmLensUtils._asyncToGenerator(function* () {
78
+ const validation = require_CalmLensUtils.validateAssetPayload(content);
79
+ if (!validation.ok) throw new Error(validation.error);
80
+ const bytes = yield require_CalmLensUtils.assetDataToUint8Array(require_CalmLensUtils.assetToData(content));
81
+ _this.content.set(assetId, {
82
+ assetId,
83
+ parts: /* @__PURE__ */ new Map([[1, bytes]]),
84
+ type: content.type
85
+ });
86
+ })();
87
+ }
88
+ putPart(assetId, part) {
89
+ var _this2 = this;
90
+ return require_CalmLensUtils._asyncToGenerator(function* () {
91
+ var _this$content$get, _part$partNumber, _part$type;
92
+ const validation = require_CalmLensUtils.validateAssetPayload(part, {
93
+ multipart: true,
94
+ isFinal: part.isFinal
95
+ });
96
+ if (!validation.ok) throw new Error(validation.error);
97
+ const bytes = yield require_CalmLensUtils.assetDataToUint8Array(require_CalmLensUtils.assetToData(part));
98
+ const existing = (_this$content$get = _this2.content.get(assetId)) !== null && _this$content$get !== void 0 ? _this$content$get : {
99
+ assetId,
100
+ parts: /* @__PURE__ */ new Map(),
101
+ type: part.type
102
+ };
103
+ existing.parts.set((_part$partNumber = part.partNumber) !== null && _part$partNumber !== void 0 ? _part$partNumber : 1, bytes);
104
+ existing.type = (_part$type = part.type) !== null && _part$type !== void 0 ? _part$type : existing.type;
105
+ _this2.content.set(assetId, existing);
106
+ })();
107
+ }
108
+ getContent(assetId) {
109
+ var _this3 = this;
110
+ return require_CalmLensUtils._asyncToGenerator(function* () {
111
+ return _this3.content.get(assetId);
112
+ })();
113
+ }
114
+ deleteContent(assetId) {
115
+ var _this4 = this;
116
+ return require_CalmLensUtils._asyncToGenerator(function* () {
117
+ _this4.content.delete(assetId);
118
+ })();
119
+ }
120
+ };
121
+ var InMemoryMockDatabaseStorage = class {
122
+ constructor() {
123
+ this.assets = /* @__PURE__ */ new Map();
124
+ this.folders = /* @__PURE__ */ new Map();
125
+ }
126
+ createAsset(asset) {
127
+ var _this5 = this;
128
+ return require_CalmLensUtils._asyncToGenerator(function* () {
129
+ _this5.assets.set(asset.id, asset);
130
+ return asset;
131
+ })();
132
+ }
133
+ updateAsset(asset) {
134
+ var _this6 = this;
135
+ return require_CalmLensUtils._asyncToGenerator(function* () {
136
+ _this6.assets.set(asset.id, asset);
137
+ return asset;
138
+ })();
139
+ }
140
+ getAsset(assetId) {
141
+ var _this7 = this;
142
+ return require_CalmLensUtils._asyncToGenerator(function* () {
143
+ return _this7.assets.get(assetId);
144
+ })();
145
+ }
146
+ listAssets(projectId) {
147
+ var _this8 = this;
148
+ return require_CalmLensUtils._asyncToGenerator(function* () {
149
+ return [..._this8.assets.values()].filter((asset) => asset.projectId === projectId);
150
+ })();
151
+ }
152
+ deleteAsset(assetId) {
153
+ var _this9 = this;
154
+ return require_CalmLensUtils._asyncToGenerator(function* () {
155
+ _this9.assets.delete(assetId);
156
+ })();
157
+ }
158
+ createFolder(folder) {
159
+ var _this10 = this;
160
+ return require_CalmLensUtils._asyncToGenerator(function* () {
161
+ _this10.folders.set(folder.id, folder);
162
+ return folder;
163
+ })();
164
+ }
165
+ updateFolder(folder) {
166
+ var _this11 = this;
167
+ return require_CalmLensUtils._asyncToGenerator(function* () {
168
+ _this11.folders.set(folder.id, folder);
169
+ return folder;
170
+ })();
171
+ }
172
+ getFolder(folderId) {
173
+ var _this12 = this;
174
+ return require_CalmLensUtils._asyncToGenerator(function* () {
175
+ return _this12.folders.get(folderId);
176
+ })();
177
+ }
178
+ listFolders(projectId) {
179
+ var _this13 = this;
180
+ return require_CalmLensUtils._asyncToGenerator(function* () {
181
+ return [..._this13.folders.values()].filter((folder) => folder.projectId === projectId).sort((a, b) => a.name.localeCompare(b.name));
182
+ })();
183
+ }
184
+ deleteFolder(folderId) {
185
+ var _this14 = this;
186
+ return require_CalmLensUtils._asyncToGenerator(function* () {
187
+ _this14.folders.delete(folderId);
188
+ })();
189
+ }
190
+ };
191
+ //#endregion
192
+ //#region src/testing/MockUtils.ts
193
+ const appendCdnSelector = (url, options) => {
194
+ if (options.lens && options.transform) throw new Error("Specify either a lens or a transform, not both");
195
+ if (options.lens) return `${url}/@${encodeURIComponent(options.lens)}`;
196
+ if (!options.transform) return url;
197
+ return `${url}/${encodeURI(options.transform.replace(/^\/+/, ""))}`;
198
+ };
199
+ const inferAssetType = (options) => {
200
+ if ("url" in options) return "website";
201
+ const type = "content" in options ? options.content.type : options.part.type;
202
+ if (type.startsWith("image/") || [
203
+ "jpg",
204
+ "jpeg",
205
+ "png",
206
+ "gif",
207
+ "webp",
208
+ "avif"
209
+ ].includes(type)) return "image";
210
+ if (type.startsWith("video/")) return "video";
211
+ if (type.startsWith("audio/")) return "audio";
212
+ if (type === "text/plain" || type === "txt" || type.startsWith("text/")) return "plaintext-document";
213
+ if (type.includes("pdf") || type.includes("document") || [
214
+ "pdf",
215
+ "doc",
216
+ "docx"
217
+ ].includes(type)) return "multimedia-document";
218
+ return "file";
219
+ };
220
+ const createPage = (items, query) => {
221
+ var _query$pageIndex, _query$pageSize;
222
+ const pageIndex = (_query$pageIndex = query.pageIndex) !== null && _query$pageIndex !== void 0 ? _query$pageIndex : 0;
223
+ const pageSize = (_query$pageSize = query.pageSize) !== null && _query$pageSize !== void 0 ? _query$pageSize : 10;
224
+ const start = pageIndex * pageSize;
225
+ return {
226
+ items: items.slice(start, start + pageSize),
227
+ total: items.length,
228
+ pageIndex,
229
+ pageSize,
230
+ ordering: [],
231
+ hasMore: start + pageSize < items.length
232
+ };
233
+ };
234
+ //#endregion
235
+ //#region src/testing/MockCalmLensClient.ts
236
+ const _excluded = ["assetIdentifier"];
237
+ const _excluded2 = ["assetIdentifier"];
238
+ const _excluded3 = ["assetId"];
239
+ const _excluded4 = ["assetId"];
240
+ const _excluded5 = ["folderId"];
241
+ const assertValidUploadMimeType = (mimeType) => {
242
+ if (require_CalmLensUtils.isRejectedUploadMimeType(mimeType)) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.INVALID_UPLOAD_MIME_TYPE, {
243
+ message: require_CalmLensUtils.getRejectedUploadMimeTypeError(mimeType),
244
+ details: { mimeType }
245
+ });
246
+ };
247
+ var MockCalmLensClient = class {
248
+ constructor(options) {
249
+ var _options$mockOptions$, _options$mockOptions, _options$mockOptions$2, _options$mockOptions2, _options$mockOptions$3, _options$mockOptions3, _options$mockOptions$4, _options$mockOptions4, _options$mockOptions$5, _options$mockOptions5, _options$mockOptions$6, _options$mockOptions6, _options$mockOptions$7, _options$mockOptions7, _options$mockOptions$8, _options$mockOptions8;
250
+ this.options = options;
251
+ this.lenses = /* @__PURE__ */ new Map();
252
+ if (!options.apiKey) throw new Error("API key is required");
253
+ if (!options.projectId) throw new Error("Project ID is required");
254
+ this.databaseStorage = (_options$mockOptions$ = (_options$mockOptions = options.mockOptions) === null || _options$mockOptions === void 0 ? void 0 : _options$mockOptions.databaseStorage) !== null && _options$mockOptions$ !== void 0 ? _options$mockOptions$ : new InMemoryMockDatabaseStorage();
255
+ this.imageStorage = (_options$mockOptions$2 = (_options$mockOptions2 = options.mockOptions) === null || _options$mockOptions2 === void 0 ? void 0 : _options$mockOptions2.imageStorage) !== null && _options$mockOptions$2 !== void 0 ? _options$mockOptions$2 : new InMemoryMockImageStorage();
256
+ this.createId = (_options$mockOptions$3 = (_options$mockOptions3 = options.mockOptions) === null || _options$mockOptions3 === void 0 ? void 0 : _options$mockOptions3.createId) !== null && _options$mockOptions$3 !== void 0 ? _options$mockOptions$3 : crypto.randomUUID.bind(crypto);
257
+ this.now = (_options$mockOptions$4 = (_options$mockOptions4 = options.mockOptions) === null || _options$mockOptions4 === void 0 ? void 0 : _options$mockOptions4.now) !== null && _options$mockOptions$4 !== void 0 ? _options$mockOptions$4 : Date.now;
258
+ this.queuedStatus = (_options$mockOptions$5 = (_options$mockOptions5 = options.mockOptions) === null || _options$mockOptions5 === void 0 ? void 0 : _options$mockOptions5.queuedStatus) !== null && _options$mockOptions$5 !== void 0 ? _options$mockOptions$5 : "pending";
259
+ this.analyzedStatus = (_options$mockOptions$6 = (_options$mockOptions6 = options.mockOptions) === null || _options$mockOptions6 === void 0 ? void 0 : _options$mockOptions6.analyzedStatus) !== null && _options$mockOptions$6 !== void 0 ? _options$mockOptions$6 : "approved";
260
+ this.apiKeyGrants = getMockApiKeyGrants(options.apiKey);
261
+ this.signedUrlBaseUrl = (_options$mockOptions$7 = (_options$mockOptions7 = options.mockOptions) === null || _options$mockOptions7 === void 0 ? void 0 : _options$mockOptions7.signedUrlBaseUrl) !== null && _options$mockOptions$7 !== void 0 ? _options$mockOptions$7 : "mock://calmlens";
262
+ this.cdnBaseUrl = (_options$mockOptions$8 = (_options$mockOptions8 = options.mockOptions) === null || _options$mockOptions8 === void 0 ? void 0 : _options$mockOptions8.cdnBaseUrl) !== null && _options$mockOptions$8 !== void 0 ? _options$mockOptions$8 : "mock://calmlens/v1";
263
+ }
264
+ get cdn() {
265
+ var _this = this;
266
+ return {
267
+ getAssetUrl: (_ref) => {
268
+ var _options$resource;
269
+ let { assetIdentifier } = _ref, options = require_CalmLensUtils._objectWithoutProperties(_ref, _excluded);
270
+ if (!assetIdentifier) throw new Error("Asset identifier is required");
271
+ const resource = (_options$resource = options.resource) !== null && _options$resource !== void 0 ? _options$resource : "content";
272
+ const url = `${this.cdnBaseUrl.replace(/\/$/, "")}/assets/${encodeURIComponent(this.options.projectId)}/${encodeURIComponent(assetIdentifier)}/${resource}`;
273
+ return appendCdnSelector(url, options);
274
+ },
275
+ serve: function() {
276
+ var _ref3 = require_CalmLensUtils._asyncToGenerator(function* (_ref2) {
277
+ var _asset$folderId, _await$this$databaseS, _this$databaseStorage, _this$databaseStorage2, _storedContent$type;
278
+ let { assetIdentifier } = _ref2, options = require_CalmLensUtils._objectWithoutProperties(_ref2, _excluded2);
279
+ if (!assetIdentifier) throw new Error("Asset identifier is required");
280
+ const asset = (yield _this.databaseStorage.listAssets(_this.options.projectId)).find((asset) => asset.id === assetIdentifier || asset.externalId === assetIdentifier);
281
+ if (!asset) return new Response("Asset not found", { status: 404 });
282
+ if (asset.visibility !== "public" && !permits(_this.apiKeyGrants, "assets:download", (_asset$folderId = asset.folderId) !== null && _asset$folderId !== void 0 ? _asset$folderId : null, (_await$this$databaseS = yield (_this$databaseStorage = (_this$databaseStorage2 = _this.databaseStorage).listFolders) === null || _this$databaseStorage === void 0 ? void 0 : _this$databaseStorage.call(_this$databaseStorage2, _this.options.projectId)) !== null && _await$this$databaseS !== void 0 ? _await$this$databaseS : [])) return new Response(JSON.stringify({
283
+ code: "asset/api-key-missing-permission",
284
+ message: "This API key needs assets:download permission for this asset’s folder."
285
+ }), {
286
+ status: 403,
287
+ headers: { "Content-Type": "application/json" }
288
+ });
289
+ const storedContent = yield _this.imageStorage.getContent(asset.id);
290
+ if (!storedContent) return new Response("Asset content not found", { status: 404 });
291
+ const parts = [...storedContent.parts.entries()].sort(([left], [right]) => left - right).map(([, value]) => value);
292
+ const byteLength = parts.reduce((sum, value) => sum + value.byteLength, 0);
293
+ const bytes = new Uint8Array(byteLength);
294
+ let offset = 0;
295
+ for (const part of parts) {
296
+ bytes.set(part, offset);
297
+ offset += part.byteLength;
298
+ }
299
+ return new Response(bytes, {
300
+ status: 200,
301
+ headers: {
302
+ "Content-Type": (_storedContent$type = storedContent.type) !== null && _storedContent$type !== void 0 ? _storedContent$type : "application/octet-stream",
303
+ "X-Mock-CalmLens-CDN-URL": _this.cdn.getAssetUrl(require_CalmLensUtils._objectSpread2({ assetIdentifier }, options))
304
+ }
305
+ });
306
+ });
307
+ return function serve(_x) {
308
+ return _ref3.apply(this, arguments);
309
+ };
310
+ }()
311
+ };
312
+ }
313
+ get events() {
314
+ var _this2 = this;
315
+ return {
316
+ /** The mock does not record events; it always returns an empty page at "now". */
317
+ list: function() {
318
+ var _ref4 = require_CalmLensUtils._asyncToGenerator(function* (options = {}) {
319
+ var _options$after;
320
+ return {
321
+ events: [],
322
+ cursor: (_options$after = options.after) !== null && _options$after !== void 0 ? _options$after : `${_this2.now()}_`,
323
+ hasMore: false
324
+ };
325
+ });
326
+ return function list() {
327
+ return _ref4.apply(this, arguments);
328
+ };
329
+ }() };
330
+ }
331
+ get text() {
332
+ var _this3 = this;
333
+ return { moderate: function() {
334
+ var _ref5 = require_CalmLensUtils._asyncToGenerator(function* (options) {
335
+ return _this3.assets.moderate(require_CalmLensUtils.toTextAssetOptions(options));
336
+ });
337
+ return function moderate(_x2) {
338
+ return _ref5.apply(this, arguments);
339
+ };
340
+ }() };
341
+ }
342
+ get assets() {
343
+ var _this4 = this;
344
+ return {
345
+ list: function() {
346
+ var _ref6 = require_CalmLensUtils._asyncToGenerator(function* (options) {
347
+ var _options$pageIndex;
348
+ const assets = yield _this4.databaseStorage.listAssets(_this4.options.projectId);
349
+ return createPage(assets, require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, options), {}, { pageIndex: (_options$pageIndex = options.pageIndex) !== null && _options$pageIndex !== void 0 ? _options$pageIndex : 0 }));
350
+ });
351
+ return function list(_x3) {
352
+ return _ref6.apply(this, arguments);
353
+ };
354
+ }(),
355
+ retrieve: function() {
356
+ var _ref7 = require_CalmLensUtils._asyncToGenerator(function* ({ assetId }) {
357
+ if (!assetId) throw new Error("Asset ID is required");
358
+ const asset = yield _this4.databaseStorage.getAsset(assetId);
359
+ if (!asset) throw new Error("Asset not found");
360
+ return asset;
361
+ });
362
+ return function retrieve(_x4) {
363
+ return _ref7.apply(this, arguments);
364
+ };
365
+ }(),
366
+ listChildren: function() {
367
+ var _ref9 = require_CalmLensUtils._asyncToGenerator(function* (_ref8) {
368
+ var _options$pageIndex2;
369
+ let { assetId } = _ref8, options = require_CalmLensUtils._objectWithoutProperties(_ref8, _excluded3);
370
+ if (!assetId) throw new Error("Asset ID is required");
371
+ const assets = yield _this4.databaseStorage.listAssets(_this4.options.projectId);
372
+ return createPage(assets.filter((asset) => asset.parentId === assetId), require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, options), {}, { pageIndex: (_options$pageIndex2 = options.pageIndex) !== null && _options$pageIndex2 !== void 0 ? _options$pageIndex2 : 0 }));
373
+ });
374
+ return function listChildren(_x5) {
375
+ return _ref9.apply(this, arguments);
376
+ };
377
+ }(),
378
+ create: function() {
379
+ var _ref10 = require_CalmLensUtils._asyncToGenerator(function* (options) {
380
+ return _this4.createAsset(options, _this4.queuedStatus);
381
+ });
382
+ return function create(_x6) {
383
+ return _ref10.apply(this, arguments);
384
+ };
385
+ }(),
386
+ moderate: function() {
387
+ var _ref11 = require_CalmLensUtils._asyncToGenerator(function* (options) {
388
+ if ("content" in options && "plainText" in options.content && (typeof options.content.plainText !== "string" || !options.content.plainText.trim())) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message: "Text to moderate must be a non-empty string" });
389
+ return _this4.createAsset(options, _this4.analyzedStatus);
390
+ });
391
+ return function moderate(_x7) {
392
+ return _ref11.apply(this, arguments);
393
+ };
394
+ }(),
395
+ uploadPart: function() {
396
+ var _ref12 = require_CalmLensUtils._asyncToGenerator(function* ({ assetId, part }) {
397
+ var _asset$uploadPartsRec;
398
+ if (!assetId) throw new Error("Asset ID is required");
399
+ if (!part) throw new Error("Part options are required");
400
+ const asset = yield _this4.databaseStorage.getAsset(assetId);
401
+ if (!asset) throw new Error("Asset not found");
402
+ const validation = require_CalmLensUtils.validateAssetPayload(part, {
403
+ multipart: true,
404
+ isFinal: part.isFinal
405
+ });
406
+ if (!validation.ok) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message: validation.error });
407
+ yield _this4.imageStorage.putPart(assetId, part);
408
+ const updated = require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, asset), {}, {
409
+ status: part.isFinal ? _this4.queuedStatus : "uploading",
410
+ uploadPartsReceived: Math.max((_asset$uploadPartsRec = asset.uploadPartsReceived) !== null && _asset$uploadPartsRec !== void 0 ? _asset$uploadPartsRec : 0, part.partNumber),
411
+ updatedAt: _this4.now()
412
+ });
413
+ return _this4.databaseStorage.updateAsset(updated);
414
+ });
415
+ return function uploadPart(_x8) {
416
+ return _ref12.apply(this, arguments);
417
+ };
418
+ }(),
419
+ createSignedUrl: function() {
420
+ var _ref14 = require_CalmLensUtils._asyncToGenerator(function* (_ref13) {
421
+ var _options$expiresInSec, _options$resource2;
422
+ let { assetId } = _ref13, options = require_CalmLensUtils._objectWithoutProperties(_ref13, _excluded4);
423
+ if (!assetId) throw new Error("Asset ID is required");
424
+ if (!(yield _this4.databaseStorage.getAsset(assetId))) throw new Error("Asset not found");
425
+ const expiresInSeconds = (_options$expiresInSec = options.expiresInSeconds) !== null && _options$expiresInSec !== void 0 ? _options$expiresInSec : 900;
426
+ const resource = (_options$resource2 = options.resource) !== null && _options$resource2 !== void 0 ? _options$resource2 : "content";
427
+ if (options.lens && options.transform) throw new Error("Specify either a lens or a transform, not both");
428
+ const selector = options.lens ? `&lens=${encodeURIComponent(options.lens)}` : options.transform ? `&transform=${encodeURIComponent(options.transform)}` : "";
429
+ return {
430
+ url: `${_this4.signedUrlBaseUrl}/assets/${assetId}/${resource}?expiresInSeconds=${expiresInSeconds}${selector}`,
431
+ expiresAt: _this4.now() + expiresInSeconds * 1e3
432
+ };
433
+ });
434
+ return function createSignedUrl(_x9) {
435
+ return _ref14.apply(this, arguments);
436
+ };
437
+ }(),
438
+ move: function() {
439
+ var _ref15 = require_CalmLensUtils._asyncToGenerator(function* ({ assetId, folderId }) {
440
+ if (!assetId) throw new Error("Asset ID is required");
441
+ const asset = yield _this4.databaseStorage.getAsset(assetId);
442
+ if (!asset || asset.projectId !== _this4.options.projectId) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.ASSET_NOT_FOUND);
443
+ if (folderId !== null && folderId !== void 0) {
444
+ if (!(yield _this4.resolveFolder(folderId))) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_FOUND);
445
+ }
446
+ const updated = require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, asset), {}, {
447
+ folderId: folderId !== null && folderId !== void 0 ? folderId : null,
448
+ updatedAt: _this4.now()
449
+ });
450
+ return _this4.databaseStorage.updateAsset(updated);
451
+ });
452
+ return function move(_x10) {
453
+ return _ref15.apply(this, arguments);
454
+ };
455
+ }(),
456
+ retry: function() {
457
+ var _ref16 = require_CalmLensUtils._asyncToGenerator(function* ({ assetId }) {
458
+ if (!assetId) throw new Error("Asset ID is required");
459
+ const asset = yield _this4.databaseStorage.getAsset(assetId);
460
+ if (!asset || asset.projectId !== _this4.options.projectId) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.ASSET_NOT_FOUND);
461
+ if (asset.status !== "error") throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.ASSET_NOT_RETRYABLE);
462
+ return _this4.databaseStorage.updateAsset(require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, asset), {}, {
463
+ status: "pending",
464
+ updatedAt: _this4.now()
465
+ }));
466
+ });
467
+ return function retry(_x11) {
468
+ return _ref16.apply(this, arguments);
469
+ };
470
+ }()
471
+ };
472
+ }
473
+ get folders() {
474
+ var _this5 = this;
475
+ return {
476
+ list: function() {
477
+ var _ref17 = require_CalmLensUtils._asyncToGenerator(function* () {
478
+ return [..._this5.databaseStorage.listFolders ? yield _this5.databaseStorage.listFolders(_this5.options.projectId) : []].sort((a, b) => a.name.localeCompare(b.name));
479
+ });
480
+ return function list() {
481
+ return _ref17.apply(this, arguments);
482
+ };
483
+ }(),
484
+ retrieve: function() {
485
+ var _ref18 = require_CalmLensUtils._asyncToGenerator(function* ({ folderId }) {
486
+ if (!folderId) throw new Error("Folder ID is required");
487
+ const folder = yield _this5.resolveFolder(folderId);
488
+ if (!folder) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_FOUND);
489
+ return folder;
490
+ });
491
+ return function retrieve(_x12) {
492
+ return _ref18.apply(this, arguments);
493
+ };
494
+ }(),
495
+ create: function() {
496
+ var _ref19 = require_CalmLensUtils._asyncToGenerator(function* (options) {
497
+ var _options$parentId, _options$parentId2;
498
+ if (!options.name) throw new Error("Folder name is required");
499
+ if (options.parentId) {
500
+ if (!(yield _this5.resolveFolder(options.parentId))) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_FOUND);
501
+ }
502
+ yield _this5.assertUniqueFolderName(options.name, (_options$parentId = options.parentId) !== null && _options$parentId !== void 0 ? _options$parentId : null);
503
+ const folder = {
504
+ id: _this5.createId(),
505
+ projectId: _this5.options.projectId,
506
+ parentId: (_options$parentId2 = options.parentId) !== null && _options$parentId2 !== void 0 ? _options$parentId2 : null,
507
+ name: options.name,
508
+ createdAt: _this5.now(),
509
+ updatedAt: _this5.now()
510
+ };
511
+ if (_this5.databaseStorage.createFolder) return yield _this5.databaseStorage.createFolder(folder);
512
+ return folder;
513
+ });
514
+ return function create(_x13) {
515
+ return _ref19.apply(this, arguments);
516
+ };
517
+ }(),
518
+ update: function() {
519
+ var _ref21 = require_CalmLensUtils._asyncToGenerator(function* (_ref20) {
520
+ let { folderId } = _ref20, body = require_CalmLensUtils._objectWithoutProperties(_ref20, _excluded5);
521
+ if (!folderId) throw new Error("Folder ID is required");
522
+ const folder = yield _this5.resolveFolder(folderId);
523
+ if (!folder) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_FOUND);
524
+ if (body.name !== void 0 && body.name !== folder.name) {
525
+ var _folder$parentId;
526
+ yield _this5.assertUniqueFolderName(body.name, (_folder$parentId = folder.parentId) !== null && _folder$parentId !== void 0 ? _folder$parentId : null, folderId);
527
+ }
528
+ const updated = require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, folder), body.name !== void 0 ? { name: body.name } : {}), {}, { updatedAt: _this5.now() });
529
+ if (_this5.databaseStorage.updateFolder) return yield _this5.databaseStorage.updateFolder(updated);
530
+ return updated;
531
+ });
532
+ return function update(_x14) {
533
+ return _ref21.apply(this, arguments);
534
+ };
535
+ }(),
536
+ delete: function() {
537
+ var _ref22 = require_CalmLensUtils._asyncToGenerator(function* ({ folderId }) {
538
+ if (!folderId) throw new Error("Folder ID is required");
539
+ if (!(yield _this5.resolveFolder(folderId))) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_FOUND);
540
+ const hasAssets = (yield _this5.databaseStorage.listAssets(_this5.options.projectId)).some((asset) => asset.folderId === folderId);
541
+ const hasChildren = (_this5.databaseStorage.listFolders ? yield _this5.databaseStorage.listFolders(_this5.options.projectId) : []).some((f) => f.parentId === folderId);
542
+ if (hasAssets || hasChildren) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_EMPTY, { details: {
543
+ hasAssets,
544
+ hasChildren
545
+ } });
546
+ if (_this5.databaseStorage.deleteFolder) yield _this5.databaseStorage.deleteFolder(folderId);
547
+ });
548
+ return function _delete(_x15) {
549
+ return _ref22.apply(this, arguments);
550
+ };
551
+ }(),
552
+ move: function() {
553
+ var _ref23 = require_CalmLensUtils._asyncToGenerator(function* ({ folderId, parentId }) {
554
+ if (!folderId) throw new Error("Folder ID is required");
555
+ const folder = yield _this5.resolveFolder(folderId);
556
+ if (!folder) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_FOUND);
557
+ const targetParentId = parentId !== null && parentId !== void 0 ? parentId : null;
558
+ if (targetParentId) {
559
+ const parent = yield _this5.resolveFolder(targetParentId);
560
+ if (!parent) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_NOT_FOUND);
561
+ let candidate = parent;
562
+ const visited = /* @__PURE__ */ new Set();
563
+ while (candidate) {
564
+ if (candidate.id === folderId || visited.has(candidate.id)) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.FOLDER_PARENT_CYCLE);
565
+ visited.add(candidate.id);
566
+ candidate = candidate.parentId ? yield _this5.resolveFolder(candidate.parentId) : void 0;
567
+ }
568
+ }
569
+ if (targetParentId !== folder.parentId) yield _this5.assertUniqueFolderName(folder.name, targetParentId, folderId);
570
+ const updated = require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, folder), {}, {
571
+ parentId: targetParentId,
572
+ updatedAt: _this5.now()
573
+ });
574
+ if (_this5.databaseStorage.updateFolder) return yield _this5.databaseStorage.updateFolder(updated);
575
+ return updated;
576
+ });
577
+ return function move(_x16) {
578
+ return _ref23.apply(this, arguments);
579
+ };
580
+ }()
581
+ };
582
+ }
583
+ ensureLens(options) {
584
+ var _this6 = this;
585
+ return require_CalmLensUtils._asyncToGenerator(function* () {
586
+ var _existing$description, _options$description, _existing$transforms, _options$transforms;
587
+ const existing = _this6.lenses.get(options.identifier);
588
+ if (!existing) {
589
+ const lens = require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({
590
+ id: _this6.createId(),
591
+ projectId: _this6.options.projectId,
592
+ userId: null
593
+ }, options), {}, {
594
+ createdAt: _this6.now(),
595
+ updatedAt: _this6.now()
596
+ });
597
+ _this6.lenses.set(lens.identifier, lens);
598
+ return lens;
599
+ }
600
+ if (existing.name === options.name && ((_existing$description = existing.description) !== null && _existing$description !== void 0 ? _existing$description : null) === ((_options$description = options.description) !== null && _options$description !== void 0 ? _options$description : null) && existing.type === options.type && existing.active === options.active && require_CalmLensUtils.stringifyJsonCanonical((_existing$transforms = existing.transforms) !== null && _existing$transforms !== void 0 ? _existing$transforms : null) === require_CalmLensUtils.stringifyJsonCanonical((_options$transforms = options.transforms) !== null && _options$transforms !== void 0 ? _options$transforms : null) && existing.version === options.version) return existing;
601
+ if (options.version > existing.version) {
602
+ const lens = require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2(require_CalmLensUtils._objectSpread2({}, existing), options), {}, { updatedAt: _this6.now() });
603
+ _this6.lenses.set(lens.identifier, lens);
604
+ return lens;
605
+ }
606
+ throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.LENS_VERSION_CONFLICT, { details: {
607
+ currentVersion: existing.version,
608
+ minimumVersion: existing.version + 1,
609
+ requestedVersion: options.version
610
+ } });
611
+ })();
612
+ }
613
+ ensureLenses({ lenses }) {
614
+ var _this7 = this;
615
+ return require_CalmLensUtils._asyncToGenerator(function* () {
616
+ if (lenses.length === 0) throw new Error("At least one lens is required");
617
+ return yield Promise.all(lenses.map((option) => _this7.ensureLens(option)));
618
+ })();
619
+ }
620
+ createAsset(options, status) {
621
+ var _this8 = this;
622
+ return require_CalmLensUtils._asyncToGenerator(function* () {
623
+ var _options$folderId, _options$visibility, _options$part$partNum;
624
+ if (!("content" in options) && !("url" in options) && !("part" in options)) throw new Error("Either file content, URL, or multipart part is required");
625
+ if (!options.name) throw new Error("Asset name is required");
626
+ if (!("part" in options) && "isFinal" in options) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message: "isFinal is only valid for multipart uploads" });
627
+ if ("part" in options && options.part.partNumber && options.part.partNumber > 1) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.USE_UPLOAD_PART);
628
+ if ("content" in options) {
629
+ assertValidUploadMimeType(options.content.type);
630
+ if (!("plainText" in options.content)) {
631
+ const validation = require_CalmLensUtils.validateAssetPayload(options.content);
632
+ if (!validation.ok) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message: validation.error });
633
+ }
634
+ }
635
+ if ("part" in options) {
636
+ assertValidUploadMimeType(options.part.type);
637
+ const validation = require_CalmLensUtils.validateAssetPayload(options.part, {
638
+ multipart: true,
639
+ isFinal: options.part.isFinal
640
+ });
641
+ if (!validation.ok) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message: validation.error });
642
+ }
643
+ const id = _this8.createId();
644
+ const now = _this8.now();
645
+ const type = inferAssetType(options);
646
+ const sizeInBytes = _this8.getSizeInBytes(options);
647
+ const asset = {
648
+ id,
649
+ projectId: _this8.options.projectId,
650
+ folderId: (_options$folderId = options.folderId) !== null && _options$folderId !== void 0 ? _options$folderId : null,
651
+ createdAt: now,
652
+ updatedAt: now,
653
+ name: options.name,
654
+ description: options.description,
655
+ externalId: options.externalId,
656
+ externalUrl: "url" in options ? options.url : "content" in options ? options.externalUrl : void 0,
657
+ type,
658
+ metadata: options.metadata,
659
+ status: "part" in options && !options.part.isFinal ? "uploading" : status,
660
+ processingOptions: options.processingOptions,
661
+ visibility: (_options$visibility = options.visibility) !== null && _options$visibility !== void 0 ? _options$visibility : "private",
662
+ sizeInBytes,
663
+ uploadPartsReceived: "part" in options ? (_options$part$partNum = options.part.partNumber) !== null && _options$part$partNum !== void 0 ? _options$part$partNum : 1 : void 0
664
+ };
665
+ if ("content" in options) {
666
+ if (!("plainText" in options.content)) yield _this8.imageStorage.putContent(id, options.content);
667
+ } else if ("part" in options) yield _this8.imageStorage.putPart(id, options.part);
668
+ return _this8.databaseStorage.createAsset(asset);
669
+ })();
670
+ }
671
+ resolveFolder(folderId) {
672
+ var _this9 = this;
673
+ return require_CalmLensUtils._asyncToGenerator(function* () {
674
+ if (!_this9.databaseStorage.getFolder) return void 0;
675
+ const folder = yield _this9.databaseStorage.getFolder(folderId);
676
+ if (!folder || folder.projectId !== _this9.options.projectId) return;
677
+ return folder;
678
+ })();
679
+ }
680
+ assertUniqueFolderName(name, parentId, excludeFolderId) {
681
+ var _this10 = this;
682
+ return require_CalmLensUtils._asyncToGenerator(function* () {
683
+ if ((_this10.databaseStorage.listFolders ? yield _this10.databaseStorage.listFolders(_this10.options.projectId) : []).find((f) => f.id !== excludeFolderId && f.parentId === (parentId !== null && parentId !== void 0 ? parentId : null) && f.name === name)) throw require_CalmLensUtils.calmLensError(require_CalmLensUtils.PUBLIC_ERROR_CODES.DUPLICATE_FOLDER_NAME, { message: `A folder named "${name}" already exists in this location.` });
684
+ })();
685
+ }
686
+ getSizeInBytes(options) {
687
+ if ("content" in options) {
688
+ if ("plainText" in options.content) return new TextEncoder().encode(options.content.plainText).byteLength;
689
+ return require_CalmLensUtils.getAssetPayloadByteLength(options.content);
690
+ }
691
+ if ("part" in options) {
692
+ var _options$sizeInBytes;
693
+ return (_options$sizeInBytes = options.sizeInBytes) !== null && _options$sizeInBytes !== void 0 ? _options$sizeInBytes : require_CalmLensUtils.getAssetPayloadByteLength(options.part);
694
+ }
695
+ }
696
+ };
697
+ //#endregion
698
+ exports.InMemoryMockDatabaseStorage = InMemoryMockDatabaseStorage;
699
+ exports.InMemoryMockImageStorage = InMemoryMockImageStorage;
700
+ exports.MOCK_API_KEY_PREFIX = MOCK_API_KEY_PREFIX;
701
+ exports.MockCalmLensClient = MockCalmLensClient;
702
+ exports.createMockApiKey = createMockApiKey;