@hopecloud/jetstream-player 1.3.0-rc.3 → 1.4.0-rc.5
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 +12 -11
- package/dist/{player-bridge.d.ts → bridge/player-bridge.d.ts} +1 -1
- package/dist/{protocol.d.ts → bridge/protocol.d.ts} +1 -1
- package/dist/{player.type.d.ts → bridge/protocol.types.d.ts} +11 -16
- package/dist/{embed-frame.d.ts → embed/embed-frame.d.ts} +1 -1
- package/dist/embed/embed-frame.types.d.ts +12 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +92 -91
- package/dist/{iframe-pip-plugin.d.ts → pip/iframe-pip-plugin.d.ts} +0 -1
- package/dist/player.d.ts +6 -3
- package/dist/player.types.d.ts +10 -0
- package/package.json +2 -11
- /package/dist/{player-transport.d.ts → bridge/player-transport.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @hopecloud/jetstream-player
|
|
2
2
|
|
|
3
|
-
Control an embedded [Jetstream](https://
|
|
3
|
+
Control an embedded [Jetstream](https://docs.hope.cloud/libs/jetstream-player/) player
|
|
4
4
|
from your page — play, pause, seek, mute, read playback state, and subscribe to
|
|
5
5
|
events — across the iframe boundary, with no server glue.
|
|
6
6
|
|
|
7
|
-
**[Full documentation →](https://
|
|
7
|
+
**[Full documentation →](https://docs.hope.cloud/libs/jetstream-player/)**
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -36,26 +36,25 @@ at the given selector.
|
|
|
36
36
|
|
|
37
37
|
- **Commands** — `play()`, `pause()`, `mute()`, `unmute()`, `seekTo(seconds)`,
|
|
38
38
|
`playNext()`, `playPrev()`.
|
|
39
|
-
- **Getters** (Promise-based) — `isMuted()`, `isPaused()`,
|
|
40
|
-
`
|
|
41
|
-
doesn't reply.
|
|
39
|
+
- **Getters** (Promise-based) — `isMuted()`, `isPaused()`, `getCurrentTime()`,
|
|
40
|
+
`getDuration()`. They reject after 5s if the player doesn't reply.
|
|
42
41
|
- **Events** — subscribe via `options.events`: `ready`, `timeupdate`, `play`,
|
|
43
42
|
`pause`, `loadedmetadata`, `ended`, `volumechange`, `error`.
|
|
44
43
|
- **Teardown** — `dispose()` removes listeners and tears down Picture-in-Picture.
|
|
45
44
|
|
|
46
|
-
See the [options](https://
|
|
47
|
-
and [methods](https://
|
|
45
|
+
See the [options](https://docs.hope.cloud/libs/jetstream-player/player-options)
|
|
46
|
+
and [methods](https://docs.hope.cloud/libs/jetstream-player/player-methods)
|
|
48
47
|
reference for the full list.
|
|
49
48
|
|
|
50
49
|
## Targeting a non-prod embed
|
|
51
50
|
|
|
52
51
|
By default the player loads the production embed. Point it at another host
|
|
53
|
-
(staging/dev) with `
|
|
52
|
+
(staging/dev) with `embedOrigin`:
|
|
54
53
|
|
|
55
54
|
```ts
|
|
56
55
|
new JetstreamPlayer('#player', {
|
|
57
56
|
mediaId: 'jsv:xxxxxxxxxx',
|
|
58
|
-
|
|
57
|
+
embedOrigin: 'https://embed-stage.jetstream.studio',
|
|
59
58
|
});
|
|
60
59
|
```
|
|
61
60
|
|
|
@@ -69,8 +68,10 @@ pnpm install
|
|
|
69
68
|
pnpm build # rolldown + .d.ts
|
|
70
69
|
pnpm test # vitest
|
|
71
70
|
pnpm lint
|
|
72
|
-
pnpm
|
|
73
|
-
pnpm docs:dev # vitepress docs
|
|
71
|
+
pnpm type-check
|
|
74
72
|
```
|
|
75
73
|
|
|
74
|
+
Documentation lives in the monorepo's public docs site at
|
|
75
|
+
`docs/cloud/libs/jetstream-player/`, published to docs.hope.cloud.
|
|
76
|
+
|
|
76
77
|
Architecture decisions are recorded in [`adr/`](./adr).
|
|
@@ -1,27 +1,22 @@
|
|
|
1
|
+
export interface PlayerEventMap {
|
|
2
|
+
ready: unknown;
|
|
3
|
+
timeupdate: number;
|
|
4
|
+
play: unknown;
|
|
5
|
+
pause: unknown;
|
|
6
|
+
loadedmetadata: undefined;
|
|
7
|
+
ended: boolean;
|
|
8
|
+
volumechange: number;
|
|
9
|
+
error: unknown;
|
|
10
|
+
}
|
|
1
11
|
export declare const playerListenEvents: readonly ["ready", "timeupdate", "play", "pause", "loadedmetadata", "ended", "volumechange", "error"];
|
|
2
|
-
export type PlayerEvents =
|
|
12
|
+
export type PlayerEvents = (typeof playerListenEvents)[number];
|
|
3
13
|
export type PlayerGetterEvents = 'is-muted' | 'get-video-current-time' | 'get-duration' | 'is-paused';
|
|
4
14
|
export interface PlayerEvent {
|
|
5
15
|
type: PlayerEvents | PlayerGetterEvents;
|
|
6
16
|
value?: unknown;
|
|
7
17
|
}
|
|
8
|
-
export type PlayerEventHandler = (value?: unknown) => void;
|
|
9
18
|
export type PlayerCommandEvent = 'play' | 'pause' | 'mute' | 'unmute' | 'seekTo' | 'play-next' | 'play-prev';
|
|
10
19
|
export interface PlayerCommand {
|
|
11
20
|
name: PlayerCommandEvent | PlayerGetterEvents;
|
|
12
21
|
params?: unknown;
|
|
13
22
|
}
|
|
14
|
-
export interface EmbedFrameOptions {
|
|
15
|
-
mediaId: string;
|
|
16
|
-
playerId?: string;
|
|
17
|
-
region?: 'eu';
|
|
18
|
-
audioLang?: string;
|
|
19
|
-
subtitleLang?: string;
|
|
20
|
-
origin?: string;
|
|
21
|
-
width?: string;
|
|
22
|
-
height?: string;
|
|
23
|
-
}
|
|
24
|
-
export type JetstreamPlayerOptions = {
|
|
25
|
-
sticky?: boolean;
|
|
26
|
-
events?: Partial<Record<PlayerEvents, PlayerEventHandler>>;
|
|
27
|
-
} & EmbedFrameOptions;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface EmbedFrameOptions {
|
|
2
|
+
mediaId: string;
|
|
3
|
+
playerId?: string;
|
|
4
|
+
region?: 'eu';
|
|
5
|
+
audioLang?: string;
|
|
6
|
+
subtitleLang?: string;
|
|
7
|
+
embedOrigin?: string;
|
|
8
|
+
/** @deprecated Use {@link embedOrigin} instead. */
|
|
9
|
+
origin?: string;
|
|
10
|
+
width?: string;
|
|
11
|
+
height?: string;
|
|
12
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export { JetstreamPlayer } from './player';
|
|
2
|
-
export
|
|
2
|
+
export type { JetstreamPlayerOptions, PlayerEventHandler, PlayerEventHandlers, } from './player.types';
|
|
3
|
+
export type { EmbedFrameOptions } from './embed/embed-frame.types';
|
|
4
|
+
export { playerListenEvents } from './bridge/protocol.types';
|
|
5
|
+
export type { PlayerCommand, PlayerCommandEvent, PlayerEvent, PlayerEventMap, PlayerEvents, PlayerGetterEvents, } from './bridge/protocol.types';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
|
-
//#region src/
|
|
2
|
-
const
|
|
1
|
+
//#region src/bridge/protocol.ts
|
|
2
|
+
const encode = (command) => JSON.stringify(command);
|
|
3
|
+
const decode = (raw) => {
|
|
4
|
+
if (typeof raw !== "string") return null;
|
|
5
|
+
try {
|
|
6
|
+
const parsed = JSON.parse(raw);
|
|
7
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.type === "string") return parsed;
|
|
8
|
+
return null;
|
|
9
|
+
} catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/bridge/player-bridge.ts
|
|
15
|
+
const REQUEST_TIMEOUT_MS = 5e3;
|
|
16
|
+
var PlayerBridge = class {
|
|
17
|
+
transport;
|
|
18
|
+
targetOrigin;
|
|
19
|
+
listeners = /* @__PURE__ */ new Set();
|
|
20
|
+
detach;
|
|
21
|
+
constructor(transport, initialTargetOrigin) {
|
|
22
|
+
this.transport = transport;
|
|
23
|
+
this.targetOrigin = initialTargetOrigin;
|
|
24
|
+
this.detach = this.transport.subscribe((message, origin) => {
|
|
25
|
+
const event = decode(message);
|
|
26
|
+
if (!event) return;
|
|
27
|
+
this.targetOrigin = origin;
|
|
28
|
+
this.listeners.forEach((listener) => listener(event));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
send(command) {
|
|
32
|
+
this.transport.send(encode(command), this.targetOrigin);
|
|
33
|
+
}
|
|
34
|
+
subscribe(listener) {
|
|
35
|
+
this.listeners.add(listener);
|
|
36
|
+
return () => {
|
|
37
|
+
this.listeners.delete(listener);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
request(command, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
let off = () => void 0;
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
off();
|
|
45
|
+
reject(/* @__PURE__ */ new Error(`Timed out waiting for "${command.name}" response`));
|
|
46
|
+
}, timeoutMs);
|
|
47
|
+
off = this.subscribe((event) => {
|
|
48
|
+
if (event.type === command.name) {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
off();
|
|
51
|
+
resolve(event.value);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.send(command);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
dispose() {
|
|
58
|
+
this.detach();
|
|
59
|
+
this.listeners.clear();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/bridge/player-transport.ts
|
|
64
|
+
const windowTransport = (iframe) => ({
|
|
65
|
+
send: (message, targetOrigin) => {
|
|
66
|
+
iframe.contentWindow?.postMessage(message, targetOrigin);
|
|
67
|
+
},
|
|
68
|
+
subscribe: (handler) => {
|
|
69
|
+
const listener = (event) => {
|
|
70
|
+
if (event.source !== iframe.contentWindow) return;
|
|
71
|
+
handler(event.data, event.origin);
|
|
72
|
+
};
|
|
73
|
+
window.addEventListener("message", listener);
|
|
74
|
+
return () => {
|
|
75
|
+
window.removeEventListener("message", listener);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/embed/embed-frame.ts
|
|
81
|
+
const DEFAULT_EMBED_ORIGIN = "https://jstre.am";
|
|
3
82
|
const regionOrigin = (origin, region) => {
|
|
4
83
|
const url = new URL(origin);
|
|
5
84
|
if (region === "eu") {
|
|
@@ -11,9 +90,9 @@ const regionOrigin = (origin, region) => {
|
|
|
11
90
|
};
|
|
12
91
|
const buildEmbedSrc = (options) => {
|
|
13
92
|
if (options.mediaId === "") throw new Error("mediaId not provided!");
|
|
14
|
-
const
|
|
93
|
+
const embedOrigin = regionOrigin(options.embedOrigin ?? options.origin ?? DEFAULT_EMBED_ORIGIN, options.region);
|
|
15
94
|
const path = options.playerId ? `/embed/${options.mediaId}/${options.playerId}` : `/embed/${options.mediaId}`;
|
|
16
|
-
const url = new URL(`${
|
|
95
|
+
const url = new URL(`${embedOrigin}${path}`);
|
|
17
96
|
if (options.region === "eu") url.searchParams.append("region", "eu");
|
|
18
97
|
if (options.audioLang) url.searchParams.append("audioLang", options.audioLang.toLowerCase());
|
|
19
98
|
if (options.subtitleLang) url.searchParams.append("subtitleLang", options.subtitleLang.toLowerCase());
|
|
@@ -25,11 +104,11 @@ const mountEmbedFrame = (selector, options) => {
|
|
|
25
104
|
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture";
|
|
26
105
|
iframe.allowFullscreen = true;
|
|
27
106
|
iframe.frameBorder = "0";
|
|
28
|
-
iframe.title = "Jetstream
|
|
107
|
+
iframe.title = "Jetstream Player";
|
|
29
108
|
iframe.src = src;
|
|
30
109
|
iframe.width = options.width || "480px";
|
|
31
110
|
iframe.height = options.height || "270px";
|
|
32
|
-
iframe.classList.add("
|
|
111
|
+
iframe.classList.add("jetstream-player-iframe");
|
|
33
112
|
const parent = document.querySelector(selector);
|
|
34
113
|
if (parent) parent.appendChild(iframe);
|
|
35
114
|
else console.error(`Element matching selector "${selector}" not found.`);
|
|
@@ -39,7 +118,7 @@ const mountEmbedFrame = (selector, options) => {
|
|
|
39
118
|
};
|
|
40
119
|
};
|
|
41
120
|
//#endregion
|
|
42
|
-
//#region src/iframe-pip-plugin.ts
|
|
121
|
+
//#region src/pip/iframe-pip-plugin.ts
|
|
43
122
|
const PiP_STYLES = {
|
|
44
123
|
position: "fixed",
|
|
45
124
|
bottom: "20px",
|
|
@@ -98,90 +177,8 @@ var IFramePiPPlugin = class {
|
|
|
98
177
|
if (this.iframe) if (this.originalIframeStyle) this.iframe.setAttribute("style", this.originalIframeStyle);
|
|
99
178
|
else this.iframe.removeAttribute("style");
|
|
100
179
|
}
|
|
101
|
-
destory() {
|
|
102
|
-
this.destroy();
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
//#endregion
|
|
106
|
-
//#region src/protocol.ts
|
|
107
|
-
const encode = (command) => JSON.stringify(command);
|
|
108
|
-
const decode = (raw) => {
|
|
109
|
-
if (typeof raw !== "string") return null;
|
|
110
|
-
try {
|
|
111
|
-
const parsed = JSON.parse(raw);
|
|
112
|
-
if (typeof parsed === "object" && parsed !== null && typeof parsed.type === "string") return parsed;
|
|
113
|
-
return null;
|
|
114
|
-
} catch {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
//#endregion
|
|
119
|
-
//#region src/player-bridge.ts
|
|
120
|
-
const REQUEST_TIMEOUT_MS = 5e3;
|
|
121
|
-
var PlayerBridge = class {
|
|
122
|
-
transport;
|
|
123
|
-
targetOrigin;
|
|
124
|
-
listeners = /* @__PURE__ */ new Set();
|
|
125
|
-
detach;
|
|
126
|
-
constructor(transport, initialTargetOrigin) {
|
|
127
|
-
this.transport = transport;
|
|
128
|
-
this.targetOrigin = initialTargetOrigin;
|
|
129
|
-
this.detach = this.transport.subscribe((message, origin) => {
|
|
130
|
-
const event = decode(message);
|
|
131
|
-
if (!event) return;
|
|
132
|
-
this.targetOrigin = origin;
|
|
133
|
-
this.listeners.forEach((listener) => listener(event));
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
send(command) {
|
|
137
|
-
this.transport.send(encode(command), this.targetOrigin);
|
|
138
|
-
}
|
|
139
|
-
subscribe(listener) {
|
|
140
|
-
this.listeners.add(listener);
|
|
141
|
-
return () => {
|
|
142
|
-
this.listeners.delete(listener);
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
request(command, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
146
|
-
return new Promise((resolve, reject) => {
|
|
147
|
-
let off = () => void 0;
|
|
148
|
-
const timer = setTimeout(() => {
|
|
149
|
-
off();
|
|
150
|
-
reject(/* @__PURE__ */ new Error(`Timed out waiting for "${command.name}" response`));
|
|
151
|
-
}, timeoutMs);
|
|
152
|
-
off = this.subscribe((event) => {
|
|
153
|
-
if (event.type === command.name) {
|
|
154
|
-
clearTimeout(timer);
|
|
155
|
-
off();
|
|
156
|
-
resolve(event.value);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
this.send(command);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
dispose() {
|
|
163
|
-
this.detach();
|
|
164
|
-
this.listeners.clear();
|
|
165
|
-
}
|
|
166
180
|
};
|
|
167
181
|
//#endregion
|
|
168
|
-
//#region src/player-transport.ts
|
|
169
|
-
const windowTransport = (iframe) => ({
|
|
170
|
-
send: (message, targetOrigin) => {
|
|
171
|
-
iframe.contentWindow?.postMessage(message, targetOrigin);
|
|
172
|
-
},
|
|
173
|
-
subscribe: (handler) => {
|
|
174
|
-
const listener = (event) => {
|
|
175
|
-
if (event.source !== iframe.contentWindow) return;
|
|
176
|
-
handler(event.data, event.origin);
|
|
177
|
-
};
|
|
178
|
-
window.addEventListener("message", listener);
|
|
179
|
-
return () => {
|
|
180
|
-
window.removeEventListener("message", listener);
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
//#endregion
|
|
185
182
|
//#region src/player.ts
|
|
186
183
|
var JetstreamPlayer = class {
|
|
187
184
|
options;
|
|
@@ -272,9 +269,13 @@ var JetstreamPlayer = class {
|
|
|
272
269
|
isPaused() {
|
|
273
270
|
return this.request({ name: "is-paused" });
|
|
274
271
|
}
|
|
275
|
-
|
|
272
|
+
getCurrentTime() {
|
|
276
273
|
return this.request({ name: "get-video-current-time" });
|
|
277
274
|
}
|
|
275
|
+
/** @deprecated Use {@link getCurrentTime} instead. */
|
|
276
|
+
getVideoCurrentTime() {
|
|
277
|
+
return this.getCurrentTime();
|
|
278
|
+
}
|
|
278
279
|
getDuration() {
|
|
279
280
|
return this.request({ name: "get-duration" });
|
|
280
281
|
}
|
|
@@ -285,7 +286,7 @@ var JetstreamPlayer = class {
|
|
|
285
286
|
}
|
|
286
287
|
};
|
|
287
288
|
//#endregion
|
|
288
|
-
//#region src/
|
|
289
|
+
//#region src/bridge/protocol.types.ts
|
|
289
290
|
const playerListenEvents = [
|
|
290
291
|
"ready",
|
|
291
292
|
"timeupdate",
|
package/dist/player.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { PlayerEvents
|
|
1
|
+
import type { PlayerEvents } from './bridge/protocol.types';
|
|
2
|
+
import type { JetstreamPlayerOptions, PlayerEventHandler } from './player.types';
|
|
2
3
|
export declare class JetstreamPlayer {
|
|
3
4
|
private options;
|
|
4
5
|
private readonly listeners;
|
|
@@ -7,8 +8,8 @@ export declare class JetstreamPlayer {
|
|
|
7
8
|
constructor(el: string, options: JetstreamPlayerOptions);
|
|
8
9
|
private registerEvents;
|
|
9
10
|
private emit;
|
|
10
|
-
on(event:
|
|
11
|
-
off(event:
|
|
11
|
+
on<E extends PlayerEvents>(event: E, handler: PlayerEventHandler<E>): () => void;
|
|
12
|
+
off<E extends PlayerEvents>(event: E, handler?: PlayerEventHandler<E>): void;
|
|
12
13
|
private request;
|
|
13
14
|
play(): void;
|
|
14
15
|
pause(): void;
|
|
@@ -19,6 +20,8 @@ export declare class JetstreamPlayer {
|
|
|
19
20
|
playPrev(): void;
|
|
20
21
|
isMuted(): Promise<boolean>;
|
|
21
22
|
isPaused(): Promise<boolean>;
|
|
23
|
+
getCurrentTime(): Promise<number>;
|
|
24
|
+
/** @deprecated Use {@link getCurrentTime} instead. */
|
|
22
25
|
getVideoCurrentTime(): Promise<number>;
|
|
23
26
|
getDuration(): Promise<number>;
|
|
24
27
|
dispose(): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PlayerEventMap, PlayerEvents } from './bridge/protocol.types';
|
|
2
|
+
import type { EmbedFrameOptions } from './embed/embed-frame.types';
|
|
3
|
+
export type PlayerEventHandler<E extends PlayerEvents = PlayerEvents> = (value: PlayerEventMap[E]) => void;
|
|
4
|
+
export type PlayerEventHandlers = {
|
|
5
|
+
[E in PlayerEvents]?: PlayerEventHandler<E>;
|
|
6
|
+
};
|
|
7
|
+
export type JetstreamPlayerOptions = {
|
|
8
|
+
sticky?: boolean;
|
|
9
|
+
events?: PlayerEventHandlers;
|
|
10
|
+
} & EmbedFrameOptions;
|
package/package.json
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hopecloud/jetstream-player",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-rc.5",
|
|
4
4
|
"description": "Jetstream Embed Player SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
|
-
"
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/hopechannel/hopecloud.git",
|
|
10
|
-
"directory": "libs/jetstream-player"
|
|
11
|
-
},
|
|
12
|
-
"homepage": "https://jetstream-player.docs.hope.cloud/",
|
|
7
|
+
"homepage": "https://docs.hope.cloud/libs/jetstream-player/",
|
|
13
8
|
"engines": {
|
|
14
9
|
"node": "24"
|
|
15
10
|
},
|
|
@@ -37,14 +32,10 @@
|
|
|
37
32
|
"happy-dom": "^20.4.0",
|
|
38
33
|
"rolldown": "^1.1.4",
|
|
39
34
|
"typescript": "6.0.3",
|
|
40
|
-
"vitepress": "^1.6.4",
|
|
41
35
|
"vitest": "^4.0.18"
|
|
42
36
|
},
|
|
43
37
|
"scripts": {
|
|
44
38
|
"build": "rolldown --config && tsc --emitDeclarationOnly",
|
|
45
|
-
"docs:dev": "vitepress dev docs",
|
|
46
|
-
"docs:build": "vitepress build docs",
|
|
47
|
-
"docs:preview": "vitepress preview docs",
|
|
48
39
|
"lint": "eslint",
|
|
49
40
|
"lint:fix": "eslint --fix",
|
|
50
41
|
"type-check": "tsc --noEmit",
|
|
File without changes
|