@3dsource/angular-unreal-module 0.0.156 → 0.0.158

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 CHANGED
@@ -1,412 +1,212 @@
1
1
  # @3dsource/angular-unreal-module
2
2
 
3
- A set of standalone Angular components, services, and providers for integrating Unreal Engine (WebRTC) scenes into Angular applications. It facilitates communication between Angular and Unreal Engine and enables interactive 3D experiences.
3
+ Standalone Angular integration for Unreal Engine Pixel Streaming. The package
4
+ provides the scene component, WebRTC and signalling lifecycle, NgRx state,
5
+ command/callback APIs, reconnection, file transfer and telemetry.
4
6
 
5
- ## Overview
7
+ ## Requirements
6
8
 
7
- This package provides:
8
-
9
- - Standalone Unreal scene component to embed UE stream
10
- - Communication bridge (commands, UI interactions, input data)
11
- - Callback listener for Unreal events and command responses
12
- - NgRx state and effects for 3D stream lifecycle
13
- - Config and utilities for telemetry, errors, and regions ping
14
- - Auto-reconnection support for WebRTC/DataChannel failures
15
- - File receiving from Unreal Engine
16
- - Analytics, FPS monitoring, and stream status telemetry
17
- - Playwright testing mode with mock services
18
-
19
- ## Installation
20
-
21
- ### Prerequisites
22
-
23
- - Angular `>=19.0.0 <23.0.0`
24
- - NgRx store and effects `>=19.0.0 <23.0.0`
25
- - Angular CDK `>=19.0.0 <23.0.0` — used for dialog overlays
9
+ - Angular, Angular CDK and Angular Forms `>=19.0.0 <23.0.0`
10
+ - NgRx Store and Effects `>=19.0.0 <23.0.0`
26
11
  - RxJS `>=7.8.0 <8.0.0`
27
- - `provideHttpClient()` — required by internal services (telemetry, signalling, regions ping, error reporting)
28
-
29
- ### Peer Dependencies
30
-
31
- This library requires the following peer dependencies:
32
-
33
- ```json
34
- {
35
- "@3dsource/source-ui-native": ">=1.0.9",
36
- "@3dsource/types-unreal": ">=0.0.7",
37
- "@3dsource/utils": ">=1.0.21",
38
- "@angular/cdk": ">=19.0.0 <23.0.0",
39
- "@angular/common": ">=19.0.0 <23.0.0",
40
- "@angular/core": ">=19.0.0 <23.0.0",
41
- "@angular/forms": ">=19.0.0 <23.0.0",
42
- "@angular/platform-browser": ">=19.0.0 <23.0.0",
43
- "@ngrx/effects": ">=19.0.0 <23.0.0",
44
- "@ngrx/store": ">=19.0.0 <23.0.0",
45
- "rxjs": ">=7.8.0 <8.0.0"
46
- }
47
- ```
12
+ - `@3dsource/source-ui-native >=1.0.9`
13
+ - `@3dsource/types-unreal >=0.0.7`
14
+ - `@3dsource/utils >=1.0.21`
15
+ - `provideHttpClient()` in the host application
48
16
 
49
- ### Library Installation
17
+ ## Installation
50
18
 
51
19
  ```shell
52
- npm i @3dsource/angular-unreal-module
20
+ pnpm add @3dsource/angular-unreal-module @3dsource/source-ui-native @3dsource/types-unreal @3dsource/utils
53
21
  ```
54
22
 
55
- ## Usage
23
+ The package is standalone and does not expose an NgModule.
56
24
 
57
- The API is fully standalone (no NgModule). Use providers and components as shown below.
25
+ ## Setup
58
26
 
59
- ### 1) Provide the state and config at the application root
27
+ ### 1. Register state and configuration once
60
28
 
61
- Add providers in your application bootstrap (e.g., `app.config.ts`):
29
+ Add the Unreal feature state, HTTP client and configuration at the application
30
+ root. `UNREAL_CONFIG` is required, although all its fields are optional.
62
31
 
63
- > **⚠️ Important:** `UNREAL_CONFIG` is **required** — multiple internal services inject it without `{ optional: true }`. Omitting it will cause a `NullInjectorError` at runtime. You can provide it with an empty object `{}` as a minimum.
64
-
65
- ```ts
66
- import { ApplicationConfig } from '@angular/core';
67
- import { provideRouter } from '@angular/router';
32
+ <!-- prettier-ignore -->
33
+ ```typescript
68
34
  import { provideHttpClient } from '@angular/common/http';
35
+ import type { ApplicationConfig } from '@angular/core';
69
36
  import { provideStore } from '@ngrx/store';
70
- import { provideUnrealState, UNREAL_CONFIG } from '@3dsource/angular-unreal-module';
37
+ import {
38
+ provideUnrealState,
39
+ UNREAL_CONFIG,
40
+ type UnrealInitialConfig,
41
+ } from '@3dsource/angular-unreal-module';
42
+
43
+ const unrealConfig = {
44
+ regionsPingUrl: 'https://datacenter.3dsource.com/regions/',
45
+ dataChannelConnectionTimeout: 8000,
46
+ fpsMonitor: false,
47
+ autoHighResolution: false,
48
+ } satisfies UnrealInitialConfig;
71
49
 
72
50
  export const appConfig: ApplicationConfig = {
73
51
  providers: [
74
- provideRouter([]),
75
52
  provideHttpClient(),
76
-
77
- // Root NgRx (if not already added in your app)
78
53
  provideStore(),
79
54
  provideUnrealState(),
80
-
81
- // Required: Unreal initial configuration
82
- {
83
- provide: UNREAL_CONFIG,
84
- useValue: {
85
- customErrorsEndpoint: '', // Endpoint for custom error reporting
86
- commandTelemetryReceiver: '', // Endpoint for command telemetry
87
- regionsPingUrl: '', // URL prefix for regions latency ping
88
- screenLockerContainerId: '', // DOM container id for screen locker overlay
89
- dataChannelConnectionTimeout: 8000, // Timeout in ms for data channel connection (default: 8000)
90
- streamTelemetryV2Url: '', // Endpoint for stream-status telemetry
91
- fpsMonitor: false, // Enable FPS monitoring
92
- autoHighResolution: false, // Raise resolution after the scene becomes idle
93
- playwright: false, // Mirrors the provider flag for services/effects
94
- },
95
- },
55
+ { provide: UNREAL_CONFIG, useValue: unrealConfig },
96
56
  ],
97
57
  };
98
58
  ```
99
59
 
100
- #### Minimal configuration
60
+ Omit `provideStore()` when the root NgRx store is already configured.
101
61
 
102
- If you don't need custom endpoints, provide `UNREAL_CONFIG` with an empty object:
62
+ Available configuration fields:
103
63
 
104
- ```ts
105
- { provide: UNREAL_CONFIG, useValue: {} },
106
- provideUnrealState(),
107
- ```
64
+ | Field | Purpose |
65
+ | ------------------------------ | ---------------------------------------------- |
66
+ | `regionsPingUrl` | Region latency endpoint |
67
+ | `dataChannelConnectionTimeout` | DataChannel connection timeout in ms |
68
+ | `customErrorsEndpoint` | Custom error reporting endpoint |
69
+ | `commandTelemetryReceiver` | Command telemetry endpoint |
70
+ | `streamTelemetryV2Url` | Stream lifecycle telemetry endpoint |
71
+ | `screenLockerContainerId` | Container used by the screen-locker overlay |
72
+ | `fpsMonitor` | Enables FPS monitoring |
73
+ | `autoHighResolution` | Raises resolution after the scene becomes idle |
74
+ | `playwright` | Enables the test-specific service behaviour |
75
+
76
+ Use `{ provide: UNREAL_CONFIG, useValue: {} }` for the minimal configuration.
77
+
78
+ ### 2. Boot the engine on a lazy route
108
79
 
109
- Every `UnrealInitialConfig` field is optional, but the `UNREAL_CONFIG` provider
110
- itself is required. Available fields are `playwright`,
111
- `customErrorsEndpoint`, `commandTelemetryReceiver`, `regionsPingUrl`,
112
- `screenLockerContainerId`, `dataChannelConnectionTimeout`,
113
- `streamTelemetryV2Url`, `fpsMonitor` and `autoHighResolution`.
80
+ Lazy-load the route file from the application router:
114
81
 
115
- ### 2) Boot the engine in each lazy 3D route
82
+ <!-- prettier-ignore -->
83
+ ```typescript
84
+ import type { Routes } from '@angular/router';
116
85
 
117
- `provideUnrealModule()` registers the effects and initializes the streaming
118
- services. Put it on every lazy route that renders a 3D scene:
86
+ export const APP_ROUTES: Routes = [
87
+ {
88
+ path: 'stream',
89
+ loadChildren: () =>
90
+ import('./stream/stream.routes').then((module) => module.STREAM_ROUTES),
91
+ },
92
+ ];
93
+ ```
119
94
 
120
- ```ts
121
- import { Routes } from '@angular/router';
95
+ Register `provideUnrealModule()` inside that lazy route file:
96
+
97
+ <!-- prettier-ignore -->
98
+ ```typescript
99
+ import type { Routes } from '@angular/router';
122
100
  import { provideUnrealModule } from '@3dsource/angular-unreal-module';
101
+ import { StreamComponent } from './stream.component';
123
102
 
124
103
  export const STREAM_ROUTES: Routes = [
125
104
  {
126
- path: ':id',
127
- loadComponent: () => import('./stream.component').then((module) => module.StreamComponent),
105
+ path: '',
106
+ component: StreamComponent,
128
107
  providers: [provideUnrealModule()],
129
108
  },
130
109
  ];
131
110
  ```
132
111
 
133
- Keep `provideUnrealState()` and `UNREAL_CONFIG` at the root. Keeping
134
- `provideUnrealModule()` in lazy routes also keeps the streaming engine out of
135
- the initial application bundle.
136
-
137
- ### 3) Use the Unreal scene component
112
+ Keep `provideUnrealState()` and `UNREAL_CONFIG` at the application root.
113
+ The `loadChildren()` boundary keeps the streaming engine out of the initial
114
+ bundle. Route-scoping `provideUnrealModule()` tears down its effects when the
115
+ route is left.
138
116
 
139
- Import the component into a standalone component and use it in the template.
117
+ ### 3. Render the scene
140
118
 
141
- ```ts
142
- import { Component } from '@angular/core';
119
+ ```typescript
120
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
143
121
  import { UnrealSceneComponent } from '@3dsource/angular-unreal-module';
144
122
 
145
123
  @Component({
146
- selector: 'app-root',
147
- standalone: true,
124
+ selector: 'app-stream',
148
125
  imports: [UnrealSceneComponent],
149
- template: ` <app-unreal-scene [isStudio]="false" [useContainerAsSizeProvider]="true" [resolutionSize]="{ width: 1920, height: 1080 }" (changeMouseOverScene)="onHover($event)" /> `,
126
+ template: `<app-unreal-scene />`,
127
+ changeDetection: ChangeDetectionStrategy.OnPush,
150
128
  })
151
- export class AppComponent {
152
- onHover(isOver: boolean) {
153
- // handle mouse over scene
154
- }
155
- }
156
- ```
157
-
158
- Component selector: `<app-unreal-scene>`
159
-
160
- Inputs:
161
-
162
- | Input | Type | Default |
163
- | ---------------------------- | ----------------------------------- | ------------------------------- |
164
- | `isStudio` | `boolean` | `false` |
165
- | `useContainerAsSizeProvider` | `boolean` | `true` |
166
- | `resolutionSize` | `{ width: number; height: number }` | `{ width: 1920, height: 1080 }` |
167
-
168
- Outputs:
169
-
170
- | Output | Type |
171
- | ---------------------- | --------------------------- |
172
- | `changeMouseOverScene` | `OutputEmitterRef<boolean>` |
173
-
174
- ### 4) Send commands / interactions to Unreal
175
-
176
- Inject `UnrealCommunicatorService` to send commands or UI interactions. Types for command packets are provided by `@3dsource/types-unreal`.
177
-
178
- There are three sending methods — choose based on your needs:
179
-
180
- | Method | Description |
181
- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
182
- | `sendCommandToUnreal` | Full pipeline: adds `correlationId`, records telemetry, dispatches NgRx `commandStarted` action. **Recommended for application commands.** |
183
- | `emitUIInteraction` | Sends the packet as a raw `UIInteraction` message. No telemetry or store dispatch. |
184
- | `emitCommand` | Sends the packet as a raw `Command` message (for console commands, resolution changes, etc.). |
185
-
186
- ```ts
187
- import { Component, inject } from '@angular/core';
188
- import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
189
- import { MetaBoxCommand } from '@3dsource/types-unreal';
190
- import type { MetaBoxCommandPacket } from '@3dsource/types-unreal';
191
-
192
- @Component({ standalone: true, template: '' })
193
- export class MyComponent {
194
- private unreal = inject(UnrealCommunicatorService);
195
-
196
- sendSomeCommand() {
197
- // Recommended: use sendCommandToUnreal for full telemetry + store tracking
198
- this.unreal.sendCommandToUnreal({
199
- command: MetaBoxCommand.FChangeResolutionCommand,
200
- payload: { resolution: { x: 1920, y: 1080 } },
201
- });
202
- }
203
-
204
- sendRawUIInteraction() {
205
- // Low-level: sends UIInteraction message without telemetry tracking
206
- const packet = {
207
- command: 'CustomCommand',
208
- payload: { key: 'value' },
209
- } as MetaBoxCommandPacket;
210
- this.unreal.emitUIInteraction(packet);
211
- }
212
- }
213
- ```
214
-
215
- ### 5) Store integration (actions & selectors)
216
-
217
- `provideUnrealState()` registers the NgRx feature state `unrealFeature`. You
218
- can dispatch actions and select state in your components:
219
-
220
- ```ts
221
- import { inject } from '@angular/core';
222
- import { Store } from '@ngrx/store';
223
- import { disconnectStream, selectShowLoader, selectTotalProgress, setConfig, setOrchestrationContext, startStream, unrealFeature } from '@3dsource/angular-unreal-module';
224
-
225
- // Dispatch actions
226
- const store = inject(Store);
227
- store.dispatch(startStream({ config: { autoStart: true, warnTimeout: 120 } }));
228
-
229
- // Select state
230
- const progress = store.selectSignal(selectTotalProgress);
231
- const isVideoPlaying = store.selectSignal(unrealFeature.selectIsVideoPlaying);
232
- const dataChannelConnected = store.selectSignal(unrealFeature.selectDataChannelConnected);
233
- ```
234
-
235
- **Key selectors:**
236
-
237
- - `selectTotalProgress` — Scene load progress (0–1 float)
238
- - `selectShowLoader` — Whether loader screen should be visible
239
- - `selectShowReconnectPopup` — Whether reconnect popup should be shown
240
- - `selectIsVideoPlayingAndDataChannelConnected` — Combined readiness check
241
- - `selectStreamConfig` — Current stream configuration
242
- - `unrealFeature.selectCirrusConnected` — Signalling server connection status
243
- - `unrealFeature.selectDataChannelConnected` — Data channel status
244
- - `unrealFeature.selectViewportReady` — Viewport readiness
245
-
246
- **Key actions:**
247
-
248
- - `startStream` — Start streaming with config
249
- - `setConfig` — Update stream configuration
250
- - `setOrchestrationContext` — Set orchestration URLs and environment
251
- - `disconnectStream` — Disconnect with reason
252
- - `destroyUnrealScene` — Full teardown
253
- - `reconnectPeer` — Trigger peer reconnection
254
-
255
- ### 6) Listen for Unreal callbacks
256
-
257
- Inject `UnrealCallbackService` to listen for callback events from Unreal Engine and to observe command responses.
258
-
259
- There are two methods:
260
-
261
- | Method | Description |
262
- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
263
- | `fromUnrealCallback` | Listens for callbacks matching a command or event key. Supports MetaBox commands and custom Unreal callback events. Returns `Observable<UnrealCallbackDescriptor[K]>`. |
264
- | `observeCommandResponse` | Sends a command and waits for its matching response by `correlationId`. Returns `Observable<MetaBoxCommandList[K]>`. Includes timeout and error handling. |
265
-
266
- **Custom Unreal callback events** (defined in `UnrealCallbackEventMap`):
267
-
268
- | Event | Payload Type |
269
- | -------------------------- | --------------------------------------------------- |
270
- | `onSceneState` | `FSceneState` |
271
- | `onFocusObject` | `FProductPayload` |
272
- | `cameraChanged` | `FCameraChangedPayload` |
273
- | `onObjectTransformChanged` | `{ objectName: string; transform: FTransformJson }` |
274
- | `onChangeSequence` | `unknown` |
275
- | `onFinishedSequence` | `unknown` |
276
-
277
- ```ts
278
- import { Component, inject } from '@angular/core';
279
- import { UnrealCallbackService } from '@3dsource/angular-unreal-module';
280
- import { UnrealCommunicatorService } from '@3dsource/angular-unreal-module';
281
- import { MetaBoxCommand } from '@3dsource/types-unreal';
282
-
283
- @Component({ standalone: true, template: '' })
284
- export class MyComponent {
285
- private callbackService = inject(UnrealCallbackService);
286
- private communicator = inject(UnrealCommunicatorService);
287
-
288
- listenForCallbacks() {
289
- // Listen for a MetaBox command callback
290
- this.callbackService.fromUnrealCallback(MetaBoxCommand.FLoadProductCommand).subscribe((data) => console.log('Product loaded:', data));
291
-
292
- // Listen for a custom Unreal event
293
- this.callbackService.fromUnrealCallback('cameraChanged').subscribe((data) => console.log('Camera changed:', data));
294
- }
295
-
296
- sendAndObserve() {
297
- // Send a command and observe its response (with correlationId matching)
298
- this.callbackService
299
- .observeCommandResponse(
300
- { command: MetaBoxCommand.FLoopBackCommand },
301
- (data) => this.communicator.sendCommandToUnreal(data),
302
- 60000, // timeout in ms (default: 60000)
303
- true, // emit on timeout (default: true)
304
- )
305
- .subscribe((response) => console.log('Response:', response));
306
- }
307
- }
129
+ export class StreamComponent {}
308
130
  ```
309
131
 
310
- ## Exported API
311
-
312
- ### Components
313
-
314
- | Component | Selector | Description |
315
- | ------------------------------- | ------------------ | -------------------------------------- |
316
- | `UnrealSceneComponent` | `app-unreal-scene` | Main scene container with video stream |
317
- | `AfkTimeoutModalComponent` | — | AFK timeout warning modal |
318
- | `FreezeFrameComponent` | — | Freeze frame overlay |
319
- | `LowBandwidthModalComponent` | — | Low bandwidth warning modal |
320
- | `LowBandwidthDetectorComponent` | — | Low bandwidth detector |
321
- | `ImageLoadingSrcComponent` | — | Loading image overlay |
322
- | `IntroSrcComponent` | — | Intro image/video overlay |
323
- | `VideoStatsComponent` | — | Video statistics display |
324
- | `StatGraphComponent` | — | Statistics graph |
325
- | `WebrtcErrorModalComponent` | — | WebRTC error modal |
326
-
327
- ### Services
328
-
329
- | Service | Description |
330
- | ------------------------------ | --------------------------------------------------------------- |
331
- | `UnrealCommunicatorService` | Send commands and UI interactions to Unreal |
332
- | `UnrealCallbackService` | Listen for Unreal callback events and observe command responses |
333
- | `AggregatorService` | Aggregates data channel messages from Unreal |
334
- | `SignallingService` | Manages WebSocket signalling connection |
335
- | `VideoService` | Manages video element and stats |
336
- | `WebRtcPlayerService` | Manages WebRTC peer connection |
337
- | `FreezeFrameService` | Handles freeze frame images |
338
- | `AFKService` | AFK (away from keyboard) detection and timeout |
339
- | `DevModeService` | Toggle dev mode for debugging |
340
- | `FileReceiverService` | Receives files from Unreal via data channel |
341
- | `FileHandlerService` | Processes received files |
342
- | `RegionsPingService` | Pings regions to determine latency |
343
- | `CommandTelemetryService` | Records command telemetry |
344
- | `StreamStatusTelemetryService` | Reports stream status telemetry |
345
- | `AnalyticsService` | Analytics event tracking |
346
- | `FpsMonitorService` | FPS monitoring |
347
-
348
- ### Pipes
349
-
350
- | Pipe | Description |
351
- | ---------- | ------------------------------------------------------------ |
352
- | `SafePipe` | Sanitizes a value for the requested Angular security context |
353
-
354
- ### Interfaces
355
-
356
- | Interface | Description |
357
- | -------------------------- | ---------------------------------------------------------------------------- |
358
- | `UnrealInitialConfig` | Shape for `UNREAL_CONFIG` injection token |
359
- | `StreamConfig` | Stream configuration (autoStart, warnTimeout) |
360
- | `StreamResolutionProps` | Stream resolution width/height |
361
- | `UnrealCallbackEventMap` | Custom Unreal callback events pushed from Unreal via data channel |
362
- | `UnrealCallbackDescriptor` | Combined map of MetaBoxCommandList and UnrealCallbackEventMap callback types |
363
-
364
- ## Features
365
-
366
- - Standalone Unreal Scene Component
367
- - Command and UI Interaction API via `UnrealCommunicatorService`
368
- - Callback listener and command response observer via `UnrealCallbackService`
369
- - Event-driven status UI (freeze frame, video stats, play overlay, AFK, low bandwidth)
370
- - NgRx-powered state management and effects
371
- - **Required** initial configuration via `UNREAL_CONFIG` injection token
372
- - Auto-reconnection on WebRTC/DataChannel failures (configurable)
373
- - File receiving from Unreal Engine via data channel
374
- - Analytics and FPS monitoring
375
- - Playwright testing mode with mock service substitution
376
-
377
- ## Examples
378
-
379
- Check the demo application for complete usage examples:
380
-
381
- ```shell
382
- pnpm demo:start
132
+ `UnrealSceneComponent` also accepts `isStudio`,
133
+ `useContainerAsSizeProvider` and `resolutionSize` inputs, and emits
134
+ `changeMouseOverScene`.
135
+
136
+ ## Main API
137
+
138
+ - `provideUnrealState()` — registers the `unrealFeature` NgRx state.
139
+ - `provideUnrealModule()` — registers effects and boots streaming services.
140
+ - `UnrealSceneComponent` — renders and manages the Pixel Streaming scene.
141
+ - `UnrealCommunicatorService` — sends commands and UI interactions.
142
+ - `UnrealCallbackService` — observes Unreal callbacks and command responses.
143
+ - `unrealFeature`, exported selectors and actions — expose connection and scene
144
+ lifecycle state.
145
+ - `FileReceiverService` and `FileHandlerService` — receive files over the
146
+ DataChannel.
147
+
148
+ Command packet types are provided by `@3dsource/types-unreal`.
149
+
150
+ Run `pnpm demo:start` from the repository root to see the scene component in
151
+ the demo application.
152
+
153
+ ## Optional prefetch scripts
154
+
155
+ The package publishes two dependency-free scripts for use in the document
156
+ `<head>` before Angular starts:
157
+
158
+ - `region-ping-prefetch.js` measures regions early and caches the closest one.
159
+ - `stream-prefetch.js` opens and parks an eligible WebRTC connection so Angular
160
+ can adopt it after bootstrap.
161
+
162
+ <!-- prettier-ignore -->
163
+ ```html
164
+ <script
165
+ src="https://cdn.jsdelivr.net/npm/@3dsource/angular-unreal-module/js/region-ping-prefetch.js"
166
+ async
167
+ ></script>
168
+ <script
169
+ src="https://cdn.jsdelivr.net/npm/@3dsource/angular-unreal-module/js/stream-prefetch.js"
170
+ async
171
+ ></script>
383
172
  ```
384
173
 
385
- See also: `projects/demo/src/app/demo-layout/info-pages/unreal-scene-demo/constants/unreal.routes.ts` for a real-world provider configuration example.
174
+ `stream-prefetch.js` runs by default only on
175
+ `metabox-configurator/{modular|basic}/...` routes. It reads the same-origin
176
+ `assets/config.json`; override that path with `data-config-url` when needed.
177
+ Pin an exact package version in production when deterministic CDN assets are
178
+ required.
386
179
 
387
180
  ## Repository development
388
181
 
389
- Run package commands from the repository root:
182
+ Run commands from the repository root:
390
183
 
391
184
  ```shell
392
- pnpm --filter @3dsource/angular-unreal-module build
393
- pnpm --filter @3dsource/angular-unreal-module build:watch
394
- pnpm --filter @3dsource/angular-unreal-module test:signalling
185
+ pnpm unreal:build
186
+ pnpm unreal:build:watch
187
+ pnpm unreal:lint
188
+ pnpm unreal:test
189
+ pnpm unreal:test:watch
190
+ pnpm unreal:test:signalling
191
+ pnpm unreal:test:signalling:leaks
395
192
  ```
396
193
 
397
- To version and publish:
194
+ `unreal:build` builds the local `source-ui-native`, `types-unreal` and `utils`
195
+ dependencies before this package.
196
+
197
+ Release commands publish only this package:
398
198
 
399
199
  ```shell
400
- pnpm release:package -- angular-unreal-module patch latest
200
+ pnpm unreal:release:patch
201
+ pnpm unreal:release:dev
401
202
  ```
402
203
 
403
- The release command publishes to npm. After verifying the npm release, purge
404
- the matching jsDelivr tag explicitly:
204
+ After a successful publish, the release automatically purges the matching
205
+ jsDelivr tag. Retry a failed purge without rerunning the release:
405
206
 
406
207
  ```shell
407
- pnpm --filter @3dsource/angular-unreal-module purge-cdn -- latest
208
+ pnpm unreal:purge-cdn -- latest
209
+ pnpm unreal:purge-cdn -- dev
408
210
  ```
409
211
 
410
- ## Engine requirements
411
-
412
- - Node.js: >=20
212
+ Repository tooling requires Node.js 24.16.0 or newer and pnpm 11.17.0.