@codenkay/video-nsgplayer-core 0.1.0 → 0.1.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.
package/dist/index.d.cts CHANGED
@@ -239,14 +239,30 @@ type PlayerEventMap = {
239
239
  };
240
240
 
241
241
  declare const PLAYBACK_RATES: readonly [0.5, 0.75, 1, 1.25, 1.5, 2];
242
- declare const PACKAGE_VERSION = "0.1.0";
242
+ declare const PACKAGE_VERSION = "0.1.2";
243
243
  declare const DEFAULT_PLAYER_BEHAVIOR: Required<PlayerBehaviorConfig>;
244
244
  declare const DEFAULT_CONTROLS: Required<ControlsConfig>;
245
245
  declare const DEFAULT_THEME: Required<ThemeConfig>;
246
246
  declare const DEFAULT_WATERMARK: Required<WatermarkConfig>;
247
247
  declare const DEFAULT_PLAYER_CONFIG: PlayerConfig;
248
+ /** Hard cap so pathological graphs cannot blow the stack. */
249
+ declare const SECRET_SCAN_MAX_DEPTH = 32;
250
+ /**
251
+ * True only for JSON-like plain objects (`{}` / `Object.create(null)`).
252
+ * Excludes DOM nodes, class instances, arrays, dates, etc.
253
+ */
254
+ declare function isPlainObject(value: unknown): value is Record<string, unknown>;
255
+ /**
256
+ * Scans plain config objects for forbidden secret key names.
257
+ *
258
+ * Enterprise guarantees:
259
+ * - Never deep-walks DOM / host / class instances (plain-object only)
260
+ * - Does not descend into `mount` / `auth` / `playback` (shallow key check only)
261
+ * - Cycle-safe via WeakSet
262
+ * - Depth-capped + iterative (no call-stack recursion)
263
+ */
248
264
  declare function assertNoSecretsInConfig(raw: unknown): void;
249
- declare function mergePlayerConfig(partial?: Partial<{
265
+ type PlayerConfigPartial = Partial<{
250
266
  player: Partial<PlayerBehaviorConfig>;
251
267
  controls: Partial<ControlsConfig>;
252
268
  theme: Partial<ThemeConfig>;
@@ -259,7 +275,8 @@ declare function mergePlayerConfig(partial?: Partial<{
259
275
  logging: Partial<PlayerConfig["logging"]>;
260
276
  debug: Partial<PlayerConfig["debug"]>;
261
277
  accessibility: Partial<PlayerConfig["accessibility"]>;
262
- }>): PlayerConfig;
278
+ }>;
279
+ declare function mergePlayerConfig(partial?: PlayerConfigPartial): PlayerConfig;
263
280
  /** Maps theme colors to CSS custom properties for UI adapters. */
264
281
  declare function themeToCssVars(theme: Required<ThemeConfig>): Record<string, string>;
265
282
 
@@ -541,7 +558,7 @@ declare class RefreshManager {
541
558
  private renew;
542
559
  }
543
560
 
544
- declare function redactValue(key: string, value: unknown): unknown;
545
- declare function redactObject(obj: Record<string, unknown>): Record<string, unknown>;
561
+ declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>, depth?: number): unknown;
562
+ declare function redactObject(obj: Record<string, unknown>, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
546
563
 
547
- export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, mergePlayerConfig, redactObject, redactSensitive, redactValue, seekToLiveEdge, themeToCssVars };
564
+ export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, seekToLiveEdge, themeToCssVars };
package/dist/index.d.ts CHANGED
@@ -239,14 +239,30 @@ type PlayerEventMap = {
239
239
  };
240
240
 
241
241
  declare const PLAYBACK_RATES: readonly [0.5, 0.75, 1, 1.25, 1.5, 2];
242
- declare const PACKAGE_VERSION = "0.1.0";
242
+ declare const PACKAGE_VERSION = "0.1.2";
243
243
  declare const DEFAULT_PLAYER_BEHAVIOR: Required<PlayerBehaviorConfig>;
244
244
  declare const DEFAULT_CONTROLS: Required<ControlsConfig>;
245
245
  declare const DEFAULT_THEME: Required<ThemeConfig>;
246
246
  declare const DEFAULT_WATERMARK: Required<WatermarkConfig>;
247
247
  declare const DEFAULT_PLAYER_CONFIG: PlayerConfig;
248
+ /** Hard cap so pathological graphs cannot blow the stack. */
249
+ declare const SECRET_SCAN_MAX_DEPTH = 32;
250
+ /**
251
+ * True only for JSON-like plain objects (`{}` / `Object.create(null)`).
252
+ * Excludes DOM nodes, class instances, arrays, dates, etc.
253
+ */
254
+ declare function isPlainObject(value: unknown): value is Record<string, unknown>;
255
+ /**
256
+ * Scans plain config objects for forbidden secret key names.
257
+ *
258
+ * Enterprise guarantees:
259
+ * - Never deep-walks DOM / host / class instances (plain-object only)
260
+ * - Does not descend into `mount` / `auth` / `playback` (shallow key check only)
261
+ * - Cycle-safe via WeakSet
262
+ * - Depth-capped + iterative (no call-stack recursion)
263
+ */
248
264
  declare function assertNoSecretsInConfig(raw: unknown): void;
249
- declare function mergePlayerConfig(partial?: Partial<{
265
+ type PlayerConfigPartial = Partial<{
250
266
  player: Partial<PlayerBehaviorConfig>;
251
267
  controls: Partial<ControlsConfig>;
252
268
  theme: Partial<ThemeConfig>;
@@ -259,7 +275,8 @@ declare function mergePlayerConfig(partial?: Partial<{
259
275
  logging: Partial<PlayerConfig["logging"]>;
260
276
  debug: Partial<PlayerConfig["debug"]>;
261
277
  accessibility: Partial<PlayerConfig["accessibility"]>;
262
- }>): PlayerConfig;
278
+ }>;
279
+ declare function mergePlayerConfig(partial?: PlayerConfigPartial): PlayerConfig;
263
280
  /** Maps theme colors to CSS custom properties for UI adapters. */
264
281
  declare function themeToCssVars(theme: Required<ThemeConfig>): Record<string, string>;
265
282
 
@@ -541,7 +558,7 @@ declare class RefreshManager {
541
558
  private renew;
542
559
  }
543
560
 
544
- declare function redactValue(key: string, value: unknown): unknown;
545
- declare function redactObject(obj: Record<string, unknown>): Record<string, unknown>;
561
+ declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>, depth?: number): unknown;
562
+ declare function redactObject(obj: Record<string, unknown>, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
546
563
 
547
- export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, mergePlayerConfig, redactObject, redactSensitive, redactValue, seekToLiveEdge, themeToCssVars };
564
+ export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, seekToLiveEdge, themeToCssVars };
package/dist/index.js CHANGED
@@ -146,7 +146,7 @@ var AuthManager = class {
146
146
 
147
147
  // src/config/defaults.ts
148
148
  var PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 2];
149
- var PACKAGE_VERSION = "0.1.0";
149
+ var PACKAGE_VERSION = "0.1.2";
150
150
  var DEFAULT_PLAYER_BEHAVIOR = {
151
151
  autoplay: true,
152
152
  startMuted: true,
@@ -232,22 +232,83 @@ var FORBIDDEN_SECRET_KEYS = [
232
232
  "basicauthpassword",
233
233
  "password"
234
234
  ];
235
+ var SKIP_DEEP_SCAN_KEYS = /* @__PURE__ */ new Set([
236
+ "mount",
237
+ "auth",
238
+ "playback",
239
+ "gettoken",
240
+ "getsource",
241
+ "refreshsource",
242
+ "keyproxyurlbuilder"
243
+ ]);
244
+ var SECRET_SCAN_MAX_DEPTH = 32;
245
+ function isPlainObject(value) {
246
+ if (value === null || typeof value !== "object") return false;
247
+ if (Array.isArray(value)) return false;
248
+ const proto = Object.getPrototypeOf(value);
249
+ return proto === Object.prototype || proto === null;
250
+ }
251
+ function normalizeConfigKey(key) {
252
+ return key.toLowerCase().replace(/[^a-z0-9]/g, "");
253
+ }
254
+ function isForbiddenSecretKey(key) {
255
+ const lower = normalizeConfigKey(key);
256
+ return FORBIDDEN_SECRET_KEYS.some((k) => lower.includes(k));
257
+ }
258
+ function throwForbidden(path, key) {
259
+ throw new Error(
260
+ `INVALID_CONFIGURATION: Forbidden secret key "${path}${key}" must never be passed to the browser SDK. Keep clientSecret on your server/BFF and use auth.getToken().`
261
+ );
262
+ }
235
263
  function assertNoSecretsInConfig(raw) {
236
- if (!raw || typeof raw !== "object") return;
237
- const walk = (obj, path) => {
238
- for (const [key, value] of Object.entries(obj)) {
239
- const lower = key.toLowerCase().replace(/[^a-z0-9]/g, "");
240
- if (FORBIDDEN_SECRET_KEYS.some((k) => lower.includes(k))) {
241
- throw new Error(
242
- `INVALID_CONFIGURATION: Forbidden secret key "${path}${key}" must never be passed to the browser SDK. Keep clientSecret on your server/BFF and use auth.getToken().`
243
- );
264
+ if (!isPlainObject(raw) && !Array.isArray(raw)) return;
265
+ const seen = /* @__PURE__ */ new WeakSet();
266
+ const stack = [
267
+ { value: raw, path: "", depth: 0 }
268
+ ];
269
+ while (stack.length > 0) {
270
+ const current = stack.pop();
271
+ if (current.depth > SECRET_SCAN_MAX_DEPTH) continue;
272
+ const { value, path, depth } = current;
273
+ if (Array.isArray(value)) {
274
+ if (seen.has(value)) continue;
275
+ seen.add(value);
276
+ for (let i = 0; i < value.length; i += 1) {
277
+ const item = value[i];
278
+ if (isPlainObject(item) || Array.isArray(item)) {
279
+ stack.push({ value: item, path: `${path}[${i}]`, depth: depth + 1 });
280
+ }
244
281
  }
245
- if (value && typeof value === "object" && !Array.isArray(value)) {
246
- walk(value, `${path}${key}.`);
282
+ continue;
283
+ }
284
+ if (!isPlainObject(value)) continue;
285
+ if (seen.has(value)) continue;
286
+ seen.add(value);
287
+ for (const [key, child] of Object.entries(value)) {
288
+ const normalized = normalizeConfigKey(key);
289
+ if (isForbiddenSecretKey(key)) {
290
+ throwForbidden(path, key);
291
+ }
292
+ if (normalized === "mount") continue;
293
+ if (SKIP_DEEP_SCAN_KEYS.has(normalized)) {
294
+ if (isPlainObject(child)) {
295
+ for (const nestedKey of Object.keys(child)) {
296
+ if (isForbiddenSecretKey(nestedKey)) {
297
+ throwForbidden(`${path}${key}.`, nestedKey);
298
+ }
299
+ }
300
+ }
301
+ continue;
302
+ }
303
+ if (isPlainObject(child) || Array.isArray(child)) {
304
+ stack.push({
305
+ value: child,
306
+ path: path ? `${path}${key}.` : `${key}.`,
307
+ depth: depth + 1
308
+ });
247
309
  }
248
310
  }
249
- };
250
- walk(raw, "");
311
+ }
251
312
  }
252
313
  function mergePlayerConfig(partial) {
253
314
  assertNoSecretsInConfig(partial);
@@ -335,7 +396,14 @@ var EventEmitter = class {
335
396
 
336
397
  // src/security/redaction.ts
337
398
  var SENSITIVE_KEYS = /^(authorization|cookie|set-cookie|x-api-key|token|accessToken|access_token|clientSecret|password)$/i;
338
- function redactValue(key, value) {
399
+ var REDACT_MAX_DEPTH = 32;
400
+ function isPlainObject2(value) {
401
+ if (value === null || typeof value !== "object") return false;
402
+ if (Array.isArray(value)) return false;
403
+ const proto = Object.getPrototypeOf(value);
404
+ return proto === Object.prototype || proto === null;
405
+ }
406
+ function redactValue(key, value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
339
407
  if (SENSITIVE_KEYS.test(key)) return "[REDACTED]";
340
408
  if (typeof value === "string") {
341
409
  if (/^https?:\/\//i.test(value) && /[?&](token|expires)=/i.test(value)) {
@@ -352,15 +420,25 @@ function redactValue(key, value) {
352
420
  }
353
421
  }
354
422
  }
355
- if (value && typeof value === "object" && !Array.isArray(value)) {
356
- return redactObject(value);
423
+ if (Array.isArray(value)) {
424
+ if (depth >= REDACT_MAX_DEPTH || seen.has(value)) return "[REDACTED_CYCLE]";
425
+ seen.add(value);
426
+ return value.map(
427
+ (item, index) => redactValue(String(index), item, seen, depth + 1)
428
+ );
429
+ }
430
+ if (isPlainObject2(value)) {
431
+ return redactObject(value, seen, depth + 1);
357
432
  }
358
433
  return value;
359
434
  }
360
- function redactObject(obj) {
435
+ function redactObject(obj, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
436
+ if (depth > REDACT_MAX_DEPTH) return { "[REDACTED]": "max_depth" };
437
+ if (seen.has(obj)) return { "[REDACTED]": "cycle" };
438
+ seen.add(obj);
361
439
  const out = {};
362
440
  for (const [key, value] of Object.entries(obj)) {
363
- out[key] = redactValue(key, value);
441
+ out[key] = redactValue(key, value, seen, depth);
364
442
  }
365
443
  return out;
366
444
  }
@@ -830,7 +908,18 @@ function generateSessionId() {
830
908
  return `ps_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
831
909
  }
832
910
  function createVideoPlayer(options) {
833
- assertNoSecretsInConfig(options);
911
+ assertNoSecretsInConfig({
912
+ videoId: options.videoId,
913
+ sourceUrl: options.sourceUrl,
914
+ player: options.player,
915
+ controls: options.controls,
916
+ theme: options.theme,
917
+ watermark: options.watermark,
918
+ streaming: options.streaming,
919
+ logging: options.logging,
920
+ debug: options.debug,
921
+ accessibility: options.accessibility
922
+ });
834
923
  let config = mergePlayerConfig({
835
924
  player: options.player,
836
925
  controls: options.controls,
@@ -1212,11 +1301,13 @@ export {
1212
1301
  PlaybackSourceManager,
1213
1302
  PlayerErrorCode,
1214
1303
  RefreshManager,
1304
+ SECRET_SCAN_MAX_DEPTH,
1215
1305
  assertNoSecretsInConfig,
1216
1306
  createPlayerError,
1217
1307
  createVideoPlayer,
1218
1308
  getLiveEdgeTime,
1219
1309
  isAtLiveEdge,
1310
+ isPlainObject,
1220
1311
  mergePlayerConfig,
1221
1312
  redactObject,
1222
1313
  redactSensitive,