@broadcastingplatforms/player 0.0.0-dev.3802fed → 0.0.0-dev.40838b1

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.
Files changed (42) hide show
  1. package/README.md +220 -0
  2. package/dist/bp-player.js +424 -321
  3. package/dist/bp-player.mjs +424 -321
  4. package/dist/bp-player.standalone.mjs +425 -322
  5. package/dist/bplive/service.d.ts +4 -2
  6. package/dist/components/bp-default-ui.d.ts +10 -10
  7. package/dist/components/bp-error-display.d.ts +2 -0
  8. package/dist/components/bp-player.d.ts +18 -37
  9. package/dist/components/index.d.ts +1 -0
  10. package/dist/components/video-rendition-list.d.ts +38 -0
  11. package/dist/core/index.d.ts +2 -2
  12. package/dist/core/player-core.d.ts +42 -11
  13. package/dist/core/state.d.ts +1 -0
  14. package/dist/index.d.ts +2 -2
  15. package/dist/providers/contract.d.ts +9 -0
  16. package/dist/util/attribute.d.ts +0 -3
  17. package/package.json +5 -3
  18. package/dist/bp-player.js.map +0 -7
  19. package/dist/bp-player.mjs.map +0 -7
  20. package/dist/bp-player.standalone.mjs.map +0 -7
  21. package/dist/bplive/index.d.ts.map +0 -1
  22. package/dist/bplive/service.d.ts.map +0 -1
  23. package/dist/bplive/types.d.ts.map +0 -1
  24. package/dist/components/bp-default-ui.d.ts.map +0 -1
  25. package/dist/components/bp-error-display.d.ts.map +0 -1
  26. package/dist/components/bp-overlay.d.ts.map +0 -1
  27. package/dist/components/bp-player.d.ts.map +0 -1
  28. package/dist/components/index.d.ts.map +0 -1
  29. package/dist/core/index.d.ts.map +0 -1
  30. package/dist/core/player-core.d.ts.map +0 -1
  31. package/dist/core/state-receiver.d.ts.map +0 -1
  32. package/dist/core/state.d.ts.map +0 -1
  33. package/dist/elements/hls-video.d.ts.map +0 -1
  34. package/dist/elements/index.d.ts.map +0 -1
  35. package/dist/elements/livekit-video.d.ts.map +0 -1
  36. package/dist/elements/nano-video.d.ts.map +0 -1
  37. package/dist/index.d.ts.map +0 -1
  38. package/dist/providers/contract.d.ts.map +0 -1
  39. package/dist/providers/index.d.ts.map +0 -1
  40. package/dist/styles/index.d.ts.map +0 -1
  41. package/dist/util/attribute.d.ts.map +0 -1
  42. package/dist/util/index.d.ts.map +0 -1
@@ -5,8 +5,10 @@ export interface BPLiveResolvedResult {
5
5
  source: ResolvedPlayerSource;
6
6
  contentType: ContentType;
7
7
  poster?: string;
8
- /** Aspect ratio based on orientation (portrait: 9/16, landscape: 16/9) */
9
- aspectRatio?: string;
8
+ /** Video width from media metadata */
9
+ videoWidth?: number;
10
+ /** Video height from media metadata */
11
+ videoHeight?: number;
10
12
  }
11
13
  export declare class BPLiveError extends Error {
12
14
  code: string;
@@ -1,11 +1,10 @@
1
1
  import { LitElement, PropertyValues } from 'lit';
2
2
  import type { PlayerCore } from '../core/player-core';
3
- import type { ProviderConfig, PlayerSources } from '../providers/contract';
3
+ import type { ProviderConfig, SourceDescription } from '../providers/contract';
4
4
  import 'media-chrome';
5
5
  import 'media-chrome/menu';
6
6
  import './bp-player';
7
7
  import './bp-error-display';
8
- import './bp-overlay';
9
8
  import type { BPLiveService } from '../bplive/service';
10
9
  export type BPDefaultUIReadyEvent = CustomEvent<PlayerCore>;
11
10
  declare global {
@@ -24,7 +23,7 @@ export declare class BPDefaultUI extends LitElement {
24
23
  protected createRenderRoot(): HTMLElement | DocumentFragment;
25
24
  connectedCallback(): void;
26
25
  disconnectedCallback(): void;
27
- sources?: PlayerSources;
26
+ source?: SourceDescription;
28
27
  autoplay: boolean;
29
28
  muted: boolean;
30
29
  loop: boolean;
@@ -42,21 +41,22 @@ export declare class BPDefaultUI extends LitElement {
42
41
  private _player;
43
42
  private _providerType;
44
43
  private _error;
45
- private _overlayType;
46
44
  private _connectionState;
47
- private _hasError;
48
- private _hasCustomTopChrome;
49
- private _hasCustomCenteredChrome;
50
- private _hasCustomBottomChrome;
45
+ private _showEndedOverlay;
51
46
  private _cleanupListeners;
52
47
  get player(): PlayerCore | null;
53
48
  get mediaController(): HTMLElement | null;
54
49
  get bpLive(): BPLiveService | null;
55
- private _detectCustomChrome;
56
50
  private detectMobile;
51
+ private _getPoster;
57
52
  protected firstUpdated(_changedProperties: PropertyValues): void;
58
53
  protected updated(_changedProperties: PropertyValues): void;
59
- private _setInitialAspectRatioFromSources;
54
+ /** Set initial video dimensions from preferredOrientation hint */
55
+ private _setInitialVideoDimensionsFromSources;
56
+ /** Update video dimension CSS variables */
57
+ private _updateVideoDimensions;
58
+ /** Clear video dimension CSS variables */
59
+ private _clearVideoDimensions;
60
60
  private _moveSlottedContent;
61
61
  private setupPlayer;
62
62
  private setupPlayerListeners;
@@ -12,11 +12,13 @@ declare global {
12
12
  * @slot heading - Custom heading text (for i18n)
13
13
  * @slot message - Custom message (overrides error.message)
14
14
  * @slot code - Custom error code display
15
+ * @slot actions - Action buttons (e.g., fullscreen button, retry button)
15
16
  *
16
17
  * @csspart icon - The icon container
17
18
  * @csspart heading - The heading element
18
19
  * @csspart message - The message element
19
20
  * @csspart code - The error code element
21
+ * @csspart actions - The actions container
20
22
  */
21
23
  export declare class BPErrorDisplay extends LitElement {
22
24
  static styles: import("lit").CSSResult;
@@ -1,8 +1,9 @@
1
1
  import { LitElement, type PropertyValues } from 'lit';
2
2
  import { type PlayerCore } from '../core/player-core';
3
3
  import type { PlayerState } from '../core/state';
4
- import type { ProviderType, ProviderConfig, PlayerSources } from '../providers/contract';
4
+ import type { ProviderType, ProviderConfig, SourceDescription } from '../providers/contract';
5
5
  import type { BPLiveService } from '../bplive/service';
6
+ import { VideoRenditionList } from './video-rendition-list';
6
7
  export type BPPlayerReadyEvent = CustomEvent<PlayerCore>;
7
8
  declare global {
8
9
  interface HTMLElementTagNameMap {
@@ -12,48 +13,25 @@ declare global {
12
13
  'ready': BPPlayerReadyEvent;
13
14
  }
14
15
  }
15
- interface VideoRendition {
16
- id: string;
17
- width: number;
18
- height: number;
19
- bitrate: number;
20
- selected: boolean;
21
- }
22
- declare class VideoRenditionList extends EventTarget {
23
- [index: number]: VideoRendition;
24
- private _player;
25
- private _renditions;
26
- private _cleanup;
27
- constructor(player: BPPlayer);
28
- get length(): number;
29
- [Symbol.iterator](): Iterator<VideoRendition>;
30
- get selectedIndex(): number;
31
- set selectedIndex(index: number);
32
- private _updateSelection;
33
- _syncFromPlayer(): void;
34
- _setupListeners(): void;
35
- _destroy(): void;
36
- }
37
16
  export declare class BPPlayer extends LitElement {
38
17
  protected createRenderRoot(): HTMLElement | DocumentFragment;
39
18
  connectedCallback(): void;
40
- sources?: PlayerSources;
19
+ source?: SourceDescription;
41
20
  autoplay: boolean;
42
21
  defaultMuted: boolean;
43
22
  loop: boolean;
44
- poster?: string;
45
23
  scaling: 'letterbox' | 'crop' | 'fill';
46
24
  aspectRatio?: string;
47
25
  config?: ProviderConfig;
48
26
  debug: boolean;
49
27
  private _playerCore;
50
- private _ready;
51
- private _resolvedPoster;
52
28
  private containerRef;
53
29
  private providerContainer;
54
30
  private eventCleanup;
55
31
  private stateReceivers;
56
32
  private _mutationObserver;
33
+ private _videoRenditions;
34
+ private _hasDispatchedReady;
57
35
  get player(): PlayerCore | null;
58
36
  get playerState(): PlayerState | null;
59
37
  get bpLive(): BPLiveService | null;
@@ -78,28 +56,31 @@ export declare class BPPlayer extends LitElement {
78
56
  get videoHeight(): number;
79
57
  get videoElement(): HTMLVideoElement | null;
80
58
  get providerType(): ProviderType | null;
81
- get videoRenditions(): VideoRenditionList;
82
- private _videoRenditions;
59
+ get videoRenditions(): VideoRenditionList | null;
83
60
  disconnectedCallback(): void;
84
61
  protected firstUpdated(_changedProperties: PropertyValues): void;
85
62
  protected updated(changedProperties: PropertyValues): void;
86
- private resolveSourcesArray;
63
+ /**
64
+ * Initialize player core once. Called in firstUpdated.
65
+ */
66
+ private initPlayerCore;
67
+ /**
68
+ * Load source into player core. Player core handles provider switching internally.
69
+ */
70
+ private loadSource;
87
71
  private handleMutation;
88
72
  private registerStateReceiver;
89
73
  private unregisterStateReceiver;
90
74
  private propagateStateToAllReceivers;
91
75
  private setupEventForwarding;
92
76
  private updateStateAttributes;
93
- private initPlayer;
94
- private loadPlayableSource;
95
77
  private destroyPlayer;
96
- /** Set --bp-aspect-ratio CSS variable if not already defined by consumer */
97
- private setAspectRatioVariable;
78
+ /** Update video dimension CSS variables */
79
+ updateVideoDimensions(width: number, height: number): void;
80
+ /** Clear video dimension CSS variables */
81
+ private clearVideoDimensions;
98
82
  private getContainerClasses;
99
- private getPosterClasses;
100
83
  private getContainerStyle;
101
- private getEffectivePoster;
102
84
  protected render(): import("lit").TemplateResult<1>;
103
85
  }
104
- export {};
105
86
  //# sourceMappingURL=bp-player.d.ts.map
@@ -2,4 +2,5 @@ export { BPPlayer, type BPPlayerReadyEvent } from './bp-player';
2
2
  export { BPDefaultUI, type BPDefaultUIReadyEvent } from './bp-default-ui';
3
3
  export { BPErrorDisplay } from './bp-error-display';
4
4
  export { BPOverlay, type OverlayType } from './bp-overlay';
5
+ export { VideoRenditionList, type VideoRendition, type VideoRenditionHost } from './video-rendition-list';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,38 @@
1
+ import type { PlayerCore } from '../core/player-core';
2
+ /**
3
+ * Represents a single video rendition/quality level.
4
+ * Compatible with media-chrome's VideoRendition interface.
5
+ */
6
+ export interface VideoRendition {
7
+ id: string;
8
+ width: number;
9
+ height: number;
10
+ bitrate: number;
11
+ selected: boolean;
12
+ }
13
+ /**
14
+ * Interface for the player host that provides access to PlayerCore.
15
+ */
16
+ export interface VideoRenditionHost {
17
+ readonly player: PlayerCore | null;
18
+ }
19
+ /**
20
+ * VideoRenditionList provides media-chrome compatibility for quality selection.
21
+ * It exposes video quality levels as an iterable list with selection support.
22
+ */
23
+ export declare class VideoRenditionList extends EventTarget {
24
+ [index: number]: VideoRendition;
25
+ private _host;
26
+ private _renditions;
27
+ private _cleanup;
28
+ constructor(host: VideoRenditionHost);
29
+ get length(): number;
30
+ [Symbol.iterator](): Iterator<VideoRendition>;
31
+ get selectedIndex(): number;
32
+ set selectedIndex(index: number);
33
+ private _updateSelection;
34
+ _syncFromPlayer(): void;
35
+ _setupListeners(): void;
36
+ _destroy(): void;
37
+ }
38
+ //# sourceMappingURL=video-rendition-list.d.ts.map
@@ -1,6 +1,6 @@
1
1
  export { createPlayerCore, PlayerCoreImpl } from './player-core';
2
- export type { PlayerCore, PlayerCoreEventMap, PlayerCoreEventType } from './player-core';
3
- export { createInitialState, classifyNanoPlayerError, NANOPLAYER_NO_REPLAY_CODES } from './state';
2
+ export type { PlayerCore, PlayerCoreEventMap, PlayerCoreEventType, SourceLoadResult } from './player-core';
3
+ export { createInitialState, classifyNanoPlayerError, classifyLiveKitError, NANOPLAYER_NO_REPLAY_CODES } from './state';
4
4
  export type { PlayerState, QualityLevel, PresentationMode, ConnectionState, StreamType, ProviderType, PlayerError, ErrorCategory, } from './state';
5
5
  export { StateReceiverMixin, StateReceiverProps, isStateReceiverElement, forEachStateReceiverElement, propagateStateToReceiver, removeStateFromReceiver, } from './state-receiver';
6
6
  export type { StateReceiverElement, StateReceiverPropertyMap } from './state-receiver';
@@ -1,5 +1,5 @@
1
1
  import type { PlayerState, QualityLevel, PresentationMode, ConnectionState, StreamType, PlayerError } from './state';
2
- import type { PlayerSource, ProviderConfig } from '../providers/contract';
2
+ import type { ProviderType, PlayerSource, ProviderConfig } from '../providers/contract';
3
3
  import { BPLiveService } from '../bplive/service';
4
4
  export interface PlayerCoreEventMap {
5
5
  play: void;
@@ -17,6 +17,7 @@ export interface PlayerCoreEventMap {
17
17
  currentTime: number;
18
18
  duration: number;
19
19
  };
20
+ emptied: void;
20
21
  loadstart: void;
21
22
  loadedmetadata: {
22
23
  duration: number;
@@ -86,16 +87,35 @@ type EventListener<T> = (event: T) => void;
86
87
  export type CustomVideoElement = HTMLVideoElement & {
87
88
  nativeEl: HTMLVideoElement;
88
89
  };
90
+ /**
91
+ * Result returned when a source is loaded, containing metadata from the source.
92
+ */
93
+ export interface SourceLoadResult {
94
+ poster?: string;
95
+ videoWidth?: number;
96
+ videoHeight?: number;
97
+ }
89
98
  export interface PlayerCore {
90
99
  readonly state: PlayerState;
91
100
  readonly videoElement: HTMLVideoElement | null;
92
101
  readonly bpLive: BPLiveService | null;
102
+ /** Whether the player is ready (attached and can accept sources) */
103
+ readonly ready: boolean;
104
+ /** Current provider type based on loaded source */
105
+ readonly providerType: ProviderType | null;
93
106
  addEventListener<K extends PlayerCoreEventType>(type: K | K[], listener: EventListener<PlayerCoreEventMap[K]>): void;
94
107
  removeEventListener<K extends PlayerCoreEventType>(type: K | K[], listener: EventListener<PlayerCoreEventMap[K]>): void;
95
- loadSource(source: string | PlayerSource, container: HTMLElement, config?: ProviderConfig): Promise<{
96
- poster?: string;
97
- aspectRatio?: string;
98
- } | void>;
108
+ /**
109
+ * Attach the player to a container element. Call once during initialization.
110
+ * After attaching, you can set sources via the source property or loadSource().
111
+ */
112
+ attach(container: HTMLElement, config?: ProviderConfig): void;
113
+ /**
114
+ * Load a source. Handles provider switching automatically.
115
+ * If source type changes (e.g., video -> nano), the player will
116
+ * destroy the old element and create a new one.
117
+ */
118
+ loadSource(source: string | PlayerSource, container?: HTMLElement, config?: ProviderConfig): Promise<SourceLoadResult | void>;
99
119
  unloadSource(): void;
100
120
  play(): Promise<void>;
101
121
  pause(): void;
@@ -106,7 +126,7 @@ export interface PlayerCore {
106
126
  setPlaybackRate(rate: number): void;
107
127
  setTargetQuality(quality: QualityLevel | null): void;
108
128
  setQuality(quality: QualityLevel | null): void;
109
- setFullscreen(fullscreen: boolean): void;
129
+ setFullscreen(fullscreen: boolean): Promise<void>;
110
130
  setPresentationMode(mode: PresentationMode): void;
111
131
  destroy(): void;
112
132
  }
@@ -114,22 +134,32 @@ export declare class PlayerCoreImpl implements PlayerCore {
114
134
  private _state;
115
135
  private _mediaElement;
116
136
  private _container;
137
+ private _config;
117
138
  private _listeners;
118
139
  private _eventCleanup;
119
140
  private _destroyed;
120
141
  private _bpLive;
142
+ private _currentProviderType;
143
+ private _ready;
121
144
  constructor();
122
145
  get state(): PlayerState;
123
146
  get videoElement(): HTMLVideoElement | null;
124
147
  get bpLive(): BPLiveService | null;
148
+ get ready(): boolean;
149
+ get providerType(): ProviderType | null;
125
150
  addEventListener<K extends PlayerCoreEventType>(type: K | K[], listener: EventListener<PlayerCoreEventMap[K]>): void;
126
151
  removeEventListener<K extends PlayerCoreEventType>(type: K | K[], listener: EventListener<PlayerCoreEventMap[K]>): void;
127
152
  private dispatch;
128
153
  private updateState;
129
- loadSource(source: string | PlayerSource, container: HTMLElement, config?: ProviderConfig): Promise<{
130
- poster?: string;
131
- aspectRatio?: string;
132
- } | void>;
154
+ /**
155
+ * Attach the player to a container. Call once during initialization.
156
+ */
157
+ attach(container: HTMLElement, config?: ProviderConfig): void;
158
+ loadSource(source: string | PlayerSource, container?: HTMLElement, config?: ProviderConfig): Promise<SourceLoadResult | void>;
159
+ /**
160
+ * Destroy the current media element and clean up listeners.
161
+ */
162
+ private destroyMediaElement;
133
163
  private createMediaElement;
134
164
  private attachMediaElementListeners;
135
165
  private handleMediaEvent;
@@ -143,7 +173,8 @@ export declare class PlayerCoreImpl implements PlayerCore {
143
173
  setPlaybackRate(rate: number): void;
144
174
  setTargetQuality(quality: QualityLevel | null): void;
145
175
  setQuality(quality: QualityLevel | null): void;
146
- setFullscreen(fullscreen: boolean): void;
176
+ private _getFullscreenTarget;
177
+ setFullscreen(fullscreen: boolean): Promise<void>;
147
178
  setPresentationMode(mode: PresentationMode): void;
148
179
  destroy(): void;
149
180
  }
@@ -47,5 +47,6 @@ export interface PlayerError {
47
47
  }
48
48
  export declare const NANOPLAYER_NO_REPLAY_CODES: readonly [1005, 1007, 1008, 1009, 3001, 3002, 3003, 3004, 3005, 3100, 3101, 3200, 4003];
49
49
  export declare function classifyNanoPlayerError(code: number): ErrorCategory;
50
+ export declare function classifyLiveKitError(code: number): ErrorCategory;
50
51
  export declare function createInitialState(): PlayerState;
51
52
  //# sourceMappingURL=state.d.ts.map
package/dist/index.d.ts CHANGED
@@ -7,11 +7,11 @@ export { Attribute, toggleAttribute } from './util/attribute';
7
7
  export { HlsVideoElement, HlsVideo, Hls, NanoVideoElement, NanoVideo, LiveKitVideoElement, LiveKitVideo, } from './elements/index';
8
8
  export { createPlayerCore, PlayerCoreImpl } from './core/player-core';
9
9
  export type { PlayerCore, PlayerCoreEventMap, PlayerCoreEventType, CustomVideoElement } from './core/player-core';
10
- export { createInitialState, classifyNanoPlayerError, NANOPLAYER_NO_REPLAY_CODES } from './core/state';
10
+ export { createInitialState, classifyNanoPlayerError, classifyLiveKitError, NANOPLAYER_NO_REPLAY_CODES } from './core/state';
11
11
  export type { PlayerState, QualityLevel, PresentationMode, ConnectionState, StreamType, ContentType, PlayerError, ErrorCategory, } from './core/state';
12
12
  export { StateReceiverMixin, StateReceiverProps, isStateReceiverElement, forEachStateReceiverElement, propagateStateToReceiver, removeStateFromReceiver, } from './core/state-receiver';
13
13
  export type { StateReceiverElement, StateReceiverPropertyMap } from './core/state-receiver';
14
- export type { ProviderType, ProviderConfig, VideoProviderConfig, NanoProviderConfig, LiveKitProviderConfig, PlayerSource, ResolvedPlayerSource, VideoSource, NanoSource, LiveKitSource, PosterSource, PlayerSourceItem, PlayerSources, } from './providers/contract';
14
+ export type { ProviderType, ProviderConfig, VideoProviderConfig, NanoProviderConfig, LiveKitProviderConfig, PlayerSource, ResolvedPlayerSource, VideoSource, NanoSource, LiveKitSource, PosterSource, PlayerSourceItem, PlayerSources, SourceDescription, } from './providers/contract';
15
15
  export { BPLiveService, BPLiveError, type BPLiveResolvedResult } from './bplive/service';
16
16
  export { isBPLiveSource, isBPLiveStreamSource, isBPLiveClipSource, } from './bplive/types';
17
17
  export type { BPLiveConfig, BPLiveSource, BPLiveStreamSource, BPLiveClipSource, BPLiveStream, BPLiveStreamResponse, BPLiveClip, BPLiveClipResponse, BPLiveChannel, BPLiveActiveStream, BPLivePlayerSource, BPLiveLiveKitPlayerSource, BPLiveNanoPlayerSource, BPLiveClipMedia, } from './bplive/types';
@@ -51,6 +51,15 @@ export type PosterSource = {
51
51
  };
52
52
  export type PlayerSourceItem = PlayerSource | PosterSource;
53
53
  export type PlayerSources = PlayerSourceItem[];
54
+ /**
55
+ * Source description containing sources and optional metadata.
56
+ */
57
+ export interface SourceDescription {
58
+ /** Array of playable sources */
59
+ sources: PlayerSource[];
60
+ /** Poster image URL */
61
+ poster?: string;
62
+ }
54
63
  export interface ProviderConfig {
55
64
  libraryLocation?: string;
56
65
  video?: VideoProviderConfig;
@@ -1,7 +1,5 @@
1
1
  /**
2
2
  * Centralized HTML attributes used by BP Player components.
3
- *
4
- * Following theoplayer's pattern for consistent attribute naming.
5
3
  */
6
4
  export declare enum Attribute {
7
5
  CONFIGURATION = "configuration",
@@ -10,7 +8,6 @@ export declare enum Attribute {
10
8
  AUTOPLAY = "autoplay",
11
9
  MUTED = "muted",
12
10
  LOOP = "loop",
13
- POSTER = "poster",
14
11
  SCALING = "scaling",
15
12
  ASPECT_RATIO = "aspect-ratio",
16
13
  DEBUG = "debug",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@broadcastingplatforms/player",
3
- "version": "0.0.0-dev.3802fed",
3
+ "version": "0.0.0-dev.40838b1",
4
4
  "description": "Universal video player web component built with Lit",
5
5
  "type": "module",
6
6
  "main": "dist/bp-player.js",
@@ -36,7 +36,8 @@
36
36
  "./package.json": "./package.json"
37
37
  },
38
38
  "files": [
39
- "dist/"
39
+ "dist/",
40
+ "!**/*.map"
40
41
  ],
41
42
  "dependencies": {
42
43
  "better-call": "^1.0.6",
@@ -49,6 +50,7 @@
49
50
  },
50
51
  "devDependencies": {
51
52
  "@types/node": "^22.10.2",
53
+ "concurrently": "^9.1.2",
52
54
  "esbuild": "^0.24.0",
53
55
  "typescript": "^5.7.2",
54
56
  "vite": "^6.0.5"
@@ -62,7 +64,7 @@
62
64
  "build:types": "tsc --emitDeclarationOnly",
63
65
  "build:bundle": "node build.mjs",
64
66
  "build:prod": "NODE_ENV=production pnpm build",
65
- "dev": "node build.mjs --watch",
67
+ "dev": "concurrently \"tsc --emitDeclarationOnly --watch --preserveWatchOutput\" \"node build.mjs --watch\"",
66
68
  "dev:demo": "vite"
67
69
  }
68
70
  }