@calmlens/sdk 0.12.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 +14 -1
- package/cjs/CalmLensConnection-DzRDCMOP.js +233 -0
- package/cjs/CalmLensUtils-vX5H_vMn.js +699 -0
- package/cjs/{CalmLensError-CKwMKV0S.js → CalmLensVersion-DjhsJ1gj.js} +48 -0
- package/cjs/{CalmLensWebhooks-BTPxKvcD.js → CalmLensWebhooks-hVquX5L1.js} +9 -9
- package/cjs/{WebhookPayload-Cgb32aSH.d.ts → WebhookPayload-B7CgSmI5.d.ts} +4996 -3255
- package/cjs/app.d.ts +3 -3
- package/cjs/app.js +10 -10
- package/cjs/{index-BgmWj3KL.d.ts → index-BywTQbRq.d.ts} +3 -1
- package/cjs/index.d.ts +3 -3
- package/cjs/index.js +4 -5
- package/cjs/server.d.ts +12 -4
- package/cjs/server.js +31 -18
- package/cjs/testing.d.ts +6 -1
- package/cjs/testing.js +91 -73
- package/esm/CalmLensConnection-D8VsTdsA.js +192 -0
- package/esm/{CalmLensUtils-Cx32j2zt.js → CalmLensUtils-B4i3Z2He.js} +316 -2
- package/esm/{CalmLensError-CihGG26K.js → CalmLensVersion-DK4BMEST.js} +25 -1
- package/esm/{CalmLensWebhooks-DShmAal4.js → CalmLensWebhooks-DyCoEvpf.js} +2 -2
- package/esm/{WebhookPayload-Cgb32aSH.d.ts → WebhookPayload-B7CgSmI5.d.ts} +4996 -3255
- package/esm/app.d.ts +3 -3
- package/esm/app.js +4 -4
- package/esm/{index-BgmWj3KL.d.ts → index-BywTQbRq.d.ts} +3 -1
- package/esm/index.d.ts +3 -3
- package/esm/index.js +1 -3
- package/esm/server.d.ts +12 -4
- package/esm/server.js +20 -7
- package/esm/testing.d.ts +6 -1
- package/esm/testing.js +59 -41
- package/package.json +1 -1
- package/cjs/CalmLensConnection-CYtBP-vu.js +0 -516
- package/cjs/CalmLensUtils-Dg3s4loH.js +0 -367
- package/cjs/src-Dsc8Pn6v.js +0 -45
- package/esm/CalmLensConnection-wLNy0OIP.js +0 -475
- package/esm/src-CJhrILvM.js +0 -22
|
@@ -11,6 +11,7 @@ const API_ERROR_CODES = {
|
|
|
11
11
|
MULTIPART_IMAGE_TOO_LARGE: "upload/multipart-image-too-large",
|
|
12
12
|
IMAGE_EXCEEDED_MAX_DIMENSIONS: "upload/image-exceeded-max-dimensions",
|
|
13
13
|
UPLOAD_LIMIT_EXCEEDED: "upload/limit-exceeded",
|
|
14
|
+
SPEND_LIMIT_REACHED: "upload/spend-limit-reached",
|
|
14
15
|
INVALID_UPLOAD_MIME_TYPE: "upload/invalid-mime-type",
|
|
15
16
|
INVALID_EVENT_CURSOR: "events/invalid-cursor",
|
|
16
17
|
INVALID_UPLOAD_PAYLOAD: "upload/invalid-payload",
|
|
@@ -89,6 +90,10 @@ const API_ERROR_DEFINITIONS = {
|
|
|
89
90
|
status: 403,
|
|
90
91
|
message: "Upload limit exceeded. You have used all your free uploads. Please upgrade to Plus or Pro for unlimited uploads."
|
|
91
92
|
},
|
|
93
|
+
"upload/spend-limit-reached": {
|
|
94
|
+
status: 402,
|
|
95
|
+
message: "The project owner's spend limit for this billing period has been reached. Raise the limit in Billing to resume uploads."
|
|
96
|
+
},
|
|
92
97
|
"upload/invalid-mime-type": {
|
|
93
98
|
status: 400,
|
|
94
99
|
message: "Upload file type is not supported. Uploads must use a concrete file MIME type that CalmLens can store and process, such as image/png, image/jpeg, application/pdf, or text/plain."
|
|
@@ -318,6 +323,25 @@ const invalidArgument = (message, details) => new CalmLensError(SDK_ERROR_CODES.
|
|
|
318
323
|
});
|
|
319
324
|
const invalidConfig = (message) => new CalmLensError(SDK_ERROR_CODES.INVALID_CONFIG, { message });
|
|
320
325
|
//#endregion
|
|
326
|
+
//#region src/client/CalmLensVersion.ts
|
|
327
|
+
/** This SDK's version, from its package.json. */
|
|
328
|
+
const SDK_VERSION = "0.13.0";
|
|
329
|
+
const runtimeName = () => {
|
|
330
|
+
const runtime = globalThis;
|
|
331
|
+
if (isReactNativeRuntime()) return "react-native";
|
|
332
|
+
if (runtime.Bun?.version) return `bun/${runtime.Bun.version}`;
|
|
333
|
+
if (runtime.Deno?.version?.deno) return `deno/${runtime.Deno.version.deno}`;
|
|
334
|
+
if (runtime.navigator?.userAgent === "Cloudflare-Workers") return "workerd";
|
|
335
|
+
if (runtime.process?.versions?.node) return `node/${runtime.process.versions.node}`;
|
|
336
|
+
return "unknown";
|
|
337
|
+
};
|
|
338
|
+
/** The `User-Agent` the SDK sends from server runtimes, e.g. `calmlens-js/0.10.0 (node/22.12.0)`. */
|
|
339
|
+
const getUserAgent = () => `calmlens-js/${SDK_VERSION} (${runtimeName()})`;
|
|
340
|
+
/** True in a web page, where API keys would be visible to every visitor. */
|
|
341
|
+
const isBrowserRuntime = () => typeof globalThis.window !== "undefined" && typeof globalThis.document !== "undefined";
|
|
342
|
+
/** True in a React Native app, where an API key ships inside the app for anyone to extract. */
|
|
343
|
+
const isReactNativeRuntime = () => globalThis.navigator?.product === "ReactNative";
|
|
344
|
+
//#endregion
|
|
321
345
|
Object.defineProperty(exports, "API_ERROR_CODES", {
|
|
322
346
|
enumerable: true,
|
|
323
347
|
get: function() {
|
|
@@ -348,6 +372,18 @@ Object.defineProperty(exports, "SDK_ERROR_CODES", {
|
|
|
348
372
|
return SDK_ERROR_CODES;
|
|
349
373
|
}
|
|
350
374
|
});
|
|
375
|
+
Object.defineProperty(exports, "SDK_VERSION", {
|
|
376
|
+
enumerable: true,
|
|
377
|
+
get: function() {
|
|
378
|
+
return SDK_VERSION;
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
Object.defineProperty(exports, "getUserAgent", {
|
|
382
|
+
enumerable: true,
|
|
383
|
+
get: function() {
|
|
384
|
+
return getUserAgent;
|
|
385
|
+
}
|
|
386
|
+
});
|
|
351
387
|
Object.defineProperty(exports, "invalidArgument", {
|
|
352
388
|
enumerable: true,
|
|
353
389
|
get: function() {
|
|
@@ -360,3 +396,15 @@ Object.defineProperty(exports, "invalidConfig", {
|
|
|
360
396
|
return invalidConfig;
|
|
361
397
|
}
|
|
362
398
|
});
|
|
399
|
+
Object.defineProperty(exports, "isBrowserRuntime", {
|
|
400
|
+
enumerable: true,
|
|
401
|
+
get: function() {
|
|
402
|
+
return isBrowserRuntime;
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
Object.defineProperty(exports, "isReactNativeRuntime", {
|
|
406
|
+
enumerable: true,
|
|
407
|
+
get: function() {
|
|
408
|
+
return isReactNativeRuntime;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const
|
|
2
|
-
const require_CalmLensUtils = require("./CalmLensUtils-
|
|
1
|
+
const require_CalmLensVersion = require("./CalmLensVersion-DjhsJ1gj.js");
|
|
2
|
+
const require_CalmLensUtils = require("./CalmLensUtils-vX5H_vMn.js");
|
|
3
3
|
//#region ../shared/src/JsonUtils.ts
|
|
4
4
|
const stringifyJsonCanonical = (value) => JSON.stringify(value, (_key, nestedValue) => {
|
|
5
5
|
if (!nestedValue || typeof nestedValue !== "object" || Array.isArray(nestedValue)) return nestedValue;
|
|
@@ -56,11 +56,11 @@ const signUploadToken = async (claims, apiKey) => {
|
|
|
56
56
|
* `MockCalmLensServerClient` share it so both check options the same way.
|
|
57
57
|
*/
|
|
58
58
|
const signUploadTokenWithApiKey = async (apiKey, options, { now = Date.now(), nonce = crypto.randomUUID() } = {}) => {
|
|
59
|
-
if (!options || typeof options !== "object") throw
|
|
59
|
+
if (!options || typeof options !== "object") throw require_CalmLensVersion.invalidArgument("Options are required");
|
|
60
60
|
const { uploadPresetId, externalId, expiresInSeconds = 600 } = options;
|
|
61
61
|
require_CalmLensUtils.encodePathSegment(uploadPresetId, "Upload preset ID");
|
|
62
|
-
if (!Number.isInteger(expiresInSeconds) || expiresInSeconds < 1 || expiresInSeconds > 3600) throw
|
|
63
|
-
if (externalId !== void 0 && (typeof externalId !== "string" || !externalId)) throw
|
|
62
|
+
if (!Number.isInteger(expiresInSeconds) || expiresInSeconds < 1 || expiresInSeconds > 3600) throw require_CalmLensVersion.invalidArgument(`expiresInSeconds must be a whole number from 1 to ${UPLOAD_TOKEN_MAX_TTL_SECONDS}`);
|
|
63
|
+
if (externalId !== void 0 && (typeof externalId !== "string" || !externalId)) throw require_CalmLensVersion.invalidArgument("externalId must be a non-empty string");
|
|
64
64
|
const expiresAt = now + expiresInSeconds * 1e3;
|
|
65
65
|
return {
|
|
66
66
|
token: await signUploadToken({
|
|
@@ -96,7 +96,7 @@ const payloadToText = (payload) => {
|
|
|
96
96
|
const view = ArrayBuffer.isView(payload) ? new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength) : new Uint8Array(payload);
|
|
97
97
|
return new TextDecoder("utf-8", { fatal: false }).decode(view);
|
|
98
98
|
}
|
|
99
|
-
throw
|
|
99
|
+
throw require_CalmLensVersion.invalidArgument("Webhook payload must be the raw request body as a string, Uint8Array/Buffer or ArrayBuffer, not parsed JSON");
|
|
100
100
|
};
|
|
101
101
|
/**
|
|
102
102
|
* Verifies a webhook delivery: `x-calmlens-signature` must contain a `v1=` HMAC-SHA256 of
|
|
@@ -130,18 +130,18 @@ async function verifyWebhookSignature(options) {
|
|
|
130
130
|
* so keep a default branch when you switch on `type`.
|
|
131
131
|
*/
|
|
132
132
|
async function parseWebhookEvent(options) {
|
|
133
|
-
if (!await verifyWebhookSignature(options)) throw new
|
|
133
|
+
if (!await verifyWebhookSignature(options)) throw new require_CalmLensVersion.CalmLensError(require_CalmLensVersion.SDK_ERROR_CODES.INVALID_WEBHOOK_SIGNATURE, { message: "Webhook signature or timestamp did not verify" });
|
|
134
134
|
let event;
|
|
135
135
|
try {
|
|
136
136
|
event = JSON.parse(payloadToText(options.payload));
|
|
137
137
|
} catch (cause) {
|
|
138
|
-
throw new
|
|
138
|
+
throw new require_CalmLensVersion.CalmLensError(require_CalmLensVersion.SDK_ERROR_CODES.INVALID_WEBHOOK_PAYLOAD, {
|
|
139
139
|
message: "Webhook body is not JSON",
|
|
140
140
|
cause
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
const candidate = event;
|
|
144
|
-
if (!candidate || typeof candidate !== "object" || typeof candidate.id !== "string" || typeof candidate.type !== "string" || typeof candidate.projectId !== "string" || !candidate.data || typeof candidate.data !== "object") throw new
|
|
144
|
+
if (!candidate || typeof candidate !== "object" || typeof candidate.id !== "string" || typeof candidate.type !== "string" || typeof candidate.projectId !== "string" || !candidate.data || typeof candidate.data !== "object") throw new require_CalmLensVersion.CalmLensError(require_CalmLensVersion.SDK_ERROR_CODES.INVALID_WEBHOOK_PAYLOAD, { message: "Webhook body is not a CalmLens event" });
|
|
145
145
|
return event;
|
|
146
146
|
}
|
|
147
147
|
//#endregion
|