@viji-dev/core 0.11.1 → 0.11.2

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.
@@ -1,4 +1,4 @@
1
- import { g as kn } from "./index-D7BA9Ry-.js";
1
+ import { g as kn } from "./index-S7Vv0fhj.js";
2
2
  function jn(Oe, ot) {
3
3
  for (var ve = 0; ve < ot.length; ve++) {
4
4
  const Z = ot[ve];
@@ -3374,4 +3374,4 @@ const xn = /* @__PURE__ */ kn(yi), Ln = /* @__PURE__ */ jn({
3374
3374
  export {
3375
3375
  Ln as e
3376
3376
  };
3377
- //# sourceMappingURL=essentia-wasm.web-D1B5j3cM.js.map
3377
+ //# sourceMappingURL=essentia-wasm.web-BSqfHACB.js.map
@@ -1518,7 +1518,7 @@ class YB {
1518
1518
  if (!this.isInitialized)
1519
1519
  return this.initPromise ? this.initPromise : (this.initPromise = (async () => {
1520
1520
  try {
1521
- const A = await import("./essentia.js-core.es-CC_3Ap1i.js"), B = await import("./essentia-wasm.web-D1B5j3cM.js").then((g) => g.e), I = A.Essentia || A.default?.Essentia || A.default;
1521
+ const A = await import("./essentia.js-core.es-CC_3Ap1i.js"), B = await import("./essentia-wasm.web-BSqfHACB.js").then((g) => g.e), I = A.Essentia || A.default?.Essentia || A.default;
1522
1522
  let Q = B.default || B.EssentiaWASM || B.default?.EssentiaWASM;
1523
1523
  if (!Q)
1524
1524
  throw new Error("WASM module not found - check essentia-wasm.web.js export");
@@ -8825,7 +8825,12 @@ class QA {
8825
8825
  }
8826
8826
  /** Remove an external device and drop its remote-analysis state. */
8827
8827
  removeExternalDevice(A) {
8828
- this.clearDeviceAudio(A), this.clearDeviceVideo(A), this.lastAnalysisSeq.delete(`${A}:cv`), this.deviceRegistry.remove(A);
8828
+ this.beginConnectivityEdge();
8829
+ try {
8830
+ this.clearDeviceAudio(A), this.clearDeviceVideo(A), this.lastAnalysisSeq.delete(`${A}:cv`), this.deviceRegistry.remove(A);
8831
+ } finally {
8832
+ this.endConnectivityEdge();
8833
+ }
8829
8834
  }
8830
8835
  /** Host-UI device list (id/name/index). */
8831
8836
  getConnectedDevices() {
@@ -8982,13 +8987,23 @@ class QA {
8982
8987
  * deviceId. Returns the stream index.
8983
8988
  */
8984
8989
  setDeviceVideo(A, B) {
8985
- const I = this.ensureVideo().setDeviceStream(A, B);
8986
- return this.deviceVideoIndexToId.set(I, A), this.deviceIdToVideoIndex.set(A, I), I;
8990
+ this.beginConnectivityEdge();
8991
+ try {
8992
+ const I = this.ensureVideo().setDeviceStream(A, B);
8993
+ return this.deviceVideoIndexToId.set(I, A), this.deviceIdToVideoIndex.set(A, I), I;
8994
+ } finally {
8995
+ this.endConnectivityEdge();
8996
+ }
8987
8997
  }
8988
8998
  /** Clear a device video stream and drop its device-CV routing state. */
8989
8999
  clearDeviceVideo(A) {
8990
- const B = this.deviceIdToVideoIndex.get(A);
8991
- this.videoEngine?.clearDeviceStream(A), B !== void 0 && (this.deviceVideoIndexToId.delete(B), this.deviceIdToVideoIndex.delete(A), this.deviceCVDesired.delete(B), this.deviceCVApplied.delete(B), this.deviceCVResults.delete(B));
9000
+ this.beginConnectivityEdge();
9001
+ try {
9002
+ const B = this.deviceIdToVideoIndex.get(A);
9003
+ this.videoEngine?.clearDeviceStream(A), B !== void 0 && (this.deviceVideoIndexToId.delete(B), this.deviceIdToVideoIndex.delete(A), this.deviceCVDesired.delete(B), this.deviceCVApplied.delete(B), this.deviceCVResults.delete(B));
9004
+ } finally {
9005
+ this.endConnectivityEdge();
9006
+ }
8992
9007
  }
8993
9008
  hasDeviceVideo(A) {
8994
9009
  return this.videoEngine?.hasDeviceStream(A) ?? !1;
@@ -9054,12 +9069,17 @@ class QA {
9054
9069
  if (I === void 0) {
9055
9070
  if (this.deviceRemoteAudioIndices.size >= QA.MAX_DEVICE_AUDIO_CHANNELS)
9056
9071
  return;
9057
- const Q = /* @__PURE__ */ new Set([
9058
- ...this.deviceAudioStreamIndices.values(),
9059
- ...this.deviceRemoteAudioIndices.values()
9060
- ]);
9061
- for (I = QA.AUDIO_DEVICE_BASE; Q.has(I); ) I++;
9062
- this.deviceRemoteAudioIndices.set(A, I), this.ensureAudio().addDeviceAnalysisChannel(I, A);
9072
+ this.beginConnectivityEdge();
9073
+ try {
9074
+ const Q = /* @__PURE__ */ new Set([
9075
+ ...this.deviceAudioStreamIndices.values(),
9076
+ ...this.deviceRemoteAudioIndices.values()
9077
+ ]);
9078
+ for (I = QA.AUDIO_DEVICE_BASE; Q.has(I); ) I++;
9079
+ this.deviceRemoteAudioIndices.set(A, I), this.ensureAudio().addDeviceAnalysisChannel(I, A);
9080
+ } finally {
9081
+ this.endConnectivityEdge();
9082
+ }
9063
9083
  }
9064
9084
  this.ensureAudio().feedDeviceAnalysis(I, B);
9065
9085
  }
@@ -9094,11 +9114,15 @@ class QA {
9094
9114
  }
9095
9115
  // ── Audio stream state (engine-scoped, connectivity-wrapped) ────────────
9096
9116
  setMainAudioStream(A) {
9097
- const B = this.hasMainAudio;
9098
- this.mainAudioStream = A, (A || this.audioSystem) && this.ensureAudio().handleAudioStreamUpdate({
9099
- audioStream: A,
9100
- timestamp: performance.now()
9101
- }), B !== this.hasMainAudio && this.notifyConnectivityChange();
9117
+ this.beginConnectivityEdge();
9118
+ try {
9119
+ this.mainAudioStream = A, (A || this.audioSystem) && this.ensureAudio().handleAudioStreamUpdate({
9120
+ audioStream: A,
9121
+ timestamp: performance.now()
9122
+ });
9123
+ } finally {
9124
+ this.endConnectivityEdge();
9125
+ }
9102
9126
  }
9103
9127
  getMainAudioStream() {
9104
9128
  return this.mainAudioStream;
@@ -9106,6 +9130,15 @@ class QA {
9106
9130
  get hasMainAudio() {
9107
9131
  return this.mainAudioStream !== null;
9108
9132
  }
9133
+ /**
9134
+ * Whether ANY audio source is connected — main, additional, device stream,
9135
+ * or remote device analysis. Backs `CoreCapabilities.hasAudio` (parameter
9136
+ * visibility) and the connectivity-edge detection. Distinct from
9137
+ * `hasMainAudio`, which is main-only.
9138
+ */
9139
+ get hasAnyAudio() {
9140
+ return this.mainAudioStream !== null || this.additionalAudioStreams.length > 0 || this.deviceAudioStreamIndices.size > 0 || this.deviceRemoteAudioIndices.size > 0;
9141
+ }
9109
9142
  async addAdditionalAudioStream(A) {
9110
9143
  const B = this.additionalAudioStreams.indexOf(A);
9111
9144
  if (B !== -1) return B;
@@ -9114,34 +9147,54 @@ class QA {
9114
9147
  `Maximum additional audio streams reached (${QA.MAX_ADDITIONAL_AUDIO_STREAMS})`,
9115
9148
  "STREAM_LIMIT_REACHED"
9116
9149
  );
9117
- this.additionalAudioStreams.push(A);
9118
- const I = this.additionalAudioStreams.length - 1, Q = QA.AUDIO_ADDITIONAL_BASE + I;
9119
- return await this.ensureAudio().addStream(Q, A, { streamType: "additional" }), I;
9150
+ this.beginConnectivityEdge();
9151
+ try {
9152
+ this.additionalAudioStreams.push(A);
9153
+ const I = this.additionalAudioStreams.length - 1, Q = QA.AUDIO_ADDITIONAL_BASE + I;
9154
+ return await this.ensureAudio().addStream(Q, A, { streamType: "additional" }), I;
9155
+ } finally {
9156
+ this.endConnectivityEdge();
9157
+ }
9120
9158
  }
9121
9159
  async removeAdditionalAudioStream(A) {
9122
9160
  if (A < 0 || A >= this.additionalAudioStreams.length)
9123
9161
  throw new J(`Invalid audio stream index: ${A}`, "INVALID_INDEX");
9124
- this.additionalAudioStreams[A].getTracks().forEach((B) => B.stop()), this.additionalAudioStreams.splice(A, 1), this.audioSystem && await this.audioSystem.reinitializeAdditionalChannels(
9125
- this.additionalAudioStreams,
9126
- QA.AUDIO_ADDITIONAL_BASE
9127
- );
9162
+ this.beginConnectivityEdge();
9163
+ try {
9164
+ this.additionalAudioStreams[A].getTracks().forEach((B) => B.stop()), this.additionalAudioStreams.splice(A, 1), this.audioSystem && await this.audioSystem.reinitializeAdditionalChannels(
9165
+ this.additionalAudioStreams,
9166
+ QA.AUDIO_ADDITIONAL_BASE
9167
+ );
9168
+ } finally {
9169
+ this.endConnectivityEdge();
9170
+ }
9128
9171
  }
9129
9172
  getAdditionalAudioStreamCount() {
9130
9173
  return this.additionalAudioStreams.length;
9131
9174
  }
9132
9175
  async setDeviceAudio(A, B) {
9133
- this.clearDeviceAudio(A);
9134
- const I = new Set(this.deviceAudioStreamIndices.values());
9135
- let Q = QA.AUDIO_DEVICE_BASE;
9136
- for (; I.has(Q); )
9137
- Q++;
9138
- return this.deviceAudioStreamIndices.set(A, Q), await this.ensureAudio().addStream(Q, B, { streamType: "device", deviceId: A }), Q;
9176
+ this.beginConnectivityEdge();
9177
+ try {
9178
+ this.clearDeviceAudio(A);
9179
+ const I = new Set(this.deviceAudioStreamIndices.values());
9180
+ let Q = QA.AUDIO_DEVICE_BASE;
9181
+ for (; I.has(Q); )
9182
+ Q++;
9183
+ return this.deviceAudioStreamIndices.set(A, Q), await this.ensureAudio().addStream(Q, B, { streamType: "device", deviceId: A }), Q;
9184
+ } finally {
9185
+ this.endConnectivityEdge();
9186
+ }
9139
9187
  }
9140
9188
  clearDeviceAudio(A) {
9141
- const B = this.deviceAudioStreamIndices.get(A);
9142
- B !== void 0 && (this.deviceAudioStreamIndices.delete(A), this.audioSystem?.removeStream(B));
9143
- const I = this.deviceRemoteAudioIndices.get(A);
9144
- I !== void 0 && (this.deviceRemoteAudioIndices.delete(A), this.audioSystem?.removeDeviceAnalysisChannel(I)), this.lastAnalysisSeq.delete(`${A}:audio`);
9189
+ this.beginConnectivityEdge();
9190
+ try {
9191
+ const B = this.deviceAudioStreamIndices.get(A);
9192
+ B !== void 0 && (this.deviceAudioStreamIndices.delete(A), this.audioSystem?.removeStream(B));
9193
+ const I = this.deviceRemoteAudioIndices.get(A);
9194
+ I !== void 0 && (this.deviceRemoteAudioIndices.delete(A), this.audioSystem?.removeDeviceAnalysisChannel(I)), this.lastAnalysisSeq.delete(`${A}:audio`);
9195
+ } finally {
9196
+ this.endConnectivityEdge();
9197
+ }
9145
9198
  }
9146
9199
  hasDeviceAudio(A) {
9147
9200
  return this.deviceAudioStreamIndices.has(A) || this.deviceRemoteAudioIndices.has(A);
@@ -9151,8 +9204,34 @@ class QA {
9151
9204
  }
9152
9205
  // ── Video stream state (connectivity-wrapped; mechanics in the engine) ──
9153
9206
  setMainVideoStream(A) {
9154
- const B = this.hasMainVideo;
9155
- (A || this.videoEngine) && this.ensureVideo().setMainStream(A), B !== this.hasMainVideo && this.notifyConnectivityChange();
9207
+ this.beginConnectivityEdge();
9208
+ try {
9209
+ (A || this.videoEngine) && this.ensureVideo().setMainStream(A);
9210
+ } finally {
9211
+ this.endConnectivityEdge();
9212
+ }
9213
+ }
9214
+ /**
9215
+ * Add an additional (non-main, non-device) video stream. Routed through the
9216
+ * group (not straight to the engine) so it participates in connectivity-edge
9217
+ * detection, mirroring `addAdditionalAudioStream`. Returns its index.
9218
+ */
9219
+ addAdditionalVideoStream(A) {
9220
+ this.beginConnectivityEdge();
9221
+ try {
9222
+ return this.ensureVideo().addAdditionalStream(A);
9223
+ } finally {
9224
+ this.endConnectivityEdge();
9225
+ }
9226
+ }
9227
+ /** Remove an additional video stream by index (re-indexes the remainder). */
9228
+ removeAdditionalVideoStream(A) {
9229
+ this.beginConnectivityEdge();
9230
+ try {
9231
+ this.ensureVideo().removeAdditionalStream(A);
9232
+ } finally {
9233
+ this.endConnectivityEdge();
9234
+ }
9156
9235
  }
9157
9236
  getMainVideoStream() {
9158
9237
  return this.videoEngine?.getMainStream() ?? null;
@@ -9160,11 +9239,36 @@ class QA {
9160
9239
  get hasMainVideo() {
9161
9240
  return (this.videoEngine?.getMainStream() ?? null) !== null;
9162
9241
  }
9242
+ /**
9243
+ * Whether ANY video source is connected — main, additional, or device
9244
+ * stream. Device CV analysis rides a device video stream (its results are
9245
+ * dropped without one), so `deviceVideoIndexToId` covers it. Backs
9246
+ * `CoreCapabilities.hasVideo` and connectivity-edge detection; distinct from
9247
+ * `hasMainVideo` (main-only).
9248
+ */
9249
+ get hasAnyVideo() {
9250
+ return (this.videoEngine?.getMainStream() ?? null) !== null || (this.videoEngine?.getAdditionalStreamCount() ?? 0) > 0 || this.deviceVideoIndexToId.size > 0;
9251
+ }
9163
9252
  // ── Capability fan-out ──────────────────────────────────────────────────
9253
+ // Aggregate-edge detection. Stream mutators bracket their body with
9254
+ // begin/end; a single fan-out fires only when the OUTERMOST bracket closes
9255
+ // AND an aggregate predicate flipped. The depth counter collapses nested
9256
+ // mutations (e.g. setDeviceAudio → clearDeviceAudio, removeExternalDevice →
9257
+ // both clears) into one notification, and the snapshot/compare suppresses
9258
+ // churn when a 2nd same-kind source connects (aggregate unchanged).
9259
+ connectivityEdgeDepth = 0;
9260
+ edgeAudioBefore = !1;
9261
+ edgeVideoBefore = !1;
9262
+ beginConnectivityEdge() {
9263
+ this.connectivityEdgeDepth++ === 0 && (this.edgeAudioBefore = this.hasAnyAudio, this.edgeVideoBefore = this.hasAnyVideo);
9264
+ }
9265
+ endConnectivityEdge() {
9266
+ --this.connectivityEdgeDepth === 0 && (this.edgeAudioBefore !== this.hasAnyAudio || this.edgeVideoBefore !== this.hasAnyVideo) && this.notifyConnectivityChange();
9267
+ }
9164
9268
  /**
9165
9269
  * Engine connectivity changed: notify ALL attached cores (each fires its
9166
9270
  * own `capabilitiesChangeListeners`). The engine is the single origin —
9167
- * mutators do not self-notify.
9271
+ * mutators signal aggregate edges via begin/endConnectivityEdge.
9168
9272
  */
9169
9273
  notifyConnectivityChange() {
9170
9274
  for (const A of this.members)
@@ -9687,7 +9791,7 @@ class mA {
9687
9791
  allowUserInteraction: A.allowUserInteraction ?? !this.isHeadless
9688
9792
  }, this.sceneRenderer = tA.detectRendererType(A.sceneCode), this.sceneCapabilities = tA.detectCapabilities(A.sceneCode, this.sceneRenderer), this.sceneRenderer === "p5" && (this.sceneP5CanvasMode = tA.detectP5CanvasMode(A.sceneCode)), this.sceneConsumesAnalysedFrame = tA.detectAnalysedFrameUse(A.sceneCode), A.videoStream && this.engineGroup.setMainVideoStream(A.videoStream);
9689
9793
  for (const Q of A.videoStreams ?? [])
9690
- this.engineGroup.ensureVideo().addAdditionalStream(Q);
9794
+ this.engineGroup.addAdditionalVideoStream(Q);
9691
9795
  this.currentInteractionEnabled = this.config.allowUserInteraction, A.allowDeviceInteraction && (this.deviceSensorManager = new sI()), this.debugLog(`VijiCore created: ${this.instanceId} (headless: ${this.isHeadless}, sharedEngines: ${!!A.mediaSource})`);
9692
9796
  }
9693
9797
  async captureFrame(A = {}) {
@@ -10096,9 +10200,12 @@ class mA {
10096
10200
  getCapabilities() {
10097
10201
  return {
10098
10202
  // Connectivity lives on the shared engine group: identical for every
10099
- // attached core, change notifications fan out to all of them.
10100
- hasAudio: this.engineGroup.hasMainAudio,
10101
- hasVideo: this.engineGroup.hasMainVideo,
10203
+ // attached core, change notifications fan out to all of them. "Any
10204
+ // source" (main / additional / device stream / remote analysis) so the
10205
+ // audio/video parameter categories light up for controller-fed media,
10206
+ // not just the main stream.
10207
+ hasAudio: this.engineGroup.hasAnyAudio,
10208
+ hasVideo: this.engineGroup.hasAnyVideo,
10102
10209
  hasInteraction: this.currentInteractionEnabled,
10103
10210
  hasGeneral: !0
10104
10211
  // General parameters are always available
@@ -10702,7 +10809,7 @@ class mA {
10702
10809
  * core sharing this core's media engines.
10703
10810
  */
10704
10811
  async addVideoStream(A) {
10705
- return this.validateReady(), this.engineGroup.ensureVideo().addAdditionalStream(A);
10812
+ return this.validateReady(), this.engineGroup.addAdditionalVideoStream(A);
10706
10813
  }
10707
10814
  /**
10708
10815
  * Removes an additional video stream by index. Stops the stream's tracks.
@@ -10711,7 +10818,7 @@ class mA {
10711
10818
  * ALL cores sharing this core's media engines.
10712
10819
  */
10713
10820
  async removeVideoStream(A) {
10714
- this.validateReady(), this.engineGroup.ensureVideo().removeAdditionalStream(A);
10821
+ this.validateReady(), this.engineGroup.removeAdditionalVideoStream(A);
10715
10822
  }
10716
10823
  /**
10717
10824
  * Gets the number of additional video streams (engine-scoped).
@@ -11451,7 +11558,7 @@ function JI(D) {
11451
11558
  expectedVersion: 1
11452
11559
  } : typeof A.senderTime != "number" ? { code: "invalid-field", details: "senderTime must be a number", field: "senderTime" } : null;
11453
11560
  }
11454
- const SI = "0.11.1";
11561
+ const SI = "0.11.2";
11455
11562
  export {
11456
11563
  yA as A,
11457
11564
  UI as C,
@@ -11461,4 +11568,4 @@ export {
11461
11568
  J as b,
11462
11569
  $B as g
11463
11570
  };
11464
- //# sourceMappingURL=index-D7BA9Ry-.js.map
11571
+ //# sourceMappingURL=index-S7Vv0fhj.js.map
package/dist/index.d.ts CHANGED
@@ -993,9 +993,17 @@ export declare type CoordinateValue = {
993
993
  };
994
994
 
995
995
  declare interface CoreCapabilities {
996
- /** Audio input is active and connected */
996
+ /**
997
+ * Any audio source is connected — main, additional, an external device
998
+ * stream, or remote device analysis. Drives audio parameter-category
999
+ * visibility, so controller-fed audio activates it, not just the main stream.
1000
+ */
997
1001
  hasAudio: boolean;
998
- /** Video input is active and connected */
1002
+ /**
1003
+ * Any video source is connected — main, additional, or an external device
1004
+ * stream (device CV analysis rides a device stream). Drives video
1005
+ * parameter-category visibility, not just the main stream.
1006
+ */
999
1007
  hasVideo: boolean;
1000
1008
  /** User interactions (mouse, touch, keyboard) are enabled */
1001
1009
  hasInteraction: boolean;
@@ -2790,7 +2798,7 @@ declare type TrackingState = 'TRACKING' | 'LOCKED' | 'BREAKDOWN' | 'LOST';
2790
2798
  /** Returned by `on*` listener registration calls; invoke to unsubscribe. */
2791
2799
  export declare type Unsubscribe = () => void;
2792
2800
 
2793
- export declare const VERSION = "0.11.1";
2801
+ export declare const VERSION = "0.11.2";
2794
2802
 
2795
2803
  /**
2796
2804
  * Real-time video API: drawable frame, dimensions, and the source-side
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as s, C as o, I as E, V as i, a as A, b as C } from "./index-D7BA9Ry-.js";
1
+ import { A as s, C as o, I as E, V as i, a as A, b as C } from "./index-S7Vv0fhj.js";
2
2
  export {
3
3
  s as AudioSystem,
4
4
  o as CV_FEATURE_KEYS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viji-dev/core",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "Universal execution engine for Viji Creative scenes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",