@civitai/sdk 0.12.1 → 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/dist/core/transport.d.ts +4 -1
- package/dist/core/transports/host-replies.generated.d.ts +18 -0
- package/dist/core/transports/host-replies.generated.js +66 -0
- package/dist/core/transports/iframe-transport.d.ts +6 -0
- package/dist/core/transports/iframe-transport.js +44 -26
- package/dist/host/index.js +6 -4
- package/dist/session/index.d.ts +1 -1
- package/dist/session/index.js +5 -0
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/package.json +3 -1
package/dist/core/transport.d.ts
CHANGED
|
@@ -9,7 +9,10 @@ export interface BlockSnapshot {
|
|
|
9
9
|
context: BlockContext;
|
|
10
10
|
token: BlockToken;
|
|
11
11
|
settings: BlockSettings;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* `null` for anonymous viewers. For identity, read `app.site.get('blocks/me')`
|
|
14
|
+
* rather than this — not `site.get('me')`, which does not accept a block token.
|
|
15
|
+
*/
|
|
13
16
|
viewer: ViewerInfo | null;
|
|
14
17
|
theme: Theme;
|
|
15
18
|
blockInstanceId: string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface HostReply {
|
|
2
|
+
/** The message type the host answers with. */
|
|
3
|
+
readonly reply: string;
|
|
4
|
+
/** `legacy`: fields straight in the payload, failure as a string. */
|
|
5
|
+
readonly framing: 'envelope' | 'legacy';
|
|
6
|
+
/** The keys a success carries besides `requestId`; `null` where the host's literal could not be read. */
|
|
7
|
+
readonly keys: readonly string[] | null;
|
|
8
|
+
}
|
|
9
|
+
/** The civitai commit this ledger was read from. A request the host added after it is refused too. */
|
|
10
|
+
export declare const HOST_SNAPSHOT = "464b2023e8";
|
|
11
|
+
/**
|
|
12
|
+
* Every request the host answered at {@link HOST_SNAPSHOT}. A type absent here is refused.
|
|
13
|
+
* Reply names and framing are fixed at publish time: if the host renames a reply or moves a
|
|
14
|
+
* type to envelope framing, builds on this version stop receiving it until they upgrade.
|
|
15
|
+
*/
|
|
16
|
+
export declare const HOST_REPLIES: Readonly<Record<string, HostReply>>;
|
|
17
|
+
/** The host's fire-and-forget messages: it handles them and never replies. */
|
|
18
|
+
export declare const HOST_NOTIFICATIONS: ReadonlySet<string>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Generated by scripts/gen-host-replies.mjs from snapshots/host-messages.json
|
|
2
|
+
// (civitai/civitai 464b2023e8, 2026-10-14). Do not edit.
|
|
3
|
+
/** The civitai commit this ledger was read from. A request the host added after it is refused too. */
|
|
4
|
+
export const HOST_SNAPSHOT = "464b2023e8";
|
|
5
|
+
/**
|
|
6
|
+
* Every request the host answered at {@link HOST_SNAPSHOT}. A type absent here is refused.
|
|
7
|
+
* Reply names and framing are fixed at publish time: if the host renames a reply or moves a
|
|
8
|
+
* type to envelope framing, builds on this version stop receiving it until they upgrade.
|
|
9
|
+
*/
|
|
10
|
+
export const HOST_REPLIES = {
|
|
11
|
+
"APP_STORAGE_DELETE": { "reply": "APP_STORAGE_DELETE_RESULT", "framing": "legacy", "keys": ["deleted", "ok"] },
|
|
12
|
+
"APP_STORAGE_GET": { "reply": "APP_STORAGE_GET_RESULT", "framing": "legacy", "keys": ["value"] },
|
|
13
|
+
"APP_STORAGE_LIST": { "reply": "APP_STORAGE_LIST_RESULT", "framing": "legacy", "keys": ["keys", "nextCursor"] },
|
|
14
|
+
"APP_STORAGE_QUOTA": { "reply": "APP_STORAGE_QUOTA_RESULT", "framing": "legacy", "keys": ["limitBytes", "limitRows", "rowCount", "usedBytes"] },
|
|
15
|
+
"APP_STORAGE_SET": { "reply": "APP_STORAGE_SET_RESULT", "framing": "legacy", "keys": ["ok", "sizeBytes"] },
|
|
16
|
+
"CANCEL_APP_WORKFLOW": { "reply": "CANCEL_APP_WORKFLOW_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
17
|
+
"CANCEL_WORKFLOW": { "reply": "WORKFLOW_CANCELED", "framing": "legacy", "keys": ["snapshot"] },
|
|
18
|
+
"CREATE_POST_FROM_APP": { "reply": "CREATE_POST_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
19
|
+
"ESTIMATE_WORKFLOW": { "reply": "ESTIMATE_RESULT", "framing": "legacy", "keys": ["snapshot"] },
|
|
20
|
+
"ESTIMATE_WORKFLOW_BATCH": { "reply": "ESTIMATE_BATCH_RESULT", "framing": "legacy", "keys": ["aggregate", "snapshots"] },
|
|
21
|
+
"GET_BUZZ_ACCOUNTS": { "reply": "BUZZ_ACCOUNTS_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
22
|
+
"GET_BUZZ_BALANCE": { "reply": "BUZZ_BALANCE_RESULT", "framing": "legacy", "keys": ["balance"] },
|
|
23
|
+
"GET_BUZZ_TRANSACTIONS": { "reply": "BUZZ_TRANSACTIONS_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
24
|
+
"GET_DAILY_COMPENSATION": { "reply": "DAILY_COMPENSATION_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
25
|
+
"GET_IMAGES_BY_IDS": { "reply": "IMAGES_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
26
|
+
"GET_VIEWER": { "reply": "VIEWER_RESULT", "framing": "legacy", "keys": ["viewer"] },
|
|
27
|
+
"GET_WILDCARD_PACK": { "reply": "WILDCARD_PACK_RESULT", "framing": "legacy", "keys": ["pack"] },
|
|
28
|
+
"OPEN_BUZZ_PURCHASE": { "reply": "BUZZ_PURCHASE_RESULT", "framing": "legacy", "keys": ["purchased"] },
|
|
29
|
+
"OPEN_CHECKPOINT_PICKER": { "reply": "CHECKPOINT_PICKER_RESULT", "framing": "legacy", "keys": ["selected"] },
|
|
30
|
+
"OPEN_IMAGE_PICKER": { "reply": "IMAGE_PICKER_RESULT", "framing": "legacy", "keys": ["selected", "selectedImages"] },
|
|
31
|
+
"OPEN_IMAGE_UPLOAD": { "reply": "IMAGE_UPLOAD_RESULT", "framing": "legacy", "keys": ["selected"] },
|
|
32
|
+
"OPEN_RESOURCE_PICKER": { "reply": "RESOURCE_PICKER_RESULT", "framing": "legacy", "keys": ["selected", "selectedResources"] },
|
|
33
|
+
"POLL_WORKFLOW": { "reply": "WORKFLOW_STATUS", "framing": "legacy", "keys": ["snapshot"] },
|
|
34
|
+
"PREPARE_TRAINING_DATASET": { "reply": "TRAINING_DATASET_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
35
|
+
"PUBLISH_GENERATION_OUTPUTS": { "reply": "PUBLISH_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
36
|
+
"QUERY_APP_WORKFLOWS": { "reply": "APP_WORKFLOWS_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
37
|
+
"REQUEST_TOKEN": { "reply": "TOKEN_REFRESH_RESPONSE", "framing": "legacy", "keys": ["token"] },
|
|
38
|
+
"RUN_CONFIRMED_STEP": { "reply": "CONFIRMED_STEP_RESULT", "framing": "legacy", "keys": ["snapshot"] },
|
|
39
|
+
"RUN_TRAINING": { "reply": "TRAINING_RESULT", "framing": "legacy", "keys": ["snapshot"] },
|
|
40
|
+
"SAVE_IMAGE": { "reply": "SAVE_IMAGE_RESULT", "framing": "legacy", "keys": ["ok"] },
|
|
41
|
+
"SET_COLLECTION_FOLLOW": { "reply": "COLLECTION_FOLLOW_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
42
|
+
"SET_USER_CHECKPOINT": { "reply": "USER_CHECKPOINT_SET", "framing": "legacy", "keys": ["ok"] },
|
|
43
|
+
"SHARED_APPEND": { "reply": "SHARED_APPEND_RESULT", "framing": "legacy", "keys": ["key"] },
|
|
44
|
+
"SHARED_GET": { "reply": "SHARED_GET_RESULT", "framing": "legacy", "keys": ["item"] },
|
|
45
|
+
"SHARED_GET_COUNT": { "reply": "SHARED_GET_COUNT_RESULT", "framing": "legacy", "keys": ["count"] },
|
|
46
|
+
"SHARED_GET_COUNTS": { "reply": "SHARED_GET_COUNTS_RESULT", "framing": "legacy", "keys": ["counts"] },
|
|
47
|
+
"SHARED_LIST": { "reply": "SHARED_LIST_RESULT", "framing": "legacy", "keys": ["items", "nextCursor"] },
|
|
48
|
+
"SHARED_REPORT": { "reply": "SHARED_REPORT_RESULT", "framing": "legacy", "keys": ["ok"] },
|
|
49
|
+
"SHARED_UNVOTE": { "reply": "SHARED_UNVOTE_RESULT", "framing": "legacy", "keys": ["count"] },
|
|
50
|
+
"SHARED_UPDATE": { "reply": "SHARED_UPDATE_RESULT", "framing": "legacy", "keys": ["ok"] },
|
|
51
|
+
"SHARED_VOTE": { "reply": "SHARED_VOTE_RESULT", "framing": "legacy", "keys": ["count"] },
|
|
52
|
+
"SHARED_WITHDRAW": { "reply": "SHARED_WITHDRAW_RESULT", "framing": "legacy", "keys": ["deleted", "ok"] },
|
|
53
|
+
"SUBMIT_WORKFLOW": { "reply": "WORKFLOW_SUBMITTED", "framing": "legacy", "keys": ["snapshot"] },
|
|
54
|
+
};
|
|
55
|
+
/** The host's fire-and-forget messages: it handles them and never replies. */
|
|
56
|
+
export const HOST_NOTIFICATIONS = new Set([
|
|
57
|
+
"BLOCK_ERROR",
|
|
58
|
+
"BLOCK_HELLO",
|
|
59
|
+
"BLOCK_MESSAGE_REJECTED",
|
|
60
|
+
"BLOCK_READY",
|
|
61
|
+
"NAVIGATE",
|
|
62
|
+
"REQUEST_CONSENT",
|
|
63
|
+
"REQUEST_SIGN_IN",
|
|
64
|
+
"RESIZE_IFRAME",
|
|
65
|
+
"TRACK_EVENT",
|
|
66
|
+
]);
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type BlockSnapshot, type BlockTransport, type RequestOptions } from '../transport.js';
|
|
2
|
+
import { BridgeError } from '../errors.js';
|
|
3
|
+
import { type HostReply } from './host-replies.generated.js';
|
|
4
|
+
/** Why `request(type)` cannot settle, and what to call instead. */
|
|
5
|
+
export declare function unanswerable(type: string): BridgeError;
|
|
6
|
+
/** Turns a reply into the value it carries, or the failure it reports. */
|
|
7
|
+
export declare function unwrap(type: string, reply: unknown, expected: HostReply): unknown;
|
|
2
8
|
export interface IframeTransportOptions {
|
|
3
9
|
/** At least one entry. Other origins — including the local one — drop silently. */
|
|
4
10
|
allowedParentOrigins: string[];
|
|
@@ -2,48 +2,63 @@ import { isHostMessage, parseBlockInitFragment, stripBlockInitFragment, } from '
|
|
|
2
2
|
import { EMPTY_SNAPSHOT, snapshotFromInit, tokenFromWrapped, } from '../transport.js';
|
|
3
3
|
import { BridgeError, classifyHostError } from '../errors.js';
|
|
4
4
|
import { OriginMatcher } from '../origin-matcher.js';
|
|
5
|
+
import { HOST_NOTIFICATIONS, HOST_REPLIES, HOST_SNAPSHOT } from './host-replies.generated.js';
|
|
5
6
|
import { VERSION } from '../../version.generated.js';
|
|
6
7
|
/**
|
|
7
8
|
* The framing the host had before this package owned the protocol: fields
|
|
8
9
|
* straight in the payload, and failure as the server's own sentence. Converting
|
|
9
10
|
* it here is what keeps the rest of this file — and every domain — speaking one
|
|
10
|
-
* shape; when the host modernises a message,
|
|
11
|
-
* and this stops being reached.
|
|
11
|
+
* shape; when the host modernises a message, the snapshot reports it as
|
|
12
|
+
* `envelope` and this stops being reached for it.
|
|
12
13
|
*/
|
|
13
|
-
function fromLegacyReply(reply) {
|
|
14
|
+
function fromLegacyReply(reply, keys) {
|
|
14
15
|
const { requestId, error, ...fields } = reply;
|
|
15
16
|
// An empty string is how the host spells "no failure" on these replies.
|
|
16
17
|
if (typeof error === 'string' && error !== '') {
|
|
17
18
|
return { requestId, error: { code: classifyHostError(error), message: error } };
|
|
18
19
|
}
|
|
19
20
|
// Some of these replies nest their value under `result` and others put its
|
|
20
|
-
// fields straight in the payload
|
|
21
|
-
|
|
21
|
+
// fields straight in the payload. The snapshot says which; where the host's
|
|
22
|
+
// reply could not be read (`keys` null), the payload itself decides.
|
|
23
|
+
const nested = keys === null ? 'result' in fields : keys.length === 1 && keys[0] === 'result';
|
|
24
|
+
return { requestId, result: nested ? fields.result : fields };
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* reply, and when it empties `fromLegacyReply` goes with it.
|
|
27
|
+
* Where a caller should go instead of a bridge message, from BREAKING.md. Only
|
|
28
|
+
* read when the host does not answer the type, so it is what a request the
|
|
29
|
+
* host dropped (or never had) says instead of hanging.
|
|
28
30
|
*/
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
const REPLACED_BY = [
|
|
32
|
+
[/^GET_VIEWER$/, "app.site.get('blocks/me')"],
|
|
33
|
+
[/^(SUBMIT|ESTIMATE|POLL|CANCEL)_WORKFLOW$|^QUERY_APP_WORKFLOWS$|^CANCEL_APP_WORKFLOW$/, 'app.workflows'],
|
|
34
|
+
[/^GET_IMAGES_BY_IDS$/, 'GET /api/v1/blocks/images?ids=… (app.site)'],
|
|
35
|
+
[/^APP_STORAGE_/, 'POST /api/v1/blocks/app-storage/* (app.site)'],
|
|
36
|
+
[/^SHARED_/, 'app.sharedStorage'],
|
|
37
|
+
[/^GET_BUZZ_BALANCE$/, "app.site.get('blocks/buzz')"],
|
|
38
|
+
[/^SET_COLLECTION_FOLLOW$/, 'POST /api/v1/blocks/collections/{id}/follow (app.site)'],
|
|
39
|
+
[/^TRACK_EVENT$/, 'app.host.track(eventName, properties)'],
|
|
40
|
+
[/^PUBLISH_GENERATION_OUTPUTS$/, 'app.host.publishGenerationOutputs'],
|
|
41
|
+
];
|
|
42
|
+
/** Why `request(type)` cannot settle, and what to call instead. */
|
|
43
|
+
export function unanswerable(type) {
|
|
44
|
+
const instead = REPLACED_BY.find(([pattern]) => pattern.test(type))?.[1];
|
|
45
|
+
const message = HOST_NOTIFICATIONS.has(type)
|
|
46
|
+
? `${type} is fire-and-forget: the host never answers it, so request() would wait forever. ` +
|
|
47
|
+
`Send it with notify()${instead ? `, or use ${instead}` : ''}.`
|
|
48
|
+
: `${type} is not a request the host answered at civitai ${HOST_SNAPSHOT}, ` +
|
|
49
|
+
`the host snapshot @civitai/sdk ${VERSION} was built from, so request() would wait forever. ` +
|
|
50
|
+
(instead
|
|
51
|
+
? `Use ${instead} instead.`
|
|
52
|
+
: 'If the host has added it since, upgrade @civitai/sdk; otherwise see BREAKING.md for where bridge messages moved.');
|
|
53
|
+
return new BridgeError('invalid', type, message);
|
|
39
54
|
}
|
|
40
55
|
/** Turns a reply into the value it carries, or the failure it reports. */
|
|
41
|
-
function unwrap(type, reply,
|
|
56
|
+
export function unwrap(type, reply, expected) {
|
|
42
57
|
if (reply == null || typeof reply !== 'object') {
|
|
43
58
|
throw new BridgeError('malformed', type, `${type} replied with no payload`);
|
|
44
59
|
}
|
|
45
|
-
const envelope = framing === 'legacy'
|
|
46
|
-
? fromLegacyReply(reply)
|
|
60
|
+
const envelope = expected.framing === 'legacy'
|
|
61
|
+
? fromLegacyReply(reply, expected.keys)
|
|
47
62
|
: reply;
|
|
48
63
|
if (envelope.error !== undefined) {
|
|
49
64
|
throw new BridgeError(envelope.error.code, type, envelope.error.message || `${type} failed`);
|
|
@@ -187,11 +202,14 @@ export class IframeTransport {
|
|
|
187
202
|
this.#dispatch(message.type, message.payload);
|
|
188
203
|
}
|
|
189
204
|
async request(type, params, opts = {}) {
|
|
190
|
-
|
|
191
|
-
|
|
205
|
+
// Own keys only: `HOST_REPLIES['toString']` must not read as an answer.
|
|
206
|
+
const expected = Object.hasOwn(HOST_REPLIES, type) ? HOST_REPLIES[type] : undefined;
|
|
207
|
+
// Nothing would ever answer it, so say so now rather than wait forever.
|
|
208
|
+
if (!expected)
|
|
209
|
+
throw unanswerable(type);
|
|
210
|
+
return unwrap(type, await this.#exchange(type, expected.reply, params, opts), expected);
|
|
192
211
|
}
|
|
193
|
-
#exchange(type, params, opts) {
|
|
194
|
-
const responseType = replyTypeFor(type);
|
|
212
|
+
#exchange(type, responseType, params, opts) {
|
|
195
213
|
const { signal } = opts;
|
|
196
214
|
if (signal?.aborted)
|
|
197
215
|
return Promise.reject(signal.reason);
|
package/dist/host/index.js
CHANGED
|
@@ -60,10 +60,12 @@ export function createHost(transport) {
|
|
|
60
60
|
transport,
|
|
61
61
|
});
|
|
62
62
|
// The host spells "no failure" as `error: ''`, which the transport reads
|
|
63
|
-
// as a success
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
63
|
+
// as a success. A reply with no `result` at all is refused by the
|
|
64
|
+
// transport (the ledger says this reply nests under `result`), but one
|
|
65
|
+
// whose `result` lacks the ids gets this far, and returning it would
|
|
66
|
+
// resolve `undefined` from a promise that says `number[]`. A caller
|
|
67
|
+
// reading that as "nothing published" would be guessing: images may well
|
|
68
|
+
// have been.
|
|
67
69
|
if (!Array.isArray(imageIds) || !imageIds.every((id) => typeof id === 'number')) {
|
|
68
70
|
throw new BridgeError('malformed', 'PUBLISH_GENERATION_OUTPUTS', 'PUBLISH_GENERATION_OUTPUTS reply carried no image ids. Whether anything ' +
|
|
69
71
|
'was published is unknown; read the workflow back rather than assuming.');
|
package/dist/session/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Every scope an app can hold, as the site names them. */
|
|
2
|
-
export declare const SCOPES: readonly ['ai:write:budgeted', 'apps:storage:read', 'apps:storage:shared:read', 'apps:storage:shared:write', 'apps:storage:write', 'buzz:read:self', 'collections:read:private', 'collections:read:self', 'collections:write:self', 'models:read:self', 'posts:write:self', 'social:tip:self', 'user:read:self'];
|
|
2
|
+
export declare const SCOPES: readonly ['ai:write:budgeted', 'apps:storage', 'apps:storage:publish', 'apps:storage:read', 'apps:storage:shared:read', 'apps:storage:shared:write', 'apps:storage:write', 'apps:store:items:write', 'buzz:read:self', 'collections:read:private', 'collections:read:self', 'collections:write:self', 'goods:purchase:self', 'goods:read:self', 'models:read:self', 'posts:write:self', 'social:tip:self', 'user:read:self'];
|
|
3
3
|
export type Scope = (typeof SCOPES)[number];
|
|
4
4
|
export interface TokenOptions {
|
|
5
5
|
/** Skip the held token and get a new one, e.g. after the API refused it. */
|
package/dist/session/index.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/** Every scope an app can hold, as the site names them. */
|
|
2
2
|
export const SCOPES = [
|
|
3
3
|
'ai:write:budgeted',
|
|
4
|
+
'apps:storage',
|
|
5
|
+
'apps:storage:publish',
|
|
4
6
|
'apps:storage:read',
|
|
5
7
|
'apps:storage:shared:read',
|
|
6
8
|
'apps:storage:shared:write',
|
|
7
9
|
'apps:storage:write',
|
|
10
|
+
'apps:store:items:write',
|
|
8
11
|
'buzz:read:self',
|
|
9
12
|
'collections:read:private',
|
|
10
13
|
'collections:read:self',
|
|
11
14
|
'collections:write:self',
|
|
15
|
+
'goods:purchase:self',
|
|
16
|
+
'goods:read:self',
|
|
12
17
|
'models:read:self',
|
|
13
18
|
'posts:write:self',
|
|
14
19
|
'social:tip:self',
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** This package's version, reported to the host as `sdkVersion` in `BLOCK_READY`. */
|
|
2
|
-
export declare const VERSION = "0.
|
|
2
|
+
export declare const VERSION = "0.13.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@civitai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "The Civitai SDK: an app holds a token and calls the Civitai API and the orchestrator; a block asks its host only to show host UI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -69,6 +69,8 @@
|
|
|
69
69
|
"gen:steps": "node scripts/gen-step-types.mjs",
|
|
70
70
|
"check:steps": "node scripts/gen-step-types.mjs --check",
|
|
71
71
|
"gen:workflow-types": "node scripts/gen-workflow-types.mjs",
|
|
72
|
+
"gen:host-replies": "node scripts/gen-host-replies.mjs",
|
|
73
|
+
"check:host-replies": "node scripts/gen-host-replies.mjs --check",
|
|
72
74
|
"snapshot:host": "node scripts/snapshot-host-messages.mjs",
|
|
73
75
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json && tsc -p tsconfig.examples.json",
|
|
74
76
|
"test": "vitest run",
|