@calmlens/sdk 0.11.0 → 0.13.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/README.md +73 -16
- package/cjs/CalmLensConnection-DzRDCMOP.js +233 -0
- package/cjs/CalmLensUtils-vX5H_vMn.js +699 -0
- package/cjs/CalmLensVersion-DjhsJ1gj.js +410 -0
- package/cjs/CalmLensWebhooks-hVquX5L1.js +201 -0
- package/cjs/WebhookPayload-B7CgSmI5.d.ts +11928 -0
- package/cjs/app.d.ts +43 -0
- package/cjs/app.js +91 -0
- package/cjs/index-BywTQbRq.d.ts +352 -0
- package/cjs/index.d.ts +3 -382
- package/cjs/index.js +4 -816
- package/cjs/server.d.ts +210 -0
- package/cjs/server.js +384 -0
- package/cjs/testing.d.ts +59 -18
- package/cjs/testing.js +245 -99
- package/esm/CalmLensConnection-D8VsTdsA.js +192 -0
- package/esm/CalmLensUtils-B4i3Z2He.js +574 -0
- package/esm/CalmLensVersion-DK4BMEST.js +345 -0
- package/esm/CalmLensWebhooks-DyCoEvpf.js +148 -0
- package/esm/WebhookPayload-B7CgSmI5.d.ts +11928 -0
- package/esm/app.d.ts +43 -0
- package/esm/app.js +87 -0
- package/esm/index-BywTQbRq.d.ts +352 -0
- package/esm/index.d.ts +3 -382
- package/esm/index.js +1 -807
- package/esm/server.d.ts +210 -0
- package/esm/server.js +374 -0
- package/esm/testing.d.ts +59 -18
- package/esm/testing.js +195 -49
- package/package.json +23 -1
- package/cjs/CalmLensTypes-BZ-nxhr_.d.ts +0 -8613
- package/cjs/CalmLensWebhooks-CH2PaPs0.js +0 -784
- package/esm/CalmLensTypes-BZ-nxhr_.d.ts +0 -8613
- package/esm/CalmLensWebhooks-3Otbubyf.js +0 -593
package/cjs/testing.js
CHANGED
|
@@ -21,7 +21,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
|
-
const
|
|
24
|
+
const require_CalmLensVersion = require("./CalmLensVersion-DjhsJ1gj.js");
|
|
25
|
+
const require_CalmLensWebhooks = require("./CalmLensWebhooks-hVquX5L1.js");
|
|
26
|
+
const require_CalmLensUtils = require("./CalmLensUtils-vX5H_vMn.js");
|
|
25
27
|
let zod = require("zod");
|
|
26
28
|
zod = __toESM(zod);
|
|
27
29
|
require("zod/v4");
|
|
@@ -58,60 +60,66 @@ const MODERATION_CATEGORY_DEFINITIONS = {
|
|
|
58
60
|
docsHref: "/docs/guides/moderation-categories#hate-and-identity-abuse"
|
|
59
61
|
},
|
|
60
62
|
"criminal-activity": {
|
|
61
|
-
summary: "Planning, assistance, instructions, encouragement or facilitation of a concrete criminal or seriously dangerous act.",
|
|
62
|
-
definition: "covers planning, requests for assistance, instructions, encouragement or facilitation of a concrete criminal or seriously dangerous act. A request can qualify even when no act occurs and a later reply refuses it. Dangerous activity requires a concrete serious risk of physical harm.",
|
|
63
|
-
exclusions: "Neutral reporting, prevention, lawful safety advice, fiction without criminal assistance, and vague dangerous references do not qualify. Masks, computers, payment cards, detention or ordinary tools do not establish criminal facilitation by themselves. A clear visual demonstration of how to carry out a crime can qualify.",
|
|
63
|
+
summary: "Planning, assistance, instructions, encouragement or facilitation of a concrete criminal or seriously dangerous act, and illegal drugs or contraband.",
|
|
64
|
+
definition: "covers planning, requests for assistance, instructions, encouragement or facilitation of a concrete criminal or seriously dangerous act. A request can qualify even when no act occurs and a later reply refuses it. Dangerous activity requires a concrete serious risk of physical harm. It also covers illegal drug use, dealing, production or trafficking, and contraband such as stolen goods, counterfeit money or documents and smuggled or illegally traded weapons.",
|
|
65
|
+
exclusions: "Neutral reporting, prevention, lawful safety advice, fiction without criminal assistance, and vague dangerous references do not qualify. Medical, pharmaceutical, clinical, research and educational content does not qualify, including prescriptions, dosages, side effects, controlled medicines used as prescribed, pharmacies, hospitals and drug manufacturing by pharmaceutical companies. Lawful alcohol and tobacco, harm reduction, addiction recovery and drug-policy discussion do not qualify either. Masks, computers, payment cards, detention or ordinary tools do not establish criminal facilitation by themselves. A clear visual demonstration of how to carry out a crime can qualify.",
|
|
64
66
|
docsHref: "/docs/guides/moderation-categories#criminal-and-dangerous-activity"
|
|
65
67
|
}
|
|
66
68
|
};
|
|
67
69
|
//#endregion
|
|
68
70
|
//#region ../shared/src/ModerationPolicyDimensions.ts
|
|
69
71
|
const MODERATION_QUALIFIERS = [
|
|
70
|
-
"nudity",
|
|
72
|
+
"sexual-nudity",
|
|
71
73
|
"sexual-activity",
|
|
72
|
-
"explicit-
|
|
74
|
+
"sexual-explicit-language",
|
|
73
75
|
"sexual-solicitation",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
76
|
+
"sexual-historical",
|
|
77
|
+
"sexual-documentary",
|
|
78
|
+
"sexual-fictional",
|
|
79
|
+
"sexual-support-prevention",
|
|
80
|
+
"violence-attack",
|
|
81
|
+
"violence-threat",
|
|
82
|
+
"violence-preparation",
|
|
83
|
+
"violence-encouragement",
|
|
84
|
+
"violence-injury",
|
|
85
|
+
"violence-death",
|
|
86
|
+
"violence-graphic",
|
|
87
|
+
"violence-historical",
|
|
88
|
+
"violence-documentary",
|
|
89
|
+
"violence-fictional",
|
|
90
|
+
"violence-support-prevention",
|
|
81
91
|
"self-harm-thoughts",
|
|
82
92
|
"self-harm-preparation",
|
|
83
93
|
"self-harm-act",
|
|
84
94
|
"self-harm-methods",
|
|
85
95
|
"self-harm-encouragement",
|
|
86
|
-
"
|
|
87
|
-
"
|
|
96
|
+
"self-harm-documentary",
|
|
97
|
+
"self-harm-fictional",
|
|
98
|
+
"self-harm-support-prevention",
|
|
99
|
+
"harassment-abuse",
|
|
100
|
+
"harassment-intimidation",
|
|
88
101
|
"harassment-threat",
|
|
89
|
-
"sexual
|
|
102
|
+
"harassment-sexual",
|
|
90
103
|
"harassment-encouragement",
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
104
|
+
"harassment-fictional",
|
|
105
|
+
"hate-abuse",
|
|
106
|
+
"hate-dehumanization",
|
|
107
|
+
"hate-inferiority",
|
|
108
|
+
"hate-exclusion",
|
|
95
109
|
"hate-threat",
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"criminal-
|
|
99
|
-
"criminal-
|
|
100
|
-
"criminal-
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
110
|
+
"hate-historical",
|
|
111
|
+
"hate-fictional",
|
|
112
|
+
"criminal-activity-demonstration",
|
|
113
|
+
"criminal-activity-preparation",
|
|
114
|
+
"criminal-activity-request",
|
|
115
|
+
"criminal-activity-instructions",
|
|
116
|
+
"criminal-activity-promotion",
|
|
117
|
+
"criminal-activity-substances",
|
|
118
|
+
"criminal-activity-fictional"
|
|
105
119
|
];
|
|
106
|
-
const SHARED_QUALIFIERS = [
|
|
107
|
-
"historical",
|
|
108
|
-
"documentary",
|
|
109
|
-
"fictional",
|
|
110
|
-
"support-prevention"
|
|
111
|
-
];
|
|
112
|
-
[...SHARED_QUALIFIERS], [...SHARED_QUALIFIERS], [...SHARED_QUALIFIERS], [...SHARED_QUALIFIERS], [...SHARED_QUALIFIERS], [...SHARED_QUALIFIERS];
|
|
113
120
|
//#endregion
|
|
114
121
|
//#region ../../node_modules/zod-meta/esm/index.js
|
|
122
|
+
const ZOD_META_KEY = "__zod_meta__";
|
|
115
123
|
const createMetaType = (type) => {
|
|
116
124
|
return Object.assign((value) => {
|
|
117
125
|
return {
|
|
@@ -120,7 +128,117 @@ const createMetaType = (type) => {
|
|
|
120
128
|
};
|
|
121
129
|
}, type);
|
|
122
130
|
};
|
|
123
|
-
|
|
131
|
+
const metaStore$1 = (meta) => {
|
|
132
|
+
const metaMap = meta.reduce((acc, meta) => {
|
|
133
|
+
if (meta) acc[meta.type.id] = meta;
|
|
134
|
+
return acc;
|
|
135
|
+
}, {});
|
|
136
|
+
return { [ZOD_META_KEY]: {
|
|
137
|
+
itemMap: metaMap,
|
|
138
|
+
get itemList() {
|
|
139
|
+
return Object.values(metaMap);
|
|
140
|
+
}
|
|
141
|
+
} };
|
|
142
|
+
};
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region ../shared/src/DocMetaTypes.ts
|
|
145
|
+
const docPropertyInfo = createMetaType({ id: "docPropertyInfo" });
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region ../shared/src/ProcessingFeatures.ts
|
|
148
|
+
/**
|
|
149
|
+
* Optional analyses a request can turn on with `processingOptions.features.<id>`. The catalog is
|
|
150
|
+
* the single source for the request and result schemas, cache keys and metering. Features are
|
|
151
|
+
* chosen per request only; there is no project-level default.
|
|
152
|
+
*/
|
|
153
|
+
/** How mature a feature is. Beta results may change shape. */
|
|
154
|
+
const PROCESSING_FEATURE_STAGES = ["beta", "ga"];
|
|
155
|
+
const createFeatureOptionsSchemas = (booleanSchema) => {
|
|
156
|
+
const enabled = booleanSchema.meta(metaStore$1([docPropertyInfo({ description: "Whether to run the feature. Every feature is off unless this is true." })]));
|
|
157
|
+
return {
|
|
158
|
+
ocr: zod.object({ enabled }).strict().meta(metaStore$1([docPropertyInfo({
|
|
159
|
+
description: "Extract image text into a child asset and run normal text moderation. Applies to images, including those extracted from multimedia documents and websites.",
|
|
160
|
+
namedType: "OcrFeatureOptions"
|
|
161
|
+
})])),
|
|
162
|
+
personDetection: zod.object({ enabled }).strict().meta(metaStore$1([docPropertyInfo({
|
|
163
|
+
description: "Beta. Locate people in images, including people whose faces are not visible. Results are informational and never change the moderation decision.",
|
|
164
|
+
namedType: "PersonDetectionFeatureOptions"
|
|
165
|
+
})])),
|
|
166
|
+
faceDetection: zod.object({
|
|
167
|
+
enabled,
|
|
168
|
+
ageEstimation: booleanSchema.optional().meta(metaStore$1([docPropertyInfo({
|
|
169
|
+
description: "Also estimate an age range for each face",
|
|
170
|
+
defaultValue: false
|
|
171
|
+
})]))
|
|
172
|
+
}).strict().meta(metaStore$1([docPropertyInfo({
|
|
173
|
+
description: "Beta. Locate faces in images and optionally estimate an age range for each. Faces are not identified or stored as biometric templates. Results are informational and never change the moderation decision.",
|
|
174
|
+
namedType: "FaceDetectionFeatureOptions"
|
|
175
|
+
})]))
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
const createProcessingFeaturesSchema = (booleanSchema) => {
|
|
179
|
+
const options = createFeatureOptionsSchemas(booleanSchema);
|
|
180
|
+
return zod.object({
|
|
181
|
+
ocr: options.ocr.nullish(),
|
|
182
|
+
personDetection: options.personDetection.nullish(),
|
|
183
|
+
faceDetection: options.faceDetection.nullish()
|
|
184
|
+
}).strict().meta(metaStore$1([docPropertyInfo({
|
|
185
|
+
description: "Optional analyses to run on this asset, keyed by feature. Unknown features are rejected.",
|
|
186
|
+
namedType: "ProcessingFeatures"
|
|
187
|
+
})]));
|
|
188
|
+
};
|
|
189
|
+
createProcessingFeaturesSchema(zod.boolean());
|
|
190
|
+
/** Position and size as fractions of the image width and height, from 0 to 1. */
|
|
191
|
+
const BOUNDING_BOX_SCHEMA = zod.object({
|
|
192
|
+
left: zod.number(),
|
|
193
|
+
top: zod.number(),
|
|
194
|
+
width: zod.number().min(0),
|
|
195
|
+
height: zod.number().min(0)
|
|
196
|
+
}).strict().meta(metaStore$1([docPropertyInfo({
|
|
197
|
+
description: "Position and size as fractions of the image width and height, from 0 to 1. `left` and `top` can be slightly negative when the subject extends past the edge.",
|
|
198
|
+
namedType: "BoundingBox"
|
|
199
|
+
})]));
|
|
200
|
+
const DETECTION_CONFIDENCE_SCHEMA = zod.number().min(0).max(1).describe("Detection confidence from 0 to 1");
|
|
201
|
+
const AGE_RANGE_SCHEMA = zod.object({
|
|
202
|
+
low: zod.number().int().nonnegative(),
|
|
203
|
+
high: zod.number().int().nonnegative()
|
|
204
|
+
}).strict().meta(metaStore$1([docPropertyInfo({
|
|
205
|
+
description: "Estimated age range in years. Estimates can be off by several years.",
|
|
206
|
+
namedType: "AgeRange"
|
|
207
|
+
})]));
|
|
208
|
+
const DETECTED_PERSON_SCHEMA = zod.object({
|
|
209
|
+
box: BOUNDING_BOX_SCHEMA,
|
|
210
|
+
confidence: DETECTION_CONFIDENCE_SCHEMA
|
|
211
|
+
}).strict().meta(metaStore$1([docPropertyInfo({
|
|
212
|
+
description: "A detected person",
|
|
213
|
+
namedType: "DetectedPerson"
|
|
214
|
+
})]));
|
|
215
|
+
const DETECTED_FACE_SCHEMA = zod.object({
|
|
216
|
+
box: BOUNDING_BOX_SCHEMA,
|
|
217
|
+
confidence: DETECTION_CONFIDENCE_SCHEMA,
|
|
218
|
+
ageRange: AGE_RANGE_SCHEMA.optional()
|
|
219
|
+
}).strict().meta(metaStore$1([docPropertyInfo({
|
|
220
|
+
description: "A detected face",
|
|
221
|
+
namedType: "DetectedFace"
|
|
222
|
+
})]));
|
|
223
|
+
const NOT_EVALUATED_FEATURE_RESULT_SCHEMA = zod.object({
|
|
224
|
+
status: zod.literal("not-evaluated"),
|
|
225
|
+
stage: zod.enum(PROCESSING_FEATURE_STAGES),
|
|
226
|
+
reason: zod.enum(["not-supported", "unavailable"])
|
|
227
|
+
}).strict();
|
|
228
|
+
const createFeatureResultSchema = (shape) => zod.discriminatedUnion("status", [zod.object({
|
|
229
|
+
status: zod.literal("evaluated"),
|
|
230
|
+
stage: zod.enum(PROCESSING_FEATURE_STAGES),
|
|
231
|
+
...shape
|
|
232
|
+
}).strict(), NOT_EVALUATED_FEATURE_RESULT_SCHEMA]);
|
|
233
|
+
const PERSON_DETECTION_RESULT_SCHEMA = createFeatureResultSchema({ people: zod.array(DETECTED_PERSON_SCHEMA) });
|
|
234
|
+
const FACE_DETECTION_RESULT_SCHEMA = createFeatureResultSchema({ faces: zod.array(DETECTED_FACE_SCHEMA) });
|
|
235
|
+
const PROCESSING_FEATURE_RESULTS_SCHEMA = zod.object({
|
|
236
|
+
personDetection: PERSON_DETECTION_RESULT_SCHEMA.optional(),
|
|
237
|
+
faceDetection: FACE_DETECTION_RESULT_SCHEMA.optional()
|
|
238
|
+
}).strict().meta(metaStore$1([docPropertyInfo({
|
|
239
|
+
description: "Results of the optional features requested in `processingOptions.features`, keyed by feature",
|
|
240
|
+
namedType: "ProcessingFeatureResults"
|
|
241
|
+
})]));
|
|
124
242
|
//#endregion
|
|
125
243
|
//#region ../shared/src/ZodUtils.ts
|
|
126
244
|
const SIZE_LIMITS = {
|
|
@@ -163,7 +281,11 @@ const LIKELIHOOD_SCHEMA = zod.enum([
|
|
|
163
281
|
"likely",
|
|
164
282
|
"very-likely"
|
|
165
283
|
]);
|
|
166
|
-
const CLASSIFICATION_NOT_EVALUATED_REASON_SCHEMA = zod.enum([
|
|
284
|
+
const CLASSIFICATION_NOT_EVALUATED_REASON_SCHEMA = zod.enum([
|
|
285
|
+
"not-supported",
|
|
286
|
+
"unavailable",
|
|
287
|
+
"not-requested"
|
|
288
|
+
]);
|
|
167
289
|
const CLASSIFICATION_QUALIFIER_RESULTS_SCHEMA = zod.partialRecord(zod.enum(MODERATION_QUALIFIERS), zod.discriminatedUnion("status", [zod.object({
|
|
168
290
|
status: zod.literal("evaluated"),
|
|
169
291
|
score: zod.number().min(0).max(1),
|
|
@@ -233,7 +355,8 @@ zod.object({
|
|
|
233
355
|
categories: CATEGORIES_SCHEMA
|
|
234
356
|
}).strict())
|
|
235
357
|
}).strict().optional(),
|
|
236
|
-
labels: zod.array(CLASSIFICATION_LABEL_SCHEMA).nullish()
|
|
358
|
+
labels: zod.array(CLASSIFICATION_LABEL_SCHEMA).nullish(),
|
|
359
|
+
features: PROCESSING_FEATURE_RESULTS_SCHEMA.optional()
|
|
237
360
|
}).strict();
|
|
238
361
|
//#endregion
|
|
239
362
|
//#region ../shared/src/MediaTestTriggers.ts
|
|
@@ -288,6 +411,10 @@ const ACTION_SCHEMA = zod.enum([
|
|
|
288
411
|
"metadata:write",
|
|
289
412
|
"lenses:read",
|
|
290
413
|
"lenses:write",
|
|
414
|
+
"upload-presets:read",
|
|
415
|
+
"upload-presets:write",
|
|
416
|
+
"reviews:read",
|
|
417
|
+
"reviews:write",
|
|
291
418
|
"project:manage"
|
|
292
419
|
]);
|
|
293
420
|
const PROJECT_ACTIONS = [...[
|
|
@@ -296,7 +423,9 @@ const PROJECT_ACTIONS = [...[
|
|
|
296
423
|
"api-keys",
|
|
297
424
|
"connectors",
|
|
298
425
|
"metadata",
|
|
299
|
-
"lenses"
|
|
426
|
+
"lenses",
|
|
427
|
+
"upload-presets",
|
|
428
|
+
"reviews"
|
|
300
429
|
].flatMap((feature) => [`${feature}:read`, `${feature}:write`]), "project:manage"];
|
|
301
430
|
const isProjectAction = (action) => PROJECT_ACTIONS.includes(action);
|
|
302
431
|
/** The actions that include `action`: its feature's write action and project:manage. */
|
|
@@ -309,7 +438,7 @@ const GRANT_SCHEMA = zod.object({
|
|
|
309
438
|
const GRANTS_SCHEMA = zod.array(GRANT_SCHEMA).max(100);
|
|
310
439
|
zod.enum([
|
|
311
440
|
"admin",
|
|
312
|
-
"
|
|
441
|
+
"editor",
|
|
313
442
|
"viewer",
|
|
314
443
|
"custom"
|
|
315
444
|
]);
|
|
@@ -357,9 +486,9 @@ var InMemoryMockImageStorage = class {
|
|
|
357
486
|
this.content = /* @__PURE__ */ new Map();
|
|
358
487
|
}
|
|
359
488
|
async putContent(assetId, content) {
|
|
360
|
-
const validation =
|
|
489
|
+
const validation = require_CalmLensUtils.validateAssetPayload(content);
|
|
361
490
|
if (!validation.ok) throw new Error(validation.error);
|
|
362
|
-
const bytes = await
|
|
491
|
+
const bytes = await require_CalmLensUtils.assetDataToUint8Array(require_CalmLensUtils.assetToData(content));
|
|
363
492
|
this.content.set(assetId, {
|
|
364
493
|
assetId,
|
|
365
494
|
parts: /* @__PURE__ */ new Map([[1, bytes]]),
|
|
@@ -367,12 +496,12 @@ var InMemoryMockImageStorage = class {
|
|
|
367
496
|
});
|
|
368
497
|
}
|
|
369
498
|
async putPart(assetId, part) {
|
|
370
|
-
const validation =
|
|
499
|
+
const validation = require_CalmLensUtils.validateAssetPayload(part, {
|
|
371
500
|
multipart: true,
|
|
372
501
|
isFinal: part.isFinal
|
|
373
502
|
});
|
|
374
503
|
if (!validation.ok) throw new Error(validation.error);
|
|
375
|
-
const bytes = await
|
|
504
|
+
const bytes = await require_CalmLensUtils.assetDataToUint8Array(require_CalmLensUtils.assetToData(part));
|
|
376
505
|
const existing = this.content.get(assetId) ?? {
|
|
377
506
|
assetId,
|
|
378
507
|
parts: /* @__PURE__ */ new Map(),
|
|
@@ -455,8 +584,8 @@ const inferAssetType = (options) => {
|
|
|
455
584
|
const createPage = (items, query) => {
|
|
456
585
|
const pageIndex = query.pageIndex ?? 0;
|
|
457
586
|
const pageSize = query.pageSize ?? 10;
|
|
458
|
-
if (!Number.isInteger(pageIndex) || pageIndex < 0) throw
|
|
459
|
-
if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > 100) throw
|
|
587
|
+
if (!Number.isInteger(pageIndex) || pageIndex < 0) throw require_CalmLensVersion.invalidArgument("pageIndex must be a non-negative integer");
|
|
588
|
+
if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > 100) throw require_CalmLensVersion.invalidArgument("pageSize must be an integer from 1 to 100");
|
|
460
589
|
const start = pageIndex * pageSize;
|
|
461
590
|
return {
|
|
462
591
|
items: items.slice(start, start + pageSize),
|
|
@@ -499,7 +628,7 @@ const parseFilterValue = (raw) => {
|
|
|
499
628
|
return value;
|
|
500
629
|
};
|
|
501
630
|
const readField = (item, path) => path.split(".").reduce((value, key) => value && typeof value === "object" ? value[key] : void 0, item);
|
|
502
|
-
const unsupportedFilter = (expression) =>
|
|
631
|
+
const unsupportedFilter = (expression) => require_CalmLensVersion.invalidArgument(`MockCalmLensServerClient cannot evaluate the filter "${expression}". It supports ==, !=, <, <=, >, >=, =in= and =out=, joined by ; (and) or , (or), without grouping parentheses.`);
|
|
503
632
|
const matchesComparison = (item, comparison) => {
|
|
504
633
|
const match = COMPARISON.exec(comparison.trim());
|
|
505
634
|
if (!match) throw unsupportedFilter(comparison);
|
|
@@ -556,7 +685,7 @@ const filterAssets = (items, filter) => {
|
|
|
556
685
|
return items.filter((item) => alternatives.some((conditions) => conditions.every((condition) => matchesComparison(item, condition))));
|
|
557
686
|
};
|
|
558
687
|
//#endregion
|
|
559
|
-
//#region src/testing/
|
|
688
|
+
//#region src/testing/MockCalmLensServerClient.ts
|
|
560
689
|
const DEFAULT_EVENTS_LIMIT = 50;
|
|
561
690
|
/** Stands in for binary payloads when comparing idempotent requests, like the API's size check. */
|
|
562
691
|
const describeBinary = (value) => {
|
|
@@ -567,14 +696,14 @@ const describeBinary = (value) => {
|
|
|
567
696
|
};
|
|
568
697
|
const MAX_EVENTS_LIMIT = 100;
|
|
569
698
|
const toFailureError = (failure) => {
|
|
570
|
-
if (failure === "transport-error") return new
|
|
699
|
+
if (failure === "transport-error") return new require_CalmLensVersion.CalmLensError(require_CalmLensVersion.SDK_ERROR_CODES.TRANSPORT_ERROR, {
|
|
571
700
|
message: "Request failed",
|
|
572
701
|
cause: /* @__PURE__ */ new TypeError("Simulated network failure")
|
|
573
702
|
});
|
|
574
703
|
if (failure === "timeout") {
|
|
575
704
|
const cause = /* @__PURE__ */ new Error("The operation timed out.");
|
|
576
705
|
cause.name = "TimeoutError";
|
|
577
|
-
return new
|
|
706
|
+
return new require_CalmLensVersion.CalmLensError(require_CalmLensVersion.SDK_ERROR_CODES.TIMEOUT, {
|
|
578
707
|
message: "Request timed out",
|
|
579
708
|
cause
|
|
580
709
|
});
|
|
@@ -582,12 +711,12 @@ const toFailureError = (failure) => {
|
|
|
582
711
|
return failure;
|
|
583
712
|
};
|
|
584
713
|
/**
|
|
585
|
-
* An in-memory stand-in for `
|
|
714
|
+
* An in-memory stand-in for `CalmLensServerClient` with the same methods, validation and error
|
|
586
715
|
* codes. API errors carry the HTTP status, a `requestId` and response headers like the real
|
|
587
716
|
* client's, so error handling can be tested without a network.
|
|
588
717
|
*/
|
|
589
|
-
var
|
|
590
|
-
/** Accepts the same options as `
|
|
718
|
+
var MockCalmLensServerClient = class {
|
|
719
|
+
/** Accepts the same options as `CalmLensServerClient` (validated the same way), plus `mockOptions`. */
|
|
591
720
|
constructor(options) {
|
|
592
721
|
this.lenses = /* @__PURE__ */ new Map();
|
|
593
722
|
this.eventFeed = [];
|
|
@@ -596,8 +725,9 @@ var MockCalmLensClient = class {
|
|
|
596
725
|
this.requestCount = 0;
|
|
597
726
|
this.pendingFailures = [];
|
|
598
727
|
this.calls = [];
|
|
599
|
-
|
|
728
|
+
require_CalmLensUtils.validateServerClientOptions(options);
|
|
600
729
|
this.projectId = options.projectId;
|
|
730
|
+
this.apiKey = options.apiKey;
|
|
601
731
|
this.databaseStorage = options.mockOptions?.databaseStorage ?? new InMemoryMockDatabaseStorage();
|
|
602
732
|
this.imageStorage = options.mockOptions?.imageStorage ?? new InMemoryMockImageStorage();
|
|
603
733
|
this.createId = options.mockOptions?.createId ?? crypto.randomUUID.bind(crypto);
|
|
@@ -610,7 +740,7 @@ var MockCalmLensClient = class {
|
|
|
610
740
|
}
|
|
611
741
|
/** Keeps the API key out of `console.log` and `util.inspect`. */
|
|
612
742
|
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
613
|
-
return `
|
|
743
|
+
return `MockCalmLensServerClient { projectId: ${JSON.stringify(this.projectId)} }`;
|
|
614
744
|
}
|
|
615
745
|
/**
|
|
616
746
|
* Makes the next call (or the next call to `operation`) throw `failure` instead of running,
|
|
@@ -647,9 +777,9 @@ var MockCalmLensClient = class {
|
|
|
647
777
|
}
|
|
648
778
|
/** An API error as the real client throws it: status, default message and request ID. */
|
|
649
779
|
apiError(code, options = {}) {
|
|
650
|
-
const definition =
|
|
780
|
+
const definition = require_CalmLensVersion.API_ERROR_DEFINITIONS[code];
|
|
651
781
|
const requestId = `mock-request-${++this.requestCount}`;
|
|
652
|
-
return new
|
|
782
|
+
return new require_CalmLensVersion.CalmLensError(code, {
|
|
653
783
|
message: options.message ?? definition.message,
|
|
654
784
|
status: definition.status,
|
|
655
785
|
details: options.details,
|
|
@@ -661,18 +791,18 @@ var MockCalmLensClient = class {
|
|
|
661
791
|
});
|
|
662
792
|
}
|
|
663
793
|
assertValidUploadMimeType(mimeType) {
|
|
664
|
-
if (
|
|
665
|
-
message:
|
|
794
|
+
if (require_CalmLensUtils.isRejectedUploadMimeType(mimeType)) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.INVALID_UPLOAD_MIME_TYPE, {
|
|
795
|
+
message: require_CalmLensUtils.getRejectedUploadMimeTypeError(mimeType),
|
|
666
796
|
details: { mimeType }
|
|
667
797
|
});
|
|
668
798
|
}
|
|
669
799
|
invalidPayload(message) {
|
|
670
|
-
return this.apiError(
|
|
800
|
+
return this.apiError(require_CalmLensVersion.API_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message });
|
|
671
801
|
}
|
|
672
802
|
async findOwnAsset(assetId) {
|
|
673
|
-
|
|
803
|
+
require_CalmLensUtils.encodePathSegment(assetId, "Asset ID");
|
|
674
804
|
const asset = await this.databaseStorage.getAsset(assetId);
|
|
675
|
-
if (!asset || asset.projectId !== this.projectId) throw this.apiError(
|
|
805
|
+
if (!asset || asset.projectId !== this.projectId) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.ASSET_NOT_FOUND);
|
|
676
806
|
return asset;
|
|
677
807
|
}
|
|
678
808
|
begin(operation, options) {
|
|
@@ -702,8 +832,8 @@ var MockCalmLensClient = class {
|
|
|
702
832
|
return {
|
|
703
833
|
getAssetUrl: ({ assetIdentifier, ...options }) => {
|
|
704
834
|
const resource = options.resource ?? "content";
|
|
705
|
-
const url = `${this.cdnBaseUrl}/assets/${encodeURIComponent(this.projectId)}/${
|
|
706
|
-
return
|
|
835
|
+
const url = `${this.cdnBaseUrl}/assets/${encodeURIComponent(this.projectId)}/${require_CalmLensUtils.encodePathSegment(assetIdentifier, "Asset identifier")}/${resource}`;
|
|
836
|
+
return require_CalmLensUtils.appendCdnSelector(url, options);
|
|
707
837
|
},
|
|
708
838
|
/**
|
|
709
839
|
* Serves stored content like the CDN: `200` with `Content-Type`, `Content-Length`,
|
|
@@ -771,7 +901,7 @@ var MockCalmLensClient = class {
|
|
|
771
901
|
}
|
|
772
902
|
listEvents(options) {
|
|
773
903
|
const limit = options.limit ?? DEFAULT_EVENTS_LIMIT;
|
|
774
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_EVENTS_LIMIT) throw this.apiError(
|
|
904
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_EVENTS_LIMIT) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message: `limit must be an integer from 1 to ${MAX_EVENTS_LIMIT}` });
|
|
775
905
|
if (!options.after) return {
|
|
776
906
|
events: [],
|
|
777
907
|
cursor: `mock_${this.eventFeed.length}`,
|
|
@@ -779,7 +909,7 @@ var MockCalmLensClient = class {
|
|
|
779
909
|
};
|
|
780
910
|
const match = /^mock_(\d+)$/.exec(options.after);
|
|
781
911
|
const position = match ? Number(match[1]) : NaN;
|
|
782
|
-
if (!Number.isSafeInteger(position) || position > this.eventFeed.length) throw this.apiError(
|
|
912
|
+
if (!Number.isSafeInteger(position) || position > this.eventFeed.length) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.INVALID_EVENT_CURSOR);
|
|
783
913
|
const events = this.eventFeed.slice(position, position + limit);
|
|
784
914
|
const next = position + events.length;
|
|
785
915
|
return {
|
|
@@ -810,7 +940,7 @@ var MockCalmLensClient = class {
|
|
|
810
940
|
get text() {
|
|
811
941
|
return { moderate: async (options) => {
|
|
812
942
|
this.begin("text.moderate", options);
|
|
813
|
-
return this.moderateAsset(
|
|
943
|
+
return this.moderateAsset(require_CalmLensUtils.toTextAssetOptions(options), "text.moderate");
|
|
814
944
|
} };
|
|
815
945
|
}
|
|
816
946
|
get assets() {
|
|
@@ -869,7 +999,7 @@ var MockCalmLensClient = class {
|
|
|
869
999
|
listChildren: async (childrenOptions = {}) => {
|
|
870
1000
|
this.begin("assets.listChildren", childrenOptions);
|
|
871
1001
|
const { assetId, ...options } = childrenOptions;
|
|
872
|
-
|
|
1002
|
+
require_CalmLensUtils.encodePathSegment(assetId, "Asset ID");
|
|
873
1003
|
const assets = await this.databaseStorage.listAssets(this.projectId);
|
|
874
1004
|
return createPage(orderItems(assets.filter((asset) => asset.parentId === assetId), options.ordering), {
|
|
875
1005
|
...options,
|
|
@@ -877,7 +1007,7 @@ var MockCalmLensClient = class {
|
|
|
877
1007
|
});
|
|
878
1008
|
},
|
|
879
1009
|
iterateChildren: (options) => {
|
|
880
|
-
|
|
1010
|
+
require_CalmLensUtils.encodePathSegment(options?.assetId, "Asset ID");
|
|
881
1011
|
return this.iteratePages((pageIndex) => this.assets.listChildren({
|
|
882
1012
|
...options,
|
|
883
1013
|
pageIndex
|
|
@@ -906,18 +1036,18 @@ var MockCalmLensClient = class {
|
|
|
906
1036
|
uploadPart: async (options) => {
|
|
907
1037
|
this.begin("assets.uploadPart", options);
|
|
908
1038
|
const { assetId, part } = options;
|
|
909
|
-
|
|
910
|
-
if (!part) throw
|
|
1039
|
+
require_CalmLensUtils.encodePathSegment(assetId, "Asset ID");
|
|
1040
|
+
if (!part) throw require_CalmLensVersion.invalidArgument("Part options are required");
|
|
911
1041
|
return this.withIdempotency("assets.uploadPart", options, async () => {
|
|
912
1042
|
const asset = await this.findOwnAsset(assetId);
|
|
913
|
-
const validation =
|
|
1043
|
+
const validation = require_CalmLensUtils.validateAssetPayload(part, {
|
|
914
1044
|
multipart: true,
|
|
915
1045
|
isFinal: part.isFinal
|
|
916
1046
|
});
|
|
917
1047
|
if (!validation.ok) throw this.invalidPayload(validation.error);
|
|
918
|
-
if (asset.status !== "uploading") throw this.apiError(
|
|
1048
|
+
if (asset.status !== "uploading") throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.UPLOAD_NOT_OPEN);
|
|
919
1049
|
const expectedPartNumber = (asset.uploadPartsReceived ?? 1) + 1;
|
|
920
|
-
if (part.partNumber !== expectedPartNumber) throw this.apiError(
|
|
1050
|
+
if (part.partNumber !== expectedPartNumber) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.INVALID_UPLOAD_PART_NUMBER, { details: { expectedPartNumber } });
|
|
921
1051
|
await this.imageStorage.putPart(assetId, part);
|
|
922
1052
|
const queue = options.queue ?? this.uploadQueues.get(assetId) ?? false;
|
|
923
1053
|
if (part.isFinal) this.uploadQueues.delete(assetId);
|
|
@@ -933,10 +1063,10 @@ var MockCalmLensClient = class {
|
|
|
933
1063
|
this.begin("assets.createSignedUrl", signedUrlOptions);
|
|
934
1064
|
const { assetId, ...options } = signedUrlOptions;
|
|
935
1065
|
const asset = await this.findOwnAsset(assetId);
|
|
936
|
-
if (options.lens && options.transform) throw
|
|
1066
|
+
if (options.lens && options.transform) throw require_CalmLensVersion.invalidArgument("Specify either a lens or a transform, not both");
|
|
937
1067
|
const expiresInSeconds = options.expiresInSeconds ?? 900;
|
|
938
1068
|
const resource = options.resource ?? "content";
|
|
939
|
-
const transform =
|
|
1069
|
+
const transform = require_CalmLensUtils.transformSelector(options.transform);
|
|
940
1070
|
const selector = options.lens ? `&lens=${encodeURIComponent(options.lens)}` : transform ? `&transform=${encodeURIComponent(transform)}` : "";
|
|
941
1071
|
return {
|
|
942
1072
|
url: `${this.signedUrlBaseUrl}/assets/${asset.id}/${resource}?expiresInSeconds=${expiresInSeconds}${selector}`,
|
|
@@ -948,7 +1078,7 @@ var MockCalmLensClient = class {
|
|
|
948
1078
|
const { assetId, folderId } = options;
|
|
949
1079
|
const asset = await this.findOwnAsset(assetId);
|
|
950
1080
|
if (folderId !== null && folderId !== void 0) {
|
|
951
|
-
if (!await this.resolveFolder(folderId)) throw this.apiError(
|
|
1081
|
+
if (!await this.resolveFolder(folderId)) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.FOLDER_NOT_FOUND);
|
|
952
1082
|
}
|
|
953
1083
|
return this.databaseStorage.updateAsset({
|
|
954
1084
|
...asset,
|
|
@@ -959,14 +1089,20 @@ var MockCalmLensClient = class {
|
|
|
959
1089
|
retry: async (options) => {
|
|
960
1090
|
this.begin("assets.retry", options);
|
|
961
1091
|
const asset = await this.findOwnAsset(options?.assetId);
|
|
962
|
-
if (asset.status !== "error") throw this.apiError(
|
|
963
|
-
if (asset.storageDeletedAt) throw this.apiError(
|
|
1092
|
+
if (asset.status !== "error") throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.ASSET_NOT_RETRYABLE);
|
|
1093
|
+
if (asset.storageDeletedAt) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.ASSET_CONTENT_UNAVAILABLE);
|
|
964
1094
|
return this.databaseStorage.updateAsset({
|
|
965
1095
|
...asset,
|
|
966
1096
|
status: "pending",
|
|
967
1097
|
updatedAt: this.now()
|
|
968
1098
|
});
|
|
969
1099
|
},
|
|
1100
|
+
/** Waits like the real client, checking the mock's storage for a decision. */
|
|
1101
|
+
waitForDecision: async (options) => {
|
|
1102
|
+
this.begin("assets.waitForDecision", options);
|
|
1103
|
+
const { assetId, ...waitOptions } = options;
|
|
1104
|
+
return require_CalmLensUtils.pollForDecision(() => this.findOwnAsset(assetId), waitOptions, require_CalmLensUtils.sleep);
|
|
1105
|
+
},
|
|
970
1106
|
deleteContent: async (options) => {
|
|
971
1107
|
this.begin("assets.deleteContent", options);
|
|
972
1108
|
const asset = await this.findOwnAsset(options?.assetId);
|
|
@@ -986,6 +1122,16 @@ var MockCalmLensClient = class {
|
|
|
986
1122
|
}
|
|
987
1123
|
};
|
|
988
1124
|
}
|
|
1125
|
+
/** Signs real upload tokens with the mock's API key, like the real client, without a request. */
|
|
1126
|
+
get uploadTokens() {
|
|
1127
|
+
return { sign: async (options) => {
|
|
1128
|
+
this.begin("uploadTokens.sign", options);
|
|
1129
|
+
return require_CalmLensWebhooks.signUploadTokenWithApiKey(this.apiKey, options, {
|
|
1130
|
+
now: this.now(),
|
|
1131
|
+
nonce: this.createId()
|
|
1132
|
+
});
|
|
1133
|
+
} };
|
|
1134
|
+
}
|
|
989
1135
|
get folders() {
|
|
990
1136
|
return {
|
|
991
1137
|
list: async () => {
|
|
@@ -1029,7 +1175,7 @@ var MockCalmLensClient = class {
|
|
|
1029
1175
|
await this.findOwnFolder(folderId);
|
|
1030
1176
|
const hasAssets = (await this.databaseStorage.listAssets(this.projectId)).some((asset) => asset.folderId === folderId);
|
|
1031
1177
|
const hasChildren = (this.databaseStorage.listFolders ? await this.databaseStorage.listFolders(this.projectId) : []).some((f) => f.parentId === folderId);
|
|
1032
|
-
if (hasAssets || hasChildren) throw this.apiError(
|
|
1178
|
+
if (hasAssets || hasChildren) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.FOLDER_NOT_EMPTY, { details: {
|
|
1033
1179
|
hasAssets,
|
|
1034
1180
|
hasChildren
|
|
1035
1181
|
} });
|
|
@@ -1044,7 +1190,7 @@ var MockCalmLensClient = class {
|
|
|
1044
1190
|
let candidate = await this.findOwnFolder(targetParentId);
|
|
1045
1191
|
const visited = /* @__PURE__ */ new Set();
|
|
1046
1192
|
while (candidate) {
|
|
1047
|
-
if (candidate.id === folderId || visited.has(candidate.id)) throw this.apiError(
|
|
1193
|
+
if (candidate.id === folderId || visited.has(candidate.id)) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.FOLDER_PARENT_CYCLE);
|
|
1048
1194
|
visited.add(candidate.id);
|
|
1049
1195
|
candidate = candidate.parentId ? await this.resolveFolder(candidate.parentId) : void 0;
|
|
1050
1196
|
}
|
|
@@ -1061,7 +1207,7 @@ var MockCalmLensClient = class {
|
|
|
1061
1207
|
}
|
|
1062
1208
|
async ensureLens(options) {
|
|
1063
1209
|
this.begin("ensureLens", options);
|
|
1064
|
-
if (!options?.identifier) throw
|
|
1210
|
+
if (!options?.identifier) throw require_CalmLensVersion.invalidArgument("Lens identifier is required");
|
|
1065
1211
|
return this.ensureLensDefinition(options);
|
|
1066
1212
|
}
|
|
1067
1213
|
ensureLensDefinition(options) {
|
|
@@ -1088,7 +1234,7 @@ var MockCalmLensClient = class {
|
|
|
1088
1234
|
this.lenses.set(lens.identifier, lens);
|
|
1089
1235
|
return lens;
|
|
1090
1236
|
}
|
|
1091
|
-
throw this.apiError(
|
|
1237
|
+
throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.LENS_VERSION_CONFLICT, { details: {
|
|
1092
1238
|
currentVersion: existing.version,
|
|
1093
1239
|
minimumVersion: existing.version + 1,
|
|
1094
1240
|
requestedVersion: options.version
|
|
@@ -1096,19 +1242,19 @@ var MockCalmLensClient = class {
|
|
|
1096
1242
|
}
|
|
1097
1243
|
async ensureLenses(options) {
|
|
1098
1244
|
this.begin("ensureLenses", options);
|
|
1099
|
-
if (!Array.isArray(options?.lenses) || options.lenses.length === 0) throw
|
|
1100
|
-
if (options.lenses.some((lens) => !lens?.identifier)) throw
|
|
1245
|
+
if (!Array.isArray(options?.lenses) || options.lenses.length === 0) throw require_CalmLensVersion.invalidArgument("At least one lens is required");
|
|
1246
|
+
if (options.lenses.some((lens) => !lens?.identifier)) throw require_CalmLensVersion.invalidArgument("Lens identifier is required");
|
|
1101
1247
|
return options.lenses.map((option) => this.ensureLensDefinition(option));
|
|
1102
1248
|
}
|
|
1103
1249
|
/** Replays the first result for a reused idempotency key, like the API. */
|
|
1104
1250
|
async withIdempotency(operation, options, run) {
|
|
1105
1251
|
const key = options?.idempotencyKey;
|
|
1106
1252
|
if (key === void 0) return run();
|
|
1107
|
-
if (!key || key.length > 255 || !/^[\x21-\x7e]+$/.test(key)) throw this.apiError(
|
|
1253
|
+
if (!key || key.length > 255 || !/^[\x21-\x7e]+$/.test(key)) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.INVALID_IDEMPOTENCY_KEY);
|
|
1108
1254
|
const fingerprint = `${operation}:${require_CalmLensWebhooks.stringifyJsonCanonical(JSON.parse(JSON.stringify(options, (_key, value) => describeBinary(value))))}`;
|
|
1109
1255
|
const saved = this.idempotentResults.get(key);
|
|
1110
1256
|
if (saved) {
|
|
1111
|
-
if (saved.fingerprint !== fingerprint) throw this.apiError(
|
|
1257
|
+
if (saved.fingerprint !== fingerprint) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.IDEMPOTENCY_KEY_REUSED);
|
|
1112
1258
|
return saved.asset;
|
|
1113
1259
|
}
|
|
1114
1260
|
const asset = await run();
|
|
@@ -1123,28 +1269,28 @@ var MockCalmLensClient = class {
|
|
|
1123
1269
|
return this.withIdempotency(operation, options, () => this.createAsset(options, false));
|
|
1124
1270
|
}
|
|
1125
1271
|
async createAsset(options, queue) {
|
|
1126
|
-
if (!options || typeof options !== "object") throw
|
|
1272
|
+
if (!options || typeof options !== "object") throw require_CalmLensVersion.invalidArgument("Asset options are required");
|
|
1127
1273
|
if (!("content" in options) && !("url" in options) && !("part" in options)) throw this.invalidPayload("Either file content, URL, or multipart part is required");
|
|
1128
1274
|
if (!options.name) throw this.invalidPayload("Asset name is required");
|
|
1129
1275
|
if (!("part" in options) && "isFinal" in options) throw this.invalidPayload("isFinal is only valid for multipart uploads");
|
|
1130
|
-
if ("part" in options && options.part.partNumber && options.part.partNumber > 1) throw this.apiError(
|
|
1276
|
+
if ("part" in options && options.part.partNumber && options.part.partNumber > 1) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.USE_UPLOAD_PART);
|
|
1131
1277
|
if ("content" in options) {
|
|
1132
1278
|
this.assertValidUploadMimeType(options.content.type);
|
|
1133
1279
|
if (!("plainText" in options.content)) {
|
|
1134
|
-
const validation =
|
|
1280
|
+
const validation = require_CalmLensUtils.validateAssetPayload(options.content);
|
|
1135
1281
|
if (!validation.ok) throw this.invalidPayload(validation.error);
|
|
1136
1282
|
}
|
|
1137
1283
|
}
|
|
1138
1284
|
if ("part" in options) {
|
|
1139
1285
|
this.assertValidUploadMimeType(options.part.type);
|
|
1140
|
-
const validation =
|
|
1286
|
+
const validation = require_CalmLensUtils.validateAssetPayload(options.part, {
|
|
1141
1287
|
multipart: true,
|
|
1142
1288
|
isFinal: options.part.isFinal
|
|
1143
1289
|
});
|
|
1144
1290
|
if (!validation.ok) throw this.invalidPayload(validation.error);
|
|
1145
1291
|
}
|
|
1146
1292
|
if (options.externalId) {
|
|
1147
|
-
if ((await this.databaseStorage.listAssets(this.projectId)).some((asset) => asset.externalId === options.externalId)) throw this.apiError(
|
|
1293
|
+
if ((await this.databaseStorage.listAssets(this.projectId)).some((asset) => asset.externalId === options.externalId)) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.DUPLICATE_EXTERNAL_ID);
|
|
1148
1294
|
}
|
|
1149
1295
|
const id = this.createId();
|
|
1150
1296
|
const now = this.now();
|
|
@@ -1182,20 +1328,20 @@ var MockCalmLensClient = class {
|
|
|
1182
1328
|
return folder;
|
|
1183
1329
|
}
|
|
1184
1330
|
async findOwnFolder(folderId) {
|
|
1185
|
-
|
|
1331
|
+
require_CalmLensUtils.encodePathSegment(folderId, "Folder ID");
|
|
1186
1332
|
const folder = await this.resolveFolder(folderId);
|
|
1187
|
-
if (!folder) throw this.apiError(
|
|
1333
|
+
if (!folder) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.FOLDER_NOT_FOUND);
|
|
1188
1334
|
return folder;
|
|
1189
1335
|
}
|
|
1190
1336
|
async assertUniqueFolderName(name, parentId, excludeFolderId) {
|
|
1191
|
-
if ((this.databaseStorage.listFolders ? await this.databaseStorage.listFolders(this.projectId) : []).find((f) => f.id !== excludeFolderId && f.parentId === (parentId ?? null) && f.name === name)) throw this.apiError(
|
|
1337
|
+
if ((this.databaseStorage.listFolders ? await this.databaseStorage.listFolders(this.projectId) : []).find((f) => f.id !== excludeFolderId && f.parentId === (parentId ?? null) && f.name === name)) throw this.apiError(require_CalmLensVersion.API_ERROR_CODES.DUPLICATE_FOLDER_NAME, { message: `A folder named "${name}" already exists in this location.` });
|
|
1192
1338
|
}
|
|
1193
1339
|
getSizeInBytes(options) {
|
|
1194
1340
|
if ("content" in options) {
|
|
1195
1341
|
if ("plainText" in options.content) return new TextEncoder().encode(options.content.plainText).byteLength;
|
|
1196
|
-
return
|
|
1342
|
+
return require_CalmLensUtils.getAssetPayloadByteLength(options.content);
|
|
1197
1343
|
}
|
|
1198
|
-
if ("part" in options) return options.part.sizeInBytes ?? options.sizeInBytes ??
|
|
1344
|
+
if ("part" in options) return options.part.sizeInBytes ?? options.sizeInBytes ?? require_CalmLensUtils.getAssetPayloadByteLength(options.part);
|
|
1199
1345
|
}
|
|
1200
1346
|
};
|
|
1201
1347
|
//#endregion
|
|
@@ -1232,7 +1378,7 @@ exports.InMemoryMockDatabaseStorage = InMemoryMockDatabaseStorage;
|
|
|
1232
1378
|
exports.InMemoryMockImageStorage = InMemoryMockImageStorage;
|
|
1233
1379
|
exports.MEDIA_TEST_SIGNALS = MEDIA_TEST_SIGNALS;
|
|
1234
1380
|
exports.MOCK_API_KEY_PREFIX = MOCK_API_KEY_PREFIX;
|
|
1235
|
-
exports.
|
|
1381
|
+
exports.MockCalmLensServerClient = MockCalmLensServerClient;
|
|
1236
1382
|
exports.createMockApiKey = createMockApiKey;
|
|
1237
1383
|
exports.createWebhookHeaders = createWebhookHeaders;
|
|
1238
1384
|
exports.createWebhookSignatureHeader = createWebhookSignatureHeader;
|