redweb-client 0.2.0 → 0.3.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/CHANGELOG.md +10 -0
- package/README.md +25 -15
- package/dist/{client-Dq8oKJwh.d.cts → client-D35g1hrL.d.cts} +2 -0
- package/dist/{client-Dq8oKJwh.d.ts → client-D35g1hrL.d.ts} +2 -0
- package/dist/index.cjs +5 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -2
- package/dist/live-html.cjs +13 -3
- package/dist/live-html.d.cts +1 -1
- package/dist/live-html.d.ts +1 -1
- package/dist/live-html.js +13 -3
- package/package.json +3 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
- Accept typed socket commands emitted by Redweb's server TSX controls on the page's custom route, reusing existing form feedback and DOM reconciliation. Requires Redweb 0.15.0 for socket-bound pages; ordinary Live HTML remains compatible with Redweb 0.14.0.
|
|
6
|
+
- Add optional `request(..., { responseType })` filtering so intermediate correlated events do not complete a request before its terminal reply. Correlated protocol errors still reject immediately; omitting the option retains existing behavior.
|
|
7
|
+
- Preserve explicitly bound JSON payloads, including `null`, and merge form fields over bound object payloads. Commands retain cancellation, deadlines and no-replay behavior.
|
|
8
|
+
- Rebuild distribution files automatically before packing/publishing, and include these release notes in the package.
|
|
9
|
+
|
|
10
|
+
Prepared for manual publication. No new runtime dependencies.
|
package/README.md
CHANGED
|
@@ -2,17 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
Browser-first WebSocket client for [Redweb](https://redweb.magnisolution.com/). It adds connection lifecycle, typed message subscriptions, request correlation, bounded queuing, opt-in reconnection, and versioned Redweb protocol envelopes without adding runtime dependencies.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Connection lifecycle
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Connection attempts stop when a synchronous state observer calls `close()` or `dispose()`. Attempts are identified across callback boundaries; a reentrant `connect()` shares an existing attempt, and an explicit replacement is not cleared by an older attempt finishing. Cancelled transport-factory results are closed after their lifecycle listeners are attached.
|
|
8
8
|
|
|
9
9
|
Integration regressions use real WebSocket connections and timers for observer-driven cancellation, upgrade-refusal retries, queued delivery, cancellation without replay, and rejected sends after disposal. Unit tests use isolated transport fixtures and explicitly simulated stale scheduling; integration tests do not mock transports. The complete verification command and its coverage scope are described below.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Live HTML integration
|
|
12
|
+
|
|
13
|
+
### Typed socket-page commands (0.3.0)
|
|
14
|
+
|
|
15
|
+
Version 0.3.0 accepts server-emitted command bindings on
|
|
16
|
+
existing Live HTML controls. It sends the actual `join`/`move` message type on
|
|
17
|
+
the page's custom route and reuses pending/error feedback and DOM reconciliation.
|
|
18
|
+
No application browser module is necessary. Socket-bound pages require Redweb
|
|
19
|
+
0.15.0; the earlier client 0.2.0 does not support these command bindings.
|
|
20
|
+
|
|
21
|
+
Direct request users may pass `{ responseType: 'redweb:result' }` to wait for a
|
|
22
|
+
specific terminal reply. Intermediate correlated events still reach subscribers
|
|
23
|
+
but do not settle that request. Correlated protocol errors reject immediately.
|
|
24
|
+
Omitting `responseType` preserves existing request behavior. Requests retain their
|
|
25
|
+
deadline/cancellation and no-replay guarantees.
|
|
12
26
|
|
|
13
27
|
The optional `redweb-client/live-html` entry owns reactive DOM updates, keyed
|
|
14
28
|
reconciliation, delegated actions/forms, feedback and connection status for pages
|
|
15
|
-
rendered by
|
|
29
|
+
rendered by Redweb. The root import stays
|
|
16
30
|
socket-only. Redweb serves the optional self-contained module and automatically
|
|
17
31
|
calls `mountLivePage()`; ordinary applications need no additional browser glue.
|
|
18
32
|
|
|
@@ -34,22 +48,18 @@ again shares the same owner; a disposed page cannot later reset a submitted draf
|
|
|
34
48
|
For local development with sibling repositories, run `npm run build` and
|
|
35
49
|
`npm link --ignore-scripts` here, then `npm link redweb-client --no-save --ignore-scripts`
|
|
36
50
|
in Redweb. Rebuild here after source changes; no repacking is needed. The link is
|
|
37
|
-
not saved in either lockfile.
|
|
38
|
-
|
|
51
|
+
not saved in either lockfile. The optional entry was introduced in 0.2.0;
|
|
52
|
+
socket-bound page commands and terminal-response filtering are added in 0.3.0.
|
|
39
53
|
|
|
40
|
-
Redweb's
|
|
41
|
-
dashboard and
|
|
42
|
-
|
|
43
|
-
covers 426 statements, 262 branches, 64 functions and 351 lines (100% each).
|
|
44
|
-
This is emitted-frontend coverage, not complete original-source/client-package or
|
|
45
|
-
cross-browser certification. Separate V8 measurements are not substituted for
|
|
46
|
-
the complete original-source gate below; the full release gate is not approved.
|
|
54
|
+
Redweb's headed-browser gates check the server-side counter, multi-user chat,
|
|
55
|
+
dashboard, forms and socket-bound multiplayer tutorial using real HTTP/WebSockets.
|
|
56
|
+
These are not cross-browser certification or a guarantee about application security.
|
|
47
57
|
|
|
48
58
|
From the linked Redweb repository, `npm run verify:client:source-coverage` runs
|
|
49
|
-
|
|
59
|
+
the complete client test inventory both plain and instrumented, then headed browser tests with
|
|
50
60
|
the same original-source coverage maps. Plain browser bundles must match this
|
|
51
61
|
client's `dist` output. It retains separate Node/browser results and currently
|
|
52
|
-
covers all
|
|
62
|
+
covers all 800 statements, 543 branches, 125 functions and 667 lines (100% each).
|
|
53
63
|
The same gate runs through the default `npm test` command. This metric does not
|
|
54
64
|
replace V8 coverage or independently count every optional-chain short circuit.
|
|
55
65
|
|
|
@@ -60,6 +60,8 @@ interface RedwebClientOptions {
|
|
|
60
60
|
random?: () => number;
|
|
61
61
|
}
|
|
62
62
|
interface RequestOptions extends ProtocolMetadata {
|
|
63
|
+
/** Ignore intermediate correlated events; protocol errors still reject immediately. */
|
|
64
|
+
responseType?: string;
|
|
63
65
|
timeoutMs?: number;
|
|
64
66
|
signal?: AbortSignal;
|
|
65
67
|
}
|
|
@@ -60,6 +60,8 @@ interface RedwebClientOptions {
|
|
|
60
60
|
random?: () => number;
|
|
61
61
|
}
|
|
62
62
|
interface RequestOptions extends ProtocolMetadata {
|
|
63
|
+
/** Ignore intermediate correlated events; protocol errors still reject immediately. */
|
|
64
|
+
responseType?: string;
|
|
63
65
|
timeoutMs?: number;
|
|
64
66
|
signal?: AbortSignal;
|
|
65
67
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -368,6 +368,9 @@ var RedwebClient = class {
|
|
|
368
368
|
const requestId = options.requestId ?? this.createRequestId();
|
|
369
369
|
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
370
370
|
assertNonNegativeInteger(timeoutMs, "timeoutMs");
|
|
371
|
+
if (options.responseType !== void 0 && (typeof options.responseType !== "string" || !options.responseType || options.responseType.length > 256)) {
|
|
372
|
+
return Promise.reject(new TypeError("responseType must be a non-empty string of at most 256 characters."));
|
|
373
|
+
}
|
|
371
374
|
if (options.signal?.aborted) return Promise.reject(new DOMException("The request was aborted.", "AbortError"));
|
|
372
375
|
if (this.pending.has(requestId)) return Promise.reject(new Error(`A Redweb request with id "${requestId}" is already pending.`));
|
|
373
376
|
return new Promise((resolve, reject) => {
|
|
@@ -375,7 +378,7 @@ var RedwebClient = class {
|
|
|
375
378
|
this.finishPending(requestId);
|
|
376
379
|
reject(new Error(`Redweb request timed out after ${timeoutMs}ms.`));
|
|
377
380
|
}, timeoutMs);
|
|
378
|
-
const pending = { resolve, reject, timer };
|
|
381
|
+
const pending = { resolve, reject, timer, responseType: options.responseType };
|
|
379
382
|
if (options.signal) {
|
|
380
383
|
pending.signal = options.signal;
|
|
381
384
|
pending.abort = () => {
|
|
@@ -482,7 +485,7 @@ var RedwebClient = class {
|
|
|
482
485
|
const requestId = message.requestId;
|
|
483
486
|
if (typeof requestId === "string") {
|
|
484
487
|
const pending = this.pending.get(requestId);
|
|
485
|
-
if (pending) {
|
|
488
|
+
if (pending && (pending.responseType === void 0 || message.type === pending.responseType || message.type === "error" && "error" in message)) {
|
|
486
489
|
this.finishPending(requestId);
|
|
487
490
|
if (message.type === "error" && "error" in message) pending.reject(new RedwebProtocolError(message));
|
|
488
491
|
else pending.resolve(message);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as ProtocolErrorEnvelope, a as ProtocolMetadata, R as RedwebMessage, b as ProtocolEnvelope } from './client-
|
|
2
|
-
export { B as BinaryListener, C as ClientState, c as CloseListener, E as ErrorListener, L as LegacyErrorMessage, M as MessageListener, d as ReconnectOptions, e as RedwebClient, f as RedwebClientOptions, g as RequestOptions, S as SocketEventLike, h as StateListener, W as WaitOptions, i as WebSocketLike } from './client-
|
|
1
|
+
import { P as ProtocolErrorEnvelope, a as ProtocolMetadata, R as RedwebMessage, b as ProtocolEnvelope } from './client-D35g1hrL.cjs';
|
|
2
|
+
export { B as BinaryListener, C as ClientState, c as CloseListener, E as ErrorListener, L as LegacyErrorMessage, M as MessageListener, d as ReconnectOptions, e as RedwebClient, f as RedwebClientOptions, g as RequestOptions, S as SocketEventLike, h as StateListener, W as WaitOptions, i as WebSocketLike } from './client-D35g1hrL.cjs';
|
|
3
3
|
|
|
4
4
|
declare const ERROR_CODES: Readonly<{
|
|
5
5
|
readonly INVALID_MESSAGE: "INVALID_MESSAGE";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as ProtocolErrorEnvelope, a as ProtocolMetadata, R as RedwebMessage, b as ProtocolEnvelope } from './client-
|
|
2
|
-
export { B as BinaryListener, C as ClientState, c as CloseListener, E as ErrorListener, L as LegacyErrorMessage, M as MessageListener, d as ReconnectOptions, e as RedwebClient, f as RedwebClientOptions, g as RequestOptions, S as SocketEventLike, h as StateListener, W as WaitOptions, i as WebSocketLike } from './client-
|
|
1
|
+
import { P as ProtocolErrorEnvelope, a as ProtocolMetadata, R as RedwebMessage, b as ProtocolEnvelope } from './client-D35g1hrL.js';
|
|
2
|
+
export { B as BinaryListener, C as ClientState, c as CloseListener, E as ErrorListener, L as LegacyErrorMessage, M as MessageListener, d as ReconnectOptions, e as RedwebClient, f as RedwebClientOptions, g as RequestOptions, S as SocketEventLike, h as StateListener, W as WaitOptions, i as WebSocketLike } from './client-D35g1hrL.js';
|
|
3
3
|
|
|
4
4
|
declare const ERROR_CODES: Readonly<{
|
|
5
5
|
readonly INVALID_MESSAGE: "INVALID_MESSAGE";
|
package/dist/index.js
CHANGED
|
@@ -336,6 +336,9 @@ var RedwebClient = class {
|
|
|
336
336
|
const requestId = options.requestId ?? this.createRequestId();
|
|
337
337
|
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
338
338
|
assertNonNegativeInteger(timeoutMs, "timeoutMs");
|
|
339
|
+
if (options.responseType !== void 0 && (typeof options.responseType !== "string" || !options.responseType || options.responseType.length > 256)) {
|
|
340
|
+
return Promise.reject(new TypeError("responseType must be a non-empty string of at most 256 characters."));
|
|
341
|
+
}
|
|
339
342
|
if (options.signal?.aborted) return Promise.reject(new DOMException("The request was aborted.", "AbortError"));
|
|
340
343
|
if (this.pending.has(requestId)) return Promise.reject(new Error(`A Redweb request with id "${requestId}" is already pending.`));
|
|
341
344
|
return new Promise((resolve, reject) => {
|
|
@@ -343,7 +346,7 @@ var RedwebClient = class {
|
|
|
343
346
|
this.finishPending(requestId);
|
|
344
347
|
reject(new Error(`Redweb request timed out after ${timeoutMs}ms.`));
|
|
345
348
|
}, timeoutMs);
|
|
346
|
-
const pending = { resolve, reject, timer };
|
|
349
|
+
const pending = { resolve, reject, timer, responseType: options.responseType };
|
|
347
350
|
if (options.signal) {
|
|
348
351
|
pending.signal = options.signal;
|
|
349
352
|
pending.abort = () => {
|
|
@@ -450,7 +453,7 @@ var RedwebClient = class {
|
|
|
450
453
|
const requestId = message.requestId;
|
|
451
454
|
if (typeof requestId === "string") {
|
|
452
455
|
const pending = this.pending.get(requestId);
|
|
453
|
-
if (pending) {
|
|
456
|
+
if (pending && (pending.responseType === void 0 || message.type === pending.responseType || message.type === "error" && "error" in message)) {
|
|
454
457
|
this.finishPending(requestId);
|
|
455
458
|
if (message.type === "error" && "error" in message) pending.reject(new RedwebProtocolError(message));
|
|
456
459
|
else pending.resolve(message);
|
package/dist/live-html.cjs
CHANGED
|
@@ -363,6 +363,9 @@ var RedwebClient = class {
|
|
|
363
363
|
const requestId = options.requestId ?? this.createRequestId();
|
|
364
364
|
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
365
365
|
assertNonNegativeInteger(timeoutMs, "timeoutMs");
|
|
366
|
+
if (options.responseType !== void 0 && (typeof options.responseType !== "string" || !options.responseType || options.responseType.length > 256)) {
|
|
367
|
+
return Promise.reject(new TypeError("responseType must be a non-empty string of at most 256 characters."));
|
|
368
|
+
}
|
|
366
369
|
if (options.signal?.aborted) return Promise.reject(new DOMException("The request was aborted.", "AbortError"));
|
|
367
370
|
if (this.pending.has(requestId)) return Promise.reject(new Error(`A Redweb request with id "${requestId}" is already pending.`));
|
|
368
371
|
return new Promise((resolve, reject) => {
|
|
@@ -370,7 +373,7 @@ var RedwebClient = class {
|
|
|
370
373
|
this.finishPending(requestId);
|
|
371
374
|
reject(new Error(`Redweb request timed out after ${timeoutMs}ms.`));
|
|
372
375
|
}, timeoutMs);
|
|
373
|
-
const pending = { resolve, reject, timer };
|
|
376
|
+
const pending = { resolve, reject, timer, responseType: options.responseType };
|
|
374
377
|
if (options.signal) {
|
|
375
378
|
pending.signal = options.signal;
|
|
376
379
|
pending.abort = () => {
|
|
@@ -477,7 +480,7 @@ var RedwebClient = class {
|
|
|
477
480
|
const requestId = message.requestId;
|
|
478
481
|
if (typeof requestId === "string") {
|
|
479
482
|
const pending = this.pending.get(requestId);
|
|
480
|
-
if (pending) {
|
|
483
|
+
if (pending && (pending.responseType === void 0 || message.type === pending.responseType || message.type === "error" && "error" in message)) {
|
|
481
484
|
this.finishPending(requestId);
|
|
482
485
|
if (message.type === "error" && "error" in message) pending.reject(new RedwebProtocolError(message));
|
|
483
486
|
else pending.resolve(message);
|
|
@@ -768,7 +771,7 @@ var ActionFeedback = class {
|
|
|
768
771
|
|
|
769
772
|
// src/live-html/feedback.js
|
|
770
773
|
function createFeedback({ componentOf, report, stateKey, clientNodes, client, listen, active }) {
|
|
771
|
-
const bindingOf = (source) => JSON.stringify([componentOf(source), source.getAttribute("rw-submit"), source.getAttribute("rw-click")]);
|
|
774
|
+
const bindingOf = (source) => JSON.stringify([componentOf(source), source.getAttribute("rw-submit"), source.getAttribute("rw-click"), source.getAttribute("data-rw-command")]);
|
|
772
775
|
const revisions = /* @__PURE__ */ new WeakMap();
|
|
773
776
|
const feedbackNodes = /* @__PURE__ */ new WeakMap();
|
|
774
777
|
const feedbackSources = /* @__PURE__ */ new WeakMap();
|
|
@@ -855,6 +858,13 @@ function createFeedback({ componentOf, report, stateKey, clientNodes, client, li
|
|
|
855
858
|
};
|
|
856
859
|
const performAction = (source, payload, completed) => feedback.run(source, () => {
|
|
857
860
|
if (client.state !== "open") throw Object.assign(new Error("Action was not sent while disconnected."), { code: "ACTION_OFFLINE" });
|
|
861
|
+
const command = source.getAttribute("data-rw-command");
|
|
862
|
+
if (command !== null) {
|
|
863
|
+
const binding = JSON.parse(command);
|
|
864
|
+
if (typeof binding.type !== "string" || !binding.type || binding.type.startsWith("redweb:")) throw new Error("Invalid socket action binding.");
|
|
865
|
+
const input = payload.args.length ? { ...binding.payload, ...payload.args[0] } : Object.hasOwn(binding, "payload") ? binding.payload : {};
|
|
866
|
+
return client.request(binding.type, input, { responseType: "redweb:result" });
|
|
867
|
+
}
|
|
858
868
|
return client.request("redweb:html", payload);
|
|
859
869
|
}).then((success) => {
|
|
860
870
|
if (success && active()) completed?.();
|
package/dist/live-html.d.cts
CHANGED
package/dist/live-html.d.ts
CHANGED
package/dist/live-html.js
CHANGED
|
@@ -336,6 +336,9 @@ var RedwebClient = class {
|
|
|
336
336
|
const requestId = options.requestId ?? this.createRequestId();
|
|
337
337
|
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
338
338
|
assertNonNegativeInteger(timeoutMs, "timeoutMs");
|
|
339
|
+
if (options.responseType !== void 0 && (typeof options.responseType !== "string" || !options.responseType || options.responseType.length > 256)) {
|
|
340
|
+
return Promise.reject(new TypeError("responseType must be a non-empty string of at most 256 characters."));
|
|
341
|
+
}
|
|
339
342
|
if (options.signal?.aborted) return Promise.reject(new DOMException("The request was aborted.", "AbortError"));
|
|
340
343
|
if (this.pending.has(requestId)) return Promise.reject(new Error(`A Redweb request with id "${requestId}" is already pending.`));
|
|
341
344
|
return new Promise((resolve, reject) => {
|
|
@@ -343,7 +346,7 @@ var RedwebClient = class {
|
|
|
343
346
|
this.finishPending(requestId);
|
|
344
347
|
reject(new Error(`Redweb request timed out after ${timeoutMs}ms.`));
|
|
345
348
|
}, timeoutMs);
|
|
346
|
-
const pending = { resolve, reject, timer };
|
|
349
|
+
const pending = { resolve, reject, timer, responseType: options.responseType };
|
|
347
350
|
if (options.signal) {
|
|
348
351
|
pending.signal = options.signal;
|
|
349
352
|
pending.abort = () => {
|
|
@@ -450,7 +453,7 @@ var RedwebClient = class {
|
|
|
450
453
|
const requestId = message.requestId;
|
|
451
454
|
if (typeof requestId === "string") {
|
|
452
455
|
const pending = this.pending.get(requestId);
|
|
453
|
-
if (pending) {
|
|
456
|
+
if (pending && (pending.responseType === void 0 || message.type === pending.responseType || message.type === "error" && "error" in message)) {
|
|
454
457
|
this.finishPending(requestId);
|
|
455
458
|
if (message.type === "error" && "error" in message) pending.reject(new RedwebProtocolError(message));
|
|
456
459
|
else pending.resolve(message);
|
|
@@ -741,7 +744,7 @@ var ActionFeedback = class {
|
|
|
741
744
|
|
|
742
745
|
// src/live-html/feedback.js
|
|
743
746
|
function createFeedback({ componentOf, report, stateKey, clientNodes, client, listen, active }) {
|
|
744
|
-
const bindingOf = (source) => JSON.stringify([componentOf(source), source.getAttribute("rw-submit"), source.getAttribute("rw-click")]);
|
|
747
|
+
const bindingOf = (source) => JSON.stringify([componentOf(source), source.getAttribute("rw-submit"), source.getAttribute("rw-click"), source.getAttribute("data-rw-command")]);
|
|
745
748
|
const revisions = /* @__PURE__ */ new WeakMap();
|
|
746
749
|
const feedbackNodes = /* @__PURE__ */ new WeakMap();
|
|
747
750
|
const feedbackSources = /* @__PURE__ */ new WeakMap();
|
|
@@ -828,6 +831,13 @@ function createFeedback({ componentOf, report, stateKey, clientNodes, client, li
|
|
|
828
831
|
};
|
|
829
832
|
const performAction = (source, payload, completed) => feedback.run(source, () => {
|
|
830
833
|
if (client.state !== "open") throw Object.assign(new Error("Action was not sent while disconnected."), { code: "ACTION_OFFLINE" });
|
|
834
|
+
const command = source.getAttribute("data-rw-command");
|
|
835
|
+
if (command !== null) {
|
|
836
|
+
const binding = JSON.parse(command);
|
|
837
|
+
if (typeof binding.type !== "string" || !binding.type || binding.type.startsWith("redweb:")) throw new Error("Invalid socket action binding.");
|
|
838
|
+
const input = payload.args.length ? { ...binding.payload, ...payload.args[0] } : Object.hasOwn(binding, "payload") ? binding.payload : {};
|
|
839
|
+
return client.request(binding.type, input, { responseType: "redweb:result" });
|
|
840
|
+
}
|
|
831
841
|
return client.request("redweb:html", payload);
|
|
832
842
|
}).then((success) => {
|
|
833
843
|
if (success && active()) completed?.();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "redweb-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Browser-first WebSocket client for Redweb",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
27
|
"README.md",
|
|
28
|
+
"CHANGELOG.md",
|
|
28
29
|
"LICENSE"
|
|
29
30
|
],
|
|
30
31
|
"sideEffects": false,
|
|
31
32
|
"scripts": {
|
|
33
|
+
"prepack": "npm run build 1>&2",
|
|
32
34
|
"build": "tsup src/index.ts src/live-html.ts --format esm,cjs --dts --clean --splitting false",
|
|
33
35
|
"typecheck": "tsc --noEmit",
|
|
34
36
|
"test": "npm run check",
|