@calmlens/sdk 0.5.0 → 0.7.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 +118 -18
- package/cjs/{CalmLensTypes-DG_kHVqY.d.ts → CalmLensTypes-BpmT60j-.d.ts} +2 -1
- package/cjs/{CalmLensUtils-0QaxbI3A.js → CalmLensUtils-CJ6o7KRU.js} +35 -8
- package/cjs/index.d.ts +4884 -2
- package/cjs/index.js +148 -83
- package/cjs/testing.d.ts +56 -15
- package/cjs/testing.js +237 -125
- package/esm/{CalmLensTypes-DG_kHVqY.d.ts → CalmLensTypes-BpmT60j-.d.ts} +2 -1
- package/esm/{CalmLensUtils-BQEgxGWk.js → CalmLensUtils-BZsX8yeO.js} +30 -9
- package/esm/index.d.ts +4884 -2
- package/esm/index.js +147 -84
- package/esm/testing.d.ts +56 -15
- package/esm/testing.js +237 -125
- package/package.json +7 -8
- package/bin/calmlens.js +0 -1323
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ CalmLens provides content moderation and classification for text, images, docume
|
|
|
10
10
|
npm install @calmlens/sdk
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
Requires Node.js 22 or later (the minimum its dependencies support), or another runtime with `fetch`, Web Crypto and `AbortSignal.any`, such as Bun or Deno.
|
|
14
|
+
|
|
13
15
|
Every public SDK operation accepts one options object. This keeps call sites stable as optional fields are added.
|
|
14
16
|
|
|
15
17
|
## Quick Start
|
|
@@ -69,6 +71,12 @@ new CalmLensClient(options: CalmLensClientOptions)
|
|
|
69
71
|
- `projectId` (string, required): Your CalmLens project ID
|
|
70
72
|
- `baseUrl` (string, optional): API base URL (defaults to `https://api.calmlens.com/v1`)
|
|
71
73
|
- `cdnBaseUrl` (string, optional): CDN base URL (defaults to `https://cdn.calmlens.com/v1`)
|
|
74
|
+
- `timeoutMs` (positive integer, optional): Deadline for each request, including reading the response body (defaults to `120000`)
|
|
75
|
+
- `signal` (AbortSignal, optional): Cancels every request made by this client
|
|
76
|
+
- `uploadFetch`, `cdnFetch` (optional): `fetch` implementations for content uploads and CDN requests
|
|
77
|
+
- `requestBackend` (optional): An `api-def` request backend for the JSON API, for example `new FetchRequestBackend(customFetch)`
|
|
78
|
+
|
|
79
|
+
Options are validated before anything else is set up: a missing `apiKey` or `projectId`, a `timeoutMs` that is not a positive integer, or a `baseUrl`/`cdnBaseUrl` that is not an absolute `http(s)` URL throws a `CalmLensError`.
|
|
72
80
|
|
|
73
81
|
#### Methods
|
|
74
82
|
|
|
@@ -110,14 +118,31 @@ const asset = await client.assets.create({
|
|
|
110
118
|
});
|
|
111
119
|
```
|
|
112
120
|
|
|
113
|
-
##### assets.moderate(options)
|
|
121
|
+
##### assets.moderate(options) and text.moderate(options)
|
|
114
122
|
|
|
115
|
-
Submit an asset and wait for classification to finish. Accepts the same options as `assets.create()` for text, images, documents, and URLs.
|
|
123
|
+
Submit an asset and wait for classification to finish. Accepts the same options as `assets.create()` for text, images, documents, and URLs. `text.moderate({ text, name?, externalId?, ... })` is a shortcut that sends `text` as `text/plain` content named `text` by default.
|
|
116
124
|
|
|
117
125
|
```typescript
|
|
118
126
|
async assets.moderate(options: SubmitAssetOptions): Promise<Asset>
|
|
127
|
+
async text.moderate(options: ModerateTextOptions): Promise<Asset>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Both resolve to the stored `Asset`, a plain object with camelCase keys exactly as the API returns it:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const asset = await client.text.moderate({ text: "Great photo!", externalId: "comment-42" });
|
|
134
|
+
asset.id; // string
|
|
135
|
+
asset.status; // "approved" | "rejected" | "error"; "pending" for audio and video, which always run in the background
|
|
136
|
+
asset.type; // "plaintext-document" for text
|
|
137
|
+
asset.report?.flagged; // boolean
|
|
138
|
+
asset.report?.score; // number, the overall score
|
|
139
|
+
asset.report?.categories.harassment.status; // "evaluated" | "partial" | "not-evaluated"
|
|
140
|
+
asset.moderationAction; // the policy action applied, if any
|
|
141
|
+
asset.createdAt; // milliseconds since the Unix epoch
|
|
119
142
|
```
|
|
120
143
|
|
|
144
|
+
Always present: `id`, `projectId`, `name`, `type`, `status`, `createdAt` and `updatedAt`. Every other field may be `null` or missing: `report` is absent when processing failed (`status: "error"`) or has not finished, `moderationAction` when no policy action applied, `externalId`, `description`, `metadata`, `folderId`, `visibility` and `processingOptions` when you did not set them, and `sizeInBytes`, `fileFormat`, `imageData`, `documentData`, `previewImage` and `extractedText` when they do not apply to the content. Inside a report, a category's `score` and `likelihood` exist only when its `status` is `evaluated` or `partial` (see [Moderation Reports](#moderation-reports)).
|
|
145
|
+
|
|
121
146
|
##### assets.retrieve(options)
|
|
122
147
|
|
|
123
148
|
Retrieve details of a specific asset.
|
|
@@ -504,7 +529,21 @@ const client = new MockCalmLensClient({
|
|
|
504
529
|
});
|
|
505
530
|
```
|
|
506
531
|
|
|
507
|
-
|
|
532
|
+
`MockCalmLensClient` accepts the same options as `CalmLensClient` (`apiKey`, `projectId`, `baseUrl`, `cdnBaseUrl`, `timeoutMs`, ...) and validates them the same way, plus `mockOptions`. `cdn.getAssetUrl` uses `cdnBaseUrl` (default `mock://calmlens/v1`).
|
|
533
|
+
|
|
534
|
+
Every call is recorded in `client.calls` as `{ operation, options }`, where `operation` is the method path (`"text.moderate"`, `"assets.retrieve"`, `"events.list"`, ...) and `options` is the object you passed. `client.callsTo(operation)` filters them. To test failure handling, `client.failNextRequest()` makes the next call throw the same `CalmLensError` the real client throws when the network fails (`sdk/transport-error`); pass `"timeout"` for `sdk/timeout`, or any `Error` to throw it as is, and `{ operation }` to fail only that method. Each queued failure is used once.
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
const client = new MockCalmLensClient({ apiKey: createMockApiKey(), projectId, timeoutMs: 5_000 });
|
|
538
|
+
|
|
539
|
+
client.failNextRequest("timeout", { operation: "text.moderate" });
|
|
540
|
+
await expect(postComment(client, "hello")).rejects.toMatchObject({ code: "sdk/timeout" });
|
|
541
|
+
|
|
542
|
+
await postComment(client, "hello");
|
|
543
|
+
expect(client.callsTo("text.moderate")[0]?.options).toMatchObject({ text: "hello" });
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
For `mockOptions`, deterministic timestamps and IDs, storage inspection, and testing recipes, see the [JavaScript SDK Testing Guide](https://calmlens.com/docs/sdk/javascript/testing).
|
|
508
547
|
|
|
509
548
|
## Webhooks
|
|
510
549
|
|
|
@@ -516,40 +555,101 @@ A `webhook` connector POSTs each event to your URL as JSON:
|
|
|
516
555
|
"type": "asset.flagged",
|
|
517
556
|
"createdAt": 1760000000000,
|
|
518
557
|
"projectId": "…",
|
|
519
|
-
"data": {
|
|
558
|
+
"data": {
|
|
559
|
+
"severity": "high",
|
|
560
|
+
"title": "…",
|
|
561
|
+
"description": null,
|
|
562
|
+
"assetId": "…",
|
|
563
|
+
"asset": null,
|
|
564
|
+
"facts": [{ "key": "asset-name", "value": "photo.jpg" }]
|
|
565
|
+
}
|
|
520
566
|
}
|
|
521
567
|
```
|
|
522
568
|
|
|
523
|
-
Each delivery has these headers:
|
|
569
|
+
Each delivery has these headers (the names are exported as constants):
|
|
570
|
+
|
|
571
|
+
| Header | Constant | Value |
|
|
572
|
+
|---|---|---|
|
|
573
|
+
| `x-calmlens-delivery` | `WEBHOOK_DELIVERY_HEADER` | Delivery ID (the same across retries) |
|
|
574
|
+
| `x-calmlens-timestamp` | `WEBHOOK_TIMESTAMP_HEADER` | Unix time in seconds when the delivery was signed |
|
|
575
|
+
| `x-calmlens-signature` | `WEBHOOK_SIGNATURE_HEADER` | `v1=<lowercase hex HMAC-SHA256(secret, "<timestamp>.<raw body>")>` |
|
|
524
576
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
577
|
+
```typescript
|
|
578
|
+
import {
|
|
579
|
+
verifyWebhookSignature,
|
|
580
|
+
WEBHOOK_SIGNATURE_HEADER,
|
|
581
|
+
WEBHOOK_TIMESTAMP_HEADER,
|
|
582
|
+
} from "@calmlens/sdk";
|
|
530
583
|
|
|
531
|
-
|
|
584
|
+
const payload = await request.text();
|
|
585
|
+
const valid = await verifyWebhookSignature({
|
|
586
|
+
payload,
|
|
587
|
+
signature: request.headers.get(WEBHOOK_SIGNATURE_HEADER),
|
|
588
|
+
timestamp: request.headers.get(WEBHOOK_TIMESTAMP_HEADER),
|
|
589
|
+
secret: process.env.CALMLENS_WEBHOOK_SECRET!,
|
|
590
|
+
});
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
Verify the exact raw request body with `verifyWebhookSignature` before parsing it; re-serializing parsed JSON can change the signed bytes. Deliveries more than 5 minutes old (or ahead of your clock) are rejected to prevent replays. The body type is exported as `WebhookEventPayload`; narrow it on `type` to get that event type's typed `data.facts` (`EventType` and `EventFacts<Type>` are exported too, and [the webhooks guide](https://calmlens.com/docs/guides/webhooks#event-types) lists every type).
|
|
532
594
|
|
|
533
595
|
## Command-line tool
|
|
534
596
|
|
|
535
|
-
|
|
597
|
+
Install the standalone [CalmLens CLI](https://calmlens.com/docs/guides/local-development) through Homebrew, a platform download or npm. Webhook connectors must use public HTTPS URLs, so during development use it to forward events to a local handler instead. Each event is sent with the same body, headers and signature as a real delivery:
|
|
536
598
|
|
|
537
599
|
```bash
|
|
538
600
|
npx calmlens listen --forward-to http://localhost:3000/api/webhooks/calmlens --env-file .env.local
|
|
539
601
|
```
|
|
540
602
|
|
|
541
|
-
The CLI reads `CALMLENS_API_KEY`, `CALMLENS_PROJECT_ID` and `CALMLENS_WEBHOOK_SECRET` from the environment or `--env-file`; without a secret it prints a generated one for your app. `npx calmlens trigger [harassment|hate|criminal-activity|clean]` moderates a harmless test input so events appear (one upload each). Run `npx calmlens --help` for all options. To install the command globally, use `npm install -g calmlens
|
|
603
|
+
The CLI reads `CALMLENS_API_KEY`, `CALMLENS_PROJECT_ID` and `CALMLENS_WEBHOOK_SECRET` from the environment or `--env-file`; without a secret it prints a generated one for your app. `npx calmlens trigger [harassment|hate|criminal-activity|clean]` moderates a harmless test input so events appear (one upload each). Run `npx calmlens --help` for all options. To install the command globally, use `npm install -g calmlens`. The CLI is released separately from the SDK.
|
|
542
604
|
|
|
543
|
-
The same feed is available in code
|
|
605
|
+
The same feed is available in code with [`events.list`](#events-feed).
|
|
544
606
|
|
|
545
|
-
##
|
|
607
|
+
## Events feed
|
|
546
608
|
|
|
547
|
-
|
|
609
|
+
`client.events.list({ after?, limit? })` reads the project's events, oldest first, without a public webhook URL. It resolves to an `EventsPage`:
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
{
|
|
613
|
+
events: TypedEvent[]; // { id, projectId, type, severity, title, description?, assetId?, asset?, facts, createdAt, updatedAt }
|
|
614
|
+
cursor: string; // pass back as `after` to continue after the last event returned
|
|
615
|
+
hasMore: boolean; // true when more events are already waiting after `cursor`
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
- Without `after` (or with an empty string), it returns **no events** and a `cursor` for the current time, so you only see events created after you start reading. It does not return history.
|
|
620
|
+
- With `after`, it returns up to `limit` events (default 50) created after that cursor. When there are none, `cursor` is the `after` you passed.
|
|
621
|
+
- Keep passing the latest `cursor` as `after` until `hasMore` is `false`, then wait before polling again. Store the cursor if you want to resume after a restart.
|
|
622
|
+
- An unknown or malformed cursor fails with the `CalmLensError` code `events/invalid-cursor`.
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
let { cursor } = await client.events.list(); // no events, cursor = "now"
|
|
626
|
+
|
|
627
|
+
async function drainEvents() {
|
|
628
|
+
let hasMore = true;
|
|
629
|
+
while (hasMore) {
|
|
630
|
+
const page = await client.events.list({ after: cursor, limit: 100 });
|
|
631
|
+
for (const event of page.events) {
|
|
632
|
+
// narrow on event.type to read its typed facts
|
|
633
|
+
console.log(event.type, event.facts);
|
|
634
|
+
}
|
|
635
|
+
cursor = page.cursor;
|
|
636
|
+
hasMore = page.hasMore;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
setInterval(drainEvents, 5_000);
|
|
641
|
+
```
|
|
548
642
|
|
|
549
|
-
|
|
643
|
+
Events carry `facts: { key, value, url? }[]`; webhook deliveries carry the same events reshaped as `{ id, type, createdAt, projectId, data }`.
|
|
644
|
+
|
|
645
|
+
## Request budgets and errors
|
|
550
646
|
|
|
551
647
|
Set `timeoutMs` (default 120000) or `signal` on the client. Use `client.withRequestOptions({ signal, timeoutMs: 30000 })` to scope them to an operation without changing the original client. Multipart state is shared between scoped clients. Deadlines include response-body reads; authenticated default REST, upload and CDN requests reject redirects. Custom non-Fetch backends own their redirect/cancellation policies.
|
|
552
648
|
|
|
553
|
-
`CalmLensError` exposes `code`, optional HTTP `status`, `details` and native `cause`.
|
|
649
|
+
`CalmLensError` exposes `code`, optional HTTP `status`, `details` and native `cause`. Every failure to complete a request (DNS, TLS, refused or reset connections, truncated bodies, decompression errors) is `sdk/transport-error`, with the underlying error as `cause`; deadlines are `sdk/timeout`, cancellation `sdk/cancelled`, successful responses whose body is not the expected JSON `sdk/invalid-response`, and HTTP failures without an API error body `sdk/http-error`. `cdn.serve` returns the `Response` once headers arrive, so errors while you read its body come from your `fetch`. API error codes/messages are preserved. Core model types (`Asset`, `Folder`, `Lens`, `AssetPage`, `EventsPage`, `ClassificationReport`) and request types are exported from the package root.
|
|
554
650
|
|
|
555
651
|
`text.moderate` is a convenience wrapper around asset moderation: it supplies `text/plain` content and defaults the asset name to `text`. `assets.create` queues processing; `assets.moderate` waits for classification. The old asset analyze method is removed.
|
|
652
|
+
|
|
653
|
+
## Releasing
|
|
654
|
+
|
|
655
|
+
Stable releases are published automatically from `main` when packed SDK contents differ from npm `latest` and an SDK Changeset is present. Contributors must run `bun run changeset` to choose the release type and write release notes. CI updates and commits this package's `CHANGELOG.md` automatically. See the repository's [.changeset release guide](../../.changeset/README.md).
|
|
@@ -1245,6 +1245,7 @@ declare const ASSET_SCHEMA: zod.ZodObject<{
|
|
|
1245
1245
|
audioTranscribed: zod.ZodBoolean;
|
|
1246
1246
|
segments: zod.ZodArray<zod.ZodObject<{
|
|
1247
1247
|
source: zod.ZodEnum<{
|
|
1248
|
+
clip: "clip";
|
|
1248
1249
|
frame: "frame";
|
|
1249
1250
|
"frame-text": "frame-text";
|
|
1250
1251
|
speech: "speech";
|
|
@@ -3518,4 +3519,4 @@ interface ModerateTextOptions extends Omit<SubmitAssetCommonOptions, "name" | "v
|
|
|
3518
3519
|
name?: string;
|
|
3519
3520
|
}
|
|
3520
3521
|
//#endregion
|
|
3521
|
-
export { GetEventsResponse as A,
|
|
3522
|
+
export { GetEventsResponse as A, EventFactValues as B, UpdateAssetOptions as C, GetAssetChildrenResponse as D, VerifyWebhookSignatureOptions as E, Folder as F, AssetStatus as G, EventSeverity as H, Event as I, MetadataItem as J, AssetType as K, TypedEvent as L, RequestErrorCode as M, AssetBinaryPayloadInput as N, GetAssetResponse as O, Lens as P, EventCategory as R, SubmitAssetOptions as S, UploadAssetPartOptions as T, EventType as U, EventFacts as V, Asset as W, ProcessingOptions as Y, MultipartUploadOptions as _, CreateAssetSignedUrlOptions as a, RetrieveAssetOptions as b, EnsureLensOptions as c, ListAssetChildrenOptions as d, ListAssetsOptions as f, MoveFolderOptions as g, MoveAssetOptions as h, CdnServeOptions as i, PostAssetSignedUrlResponse as j, GetAssetsPageResponse as k, EnsureLensesOptions as l, ModerateTextOptions as m, CalmLensClientOptions as n, CreateFolderOptions as o, ListEventsOptions as p, AssetVisibility as q, CdnAssetUrlOptions as r, CreateMultipartUploadPartOptions as s, AssetContentOptions as t, FolderIdOptions as u, MultipartUploadPartOptions as v, UpdateFolderOptions as w, RetryAssetOptions as x, RequestOptions as y, EventFact as z };
|
|
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
//#endregion
|
|
23
23
|
let sendable_error = require("sendable-error");
|
|
24
|
-
//#region \0@oxc-project+runtime@0.
|
|
24
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/typeof.js
|
|
25
25
|
function _typeof(o) {
|
|
26
26
|
"@babel/helpers - typeof";
|
|
27
27
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -31,7 +31,7 @@ function _typeof(o) {
|
|
|
31
31
|
}, _typeof(o);
|
|
32
32
|
}
|
|
33
33
|
//#endregion
|
|
34
|
-
//#region \0@oxc-project+runtime@0.
|
|
34
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/toPrimitive.js
|
|
35
35
|
function toPrimitive(t, r) {
|
|
36
36
|
if ("object" != _typeof(t) || !t) return t;
|
|
37
37
|
var e = t[Symbol.toPrimitive];
|
|
@@ -43,13 +43,13 @@ function toPrimitive(t, r) {
|
|
|
43
43
|
return ("string" === r ? String : Number)(t);
|
|
44
44
|
}
|
|
45
45
|
//#endregion
|
|
46
|
-
//#region \0@oxc-project+runtime@0.
|
|
46
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/toPropertyKey.js
|
|
47
47
|
function toPropertyKey(t) {
|
|
48
48
|
var i = toPrimitive(t, "string");
|
|
49
49
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
50
50
|
}
|
|
51
51
|
//#endregion
|
|
52
|
-
//#region \0@oxc-project+runtime@0.
|
|
52
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/defineProperty.js
|
|
53
53
|
function _defineProperty(e, r, t) {
|
|
54
54
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
55
55
|
value: t,
|
|
@@ -59,7 +59,7 @@ function _defineProperty(e, r, t) {
|
|
|
59
59
|
}) : e[r] = t, e;
|
|
60
60
|
}
|
|
61
61
|
//#endregion
|
|
62
|
-
//#region \0@oxc-project+runtime@0.
|
|
62
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/objectSpread2.js
|
|
63
63
|
function ownKeys(e, r) {
|
|
64
64
|
var t = Object.keys(e);
|
|
65
65
|
if (Object.getOwnPropertySymbols) {
|
|
@@ -82,7 +82,7 @@ function _objectSpread2(e) {
|
|
|
82
82
|
return e;
|
|
83
83
|
}
|
|
84
84
|
//#endregion
|
|
85
|
-
//#region \0@oxc-project+runtime@0.
|
|
85
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/asyncToGenerator.js
|
|
86
86
|
function asyncGeneratorStep(n, t, e, r, o, a, c) {
|
|
87
87
|
try {
|
|
88
88
|
var i = n[a](c), u = i.value;
|
|
@@ -393,7 +393,7 @@ var CalmLensError = class extends Error {
|
|
|
393
393
|
};
|
|
394
394
|
const calmLensError = (errorCode, options) => new CalmLensError(errorCode, options);
|
|
395
395
|
//#endregion
|
|
396
|
-
//#region \0@oxc-project+runtime@0.
|
|
396
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/objectWithoutPropertiesLoose.js
|
|
397
397
|
function _objectWithoutPropertiesLoose(r, e) {
|
|
398
398
|
if (null == r) return {};
|
|
399
399
|
var t = {};
|
|
@@ -404,7 +404,7 @@ function _objectWithoutPropertiesLoose(r, e) {
|
|
|
404
404
|
return t;
|
|
405
405
|
}
|
|
406
406
|
//#endregion
|
|
407
|
-
//#region \0@oxc-project+runtime@0.
|
|
407
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/objectWithoutProperties.js
|
|
408
408
|
function _objectWithoutProperties(e, t) {
|
|
409
409
|
if (null == e) return {};
|
|
410
410
|
var o, r, i = _objectWithoutPropertiesLoose(e, t);
|
|
@@ -417,6 +417,27 @@ function _objectWithoutProperties(e, t) {
|
|
|
417
417
|
//#endregion
|
|
418
418
|
//#region src/client/CalmLensUtils.ts
|
|
419
419
|
const _excluded = ["text", "name"];
|
|
420
|
+
const invalidOptions = (message) => calmLensError({ id: "upload/invalid-payload" }, { message });
|
|
421
|
+
const assertHttpUrl = (name, value) => {
|
|
422
|
+
if (value === void 0) return;
|
|
423
|
+
let url;
|
|
424
|
+
try {
|
|
425
|
+
url = new URL(value);
|
|
426
|
+
} catch (_unused) {}
|
|
427
|
+
if (!url || url.protocol !== "https:" && url.protocol !== "http:") throw invalidOptions(`${name} must be an absolute http(s) URL`);
|
|
428
|
+
};
|
|
429
|
+
/**
|
|
430
|
+
* Checks client options before the client sets anything up. `CalmLensClient` and
|
|
431
|
+
* `MockCalmLensClient` share it so both reject the same configuration.
|
|
432
|
+
*/
|
|
433
|
+
const validateClientOptions = (options) => {
|
|
434
|
+
if (!options || typeof options !== "object") throw invalidOptions("Client options are required");
|
|
435
|
+
if (!options.apiKey) throw invalidOptions("API key is required");
|
|
436
|
+
if (!options.projectId) throw invalidOptions("Project ID is required");
|
|
437
|
+
if (options.timeoutMs !== void 0 && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs <= 0)) throw invalidOptions("timeoutMs must be a positive integer");
|
|
438
|
+
assertHttpUrl("baseUrl", options.baseUrl);
|
|
439
|
+
assertHttpUrl("cdnBaseUrl", options.cdnBaseUrl);
|
|
440
|
+
};
|
|
420
441
|
const toTextAssetOptions = (_ref) => {
|
|
421
442
|
let { text, name } = _ref, options = _objectWithoutProperties(_ref, _excluded);
|
|
422
443
|
if (typeof text !== "string" || !text.trim()) throw calmLensError(PUBLIC_ERROR_CODES.INVALID_UPLOAD_PAYLOAD, { message: "Text to moderate must be a non-empty string" });
|
|
@@ -549,3 +570,9 @@ Object.defineProperty(exports, "validateAssetPayload", {
|
|
|
549
570
|
return validateAssetPayload;
|
|
550
571
|
}
|
|
551
572
|
});
|
|
573
|
+
Object.defineProperty(exports, "validateClientOptions", {
|
|
574
|
+
enumerable: true,
|
|
575
|
+
get: function() {
|
|
576
|
+
return validateClientOptions;
|
|
577
|
+
}
|
|
578
|
+
});
|