@lumiastream/ui 0.4.4 → 0.5.0

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.
@@ -163,7 +163,32 @@ interface ReviewItem {
163
163
  flaggedOff?: boolean;
164
164
  }
165
165
 
166
- /** Distinct SE CDN URLs referenced anywhere inside the overlay's settings. */
166
+ type ProxyFetchFn = (url: string, init?: {
167
+ headers?: Record<string, string>;
168
+ }) => Promise<unknown>;
169
+ interface FetchWithProxyOptions {
170
+ headers?: Record<string, string>;
171
+ proxyFetch?: ProxyFetchFn;
172
+ method?: string;
173
+ }
174
+ declare function looksLikeCorsError(err: unknown): boolean;
175
+ interface FetchOrProxyResult {
176
+ ok: boolean;
177
+ status: number;
178
+ viaProxy: boolean;
179
+ json: () => Promise<unknown>;
180
+ errorBody: () => Promise<string>;
181
+ }
182
+ declare function fetchWithProxyFallback(url: string, options?: FetchWithProxyOptions): Promise<FetchOrProxyResult>;
183
+
184
+ /**
185
+ * Distinct importable CDN URLs referenced anywhere inside the overlay's
186
+ * settings. Covers both StreamElements and Streamlabs source hosts — see
187
+ * IMPORTABLE_CDN_REGEX above for the full host list.
188
+ *
189
+ * Name kept as `findSEAssetURLs` for back-compat with existing callers; the
190
+ * SL import path uses the exact same function.
191
+ */
167
192
  declare function findSEAssetURLs(overlay: OverlayState): string[];
168
193
  /** Return a new overlay with every `oldUrl → newUrl` replacement applied. */
169
194
  declare function rewriteAssetURLs(overlay: OverlayState, mapping: Record<string, string>): OverlayState;
@@ -174,18 +199,27 @@ interface AssetMirrorProgress {
174
199
  error?: string;
175
200
  }
176
201
  /**
177
- * Mirror a single SE asset to Lumia storage via the existing `/overlays/assets`
178
- * upload endpoint. Returns the new Lumia URL on success.
202
+ * Mirror a single source CDN asset to Lumia storage via the host's upload
203
+ * endpoint. Returns the new Lumia URL on success.
179
204
  *
180
- * The host call site is responsible for retries and progress reporting; this
181
- * function is intentionally single-shot. Pass `signal` (AbortSignal) to abort
182
- * the source-side `fetch` when the modal closes mid-mirror the upload itself
183
- * is consumer-defined and the caller decides whether/how to short-circuit it.
205
+ * Tries a direct `fetch(url, { mode: 'cors' })` first. On a CORS-shaped
206
+ * TypeError, falls back to `proxyAssetFetch` if the host provided one —
207
+ * needed for `cdn.twitchalerts.com` and any other source CDN that doesn't
208
+ * serve `Access-Control-Allow-Origin`. Without the fallback, those assets
209
+ * surface as `failed` in the mirror UI and stay on the source CDN in the
210
+ * imported overlay.
184
211
  *
185
- * Bails out with a typed error if the SE server advertises a Content-Length
186
- * over MAX_MIRROR_ASSET_BYTES (cheap pre-check) or if the downloaded blob
187
- * exceeds the same cap (covers chunked responses where Content-Length is
188
- * absent or lying).
212
+ * The host call site is responsible for retries and progress reporting;
213
+ * this function is intentionally single-shot. Pass `signal` (AbortSignal)
214
+ * to abort the source-side `fetch` when the modal closes mid-mirror — the
215
+ * upload itself is consumer-defined and the caller decides whether/how to
216
+ * short-circuit it. The proxy path doesn't take a signal because the
217
+ * host-provided fetch shape varies.
218
+ *
219
+ * Bails out with a typed error if the source server advertises a
220
+ * Content-Length over MAX_MIRROR_ASSET_BYTES (cheap pre-check) or if the
221
+ * downloaded blob exceeds the same cap (covers chunked responses where
222
+ * Content-Length is absent or lying).
189
223
  */
190
224
  declare function mirrorOneAsset(url: string, upload: (file: File) => Promise<{
191
225
  asset: {
@@ -193,7 +227,7 @@ declare function mirrorOneAsset(url: string, upload: (file: File) => Promise<{
193
227
  };
194
228
  } | {
195
229
  url: string;
196
- } | unknown>, signal?: AbortSignal): Promise<string>;
230
+ } | unknown>, signal?: AbortSignal, proxyAssetFetch?: (url: string) => Promise<Blob>): Promise<string>;
197
231
  declare function filenameFromURL(url: string): string;
198
232
 
199
233
  interface TransplantedUnit {
@@ -296,6 +330,16 @@ interface SEOverlaySummary {
296
330
  };
297
331
  }
298
332
  declare function fetchSEOverlays(client: SEClient, count?: number): Promise<SEOverlaySummary[]>;
333
+ interface SEElementShareParts {
334
+ channelId: string;
335
+ widgetInstanceId: string;
336
+ publicToken: string | null;
337
+ }
338
+ declare function parseElementShareUrl(input: string): SEElementShareParts | null;
339
+ declare function fetchElementWidgetInstancePublic(channelId: string, widgetInstanceId: string, publicToken: string | null, options?: {
340
+ proxyFetch?: ProxyFetchFn;
341
+ }): Promise<unknown>;
342
+ declare function fetchElementWidgetInstanceForClient(client: SEClient, widgetInstanceId: string): Promise<unknown>;
299
343
  declare function fetchSEFiltersRaw(client: SEClient): Promise<unknown>;
300
344
  interface SEAuthProbeResult {
301
345
  endpoint: string;
@@ -362,6 +406,10 @@ interface SEImportBindings {
362
406
  CustomEmbed?: ComponentType<SECustomEmbedProps>;
363
407
  t?: (key: string) => string | undefined;
364
408
  onAuthError?: (err: SEAuthError) => void;
409
+ proxyFetch?: (url: string, init?: {
410
+ headers?: Record<string, string>;
411
+ }) => Promise<unknown>;
412
+ proxyAssetFetch?: (url: string) => Promise<Blob>;
365
413
  onOpenFullImport?: () => void;
366
414
  }
367
415
 
@@ -398,6 +446,150 @@ declare function getJwtInstructionSteps({ pasteHint }?: {
398
446
  pasteHint?: string;
399
447
  }): JwtInstructionStep[];
400
448
 
449
+ interface SEElementResponse {
450
+ widgetInstancePublicUrl?: string;
451
+ widgetInstance: SEElementWidgetInstance;
452
+ widgetEnvironment?: SEElementWidgetEnvironment;
453
+ widgetInstanceConfigVersion: SEElementConfigVersion;
454
+ widgetInstanceManagedData?: unknown;
455
+ widgetInstancePersistentData?: unknown;
456
+ }
457
+ interface SEElementWidgetInstance {
458
+ widgetInstanceId: string;
459
+ channelId: string;
460
+ displayName?: string;
461
+ languageCode?: string;
462
+ widgetManifestUrl?: string;
463
+ originalWidgetManifestUrl?: string;
464
+ widgetCatalogReferenceId?: string;
465
+ widgetPreviewImageUrl?: string;
466
+ widgetInstancePublishedConfigVersionId?: string;
467
+ createdAt?: string;
468
+ updatedAt?: string;
469
+ }
470
+ interface SEElementWidgetEnvironment {
471
+ languageCode?: string;
472
+ connectedPlatforms?: SEElementConnectedPlatform[];
473
+ }
474
+ interface SEElementConnectedPlatform {
475
+ referenceId?: string;
476
+ provider: string;
477
+ displayName?: string;
478
+ channelId?: string;
479
+ sessionData?: Record<string, unknown>;
480
+ }
481
+ interface SEElementConfigVersion {
482
+ widgetInstanceConfigVersionId: string;
483
+ widgetInstanceId: string;
484
+ displayName?: string;
485
+ configData: string;
486
+ connectedPlatforms?: string[];
487
+ createdAt?: string;
488
+ updatedAt?: string;
489
+ }
490
+ interface SEElementConfigData {
491
+ boundingBox: {
492
+ width: number;
493
+ height: number;
494
+ };
495
+ configStates: SEElementConfigState[];
496
+ }
497
+ interface SEElementConfigState {
498
+ referenceId: string;
499
+ categoryId: string | null;
500
+ displayName?: string;
501
+ triggers?: SEElementTrigger[];
502
+ settings?: {
503
+ compositeFields?: Record<string, SEElementCompositeField>;
504
+ };
505
+ }
506
+ interface SEElementTrigger {
507
+ systemCondition?: unknown;
508
+ userCondition?: unknown;
509
+ }
510
+ interface SEElementCompositeField {
511
+ type: 'video' | 'image' | 'text' | 'audio' | string;
512
+ mimeType?: string;
513
+ media?: SEElementMediaItem[];
514
+ text?: SEElementTextItem[];
515
+ style?: SEElementStyle;
516
+ highlightedStyle?: SEElementStyle;
517
+ animation?: {
518
+ enter?: SEElementAnimation;
519
+ static?: SEElementAnimation;
520
+ exit?: SEElementAnimation;
521
+ };
522
+ volume?: number;
523
+ playbackRate?: number;
524
+ delaySeconds?: number;
525
+ }
526
+ interface SEElementMediaItem {
527
+ href: string;
528
+ mimeType?: string;
529
+ role?: string;
530
+ }
531
+ interface SEElementTextItem {
532
+ content: string;
533
+ }
534
+ interface SEElementStyle {
535
+ left?: string | number;
536
+ top?: string | number;
537
+ width?: string | number;
538
+ height?: string | number;
539
+ maxWidth?: string | number;
540
+ maxHeight?: string | number;
541
+ color?: string;
542
+ fontFamily?: string;
543
+ fontSize?: string | number;
544
+ fontWeight?: string;
545
+ textAlign?: string;
546
+ textShadow?: string;
547
+ 'letter-spacing'?: string | number;
548
+ [key: string]: unknown;
549
+ }
550
+ interface SEElementAnimation {
551
+ animationName?: string;
552
+ animationDuration?: string;
553
+ animationDelay?: string;
554
+ opacity?: string | number;
555
+ [key: string]: unknown;
556
+ }
557
+ declare function isSEElementResponse(value: unknown): value is SEElementResponse;
558
+ declare function parseElementConfigData(raw: string): SEElementConfigData | null;
559
+ declare function readElementProvider(response: SEElementResponse): 'twitch' | 'kick' | 'youtube';
560
+
561
+ interface ElementImportResult {
562
+ overlay: OverlayState;
563
+ coverage: ImportCoverage;
564
+ reviewItems: ReviewItem[];
565
+ }
566
+ declare function importElementOverlay(response: SEElementResponse): ElementImportResult;
567
+
568
+ type ElementAlertKind = 'subscriber' | 'subscriberGift' | 'communityGiftPurchase' | 'follower' | 'tip' | 'cheer' | 'raid' | 'merch' | 'charity';
569
+ type ElementSceneKind = 'background' | 'foreground' | 'static';
570
+ type ElementStateClass = {
571
+ kind: 'alert';
572
+ alertKind: ElementAlertKind;
573
+ } | {
574
+ kind: 'scene';
575
+ sceneKind: ElementSceneKind;
576
+ } | {
577
+ kind: 'unknown';
578
+ };
579
+ interface TriggerExtractedVars {
580
+ [varPath: string]: string | boolean | undefined;
581
+ }
582
+ declare function extractTriggerVars(node: unknown, out?: TriggerExtractedVars): TriggerExtractedVars;
583
+ declare function classifyConfigState(state: SEElementConfigState): ElementStateClass;
584
+
585
+ type SEImportProvider = 'twitch' | 'kick' | 'youtube';
586
+
587
+ interface ElementSubstituteOptions {
588
+ listener?: string | null;
589
+ provider?: SEImportProvider;
590
+ }
591
+ declare function substituteElementTokens(input: string | null | undefined, options?: ElementSubstituteOptions): string;
592
+
401
593
  interface ImportResult {
402
594
  overlay: OverlayState;
403
595
  coverage: ImportCoverage;
@@ -409,9 +601,10 @@ declare function extractSEPreviewParts(input: string): {
409
601
  apikey: string | null;
410
602
  } | null;
411
603
  declare function buildBootstrapUrl(overlayId: string): string;
412
- declare function fetchSEBootstrap({ overlayId, apikey, }: {
604
+ declare function fetchSEBootstrap({ overlayId, apikey, proxyFetch, }: {
413
605
  overlayId: string;
414
606
  apikey: string | null;
607
+ proxyFetch?: ProxyFetchFn;
415
608
  }): Promise<SEBootstrapResponse>;
416
609
  declare function isSEBootstrap(value: unknown): value is SEBootstrapResponse;
417
610
  declare function importSEBootstrap(bootstrap: SEBootstrapResponse): ImportResult;
@@ -443,4 +636,4 @@ declare function buildAIPromptForSEWidget(widget: SEWidget, canvas?: {
443
636
  height: number;
444
637
  }): string;
445
638
 
446
- export { type AIGeneratedCustomOverlay, type AssetMirrorProgress, FLAG_OFF_REASONS, type ImportCoverage, type ImportResult, JWT_DASHBOARD_URL, type JwtInstructionStep, MarketplacePicker, type MarketplacePickerProps, type ModuleType, type OverlayLayerBounds, type OverlayLayerState, type OverlayLayerType, type OverlayModuleAlertState, type OverlayModuleState, type OverlaySettings, type OverlayState, type ReviewItem, type SEAccountClaims, type SEAuthDiagnostic, SEAuthError, type SEAuthErrorCode, type SEAuthMode, type SEAuthProbeResult, type SEBootstrapResponse, type SEChannelSummary, SEClient, type SECustomEmbedProps, type SEExistingAsset, type SEImportBindings, SEImportWizard, type SEImportWizardProps, type SEOverlaySummary, type SESaveOverlayBody, type SEUploadAssetResult, type SEUsersCurrentResponse, type SEWidget, SE_WIDGET_TO_MARKETPLACE_CANDIDATES, type TransplantedUnit, applyReviewAction, buildAIPromptForSEWidget, buildBootstrapUrl, decodeJwtPayload, diagnoseSEAuth, extractSEOverlayId, extractSEPreviewParts, fetchSEBootstrap, fetchSEFiltersRaw, fetchSEOverlays, fetchUsableChannels, filenameFromURL, findSEAssetURLs, getAILandingBounds, getJwtInstructionSteps, getMarketplaceCandidates, hasMarketplaceCandidates, importSEBootstrap, isSEBootstrap, isWidgetFlaggedOff, listTransplantableLayers, mirrorOneAsset, rewriteAssetURLs, streamElementsCopyJwt, substituteSeTokens, transplantLayer };
639
+ export { type AIGeneratedCustomOverlay, type AssetMirrorProgress, type ElementAlertKind, type ElementImportResult, type ElementSceneKind, type ElementStateClass, FLAG_OFF_REASONS, type FetchOrProxyResult, type FetchWithProxyOptions, type ImportCoverage, type ImportResult, JWT_DASHBOARD_URL, type JwtInstructionStep, MarketplacePicker, type MarketplacePickerProps, type ModuleType, type OverlayLayerBounds, type OverlayLayerState, type OverlayLayerType, type OverlayModuleAlertState, type OverlayModuleState, type OverlaySettings, type OverlayState, type ProxyFetchFn, type ReviewItem, type SEAccountClaims, type SEAuthDiagnostic, SEAuthError, type SEAuthErrorCode, type SEAuthMode, type SEAuthProbeResult, type SEBootstrapResponse, type SEChannelSummary, SEClient, type SECustomEmbedProps, type SEElementAnimation, type SEElementCompositeField, type SEElementConfigData, type SEElementConfigState, type SEElementConfigVersion, type SEElementMediaItem, type SEElementResponse, type SEElementShareParts, type SEElementStyle, type SEElementTextItem, type SEElementTrigger, type SEElementWidgetInstance, type SEExistingAsset, type SEImportBindings, SEImportWizard, type SEImportWizardProps, type SEOverlaySummary, type SESaveOverlayBody, type SEUploadAssetResult, type SEUsersCurrentResponse, type SEWidget, SE_WIDGET_TO_MARKETPLACE_CANDIDATES, type TransplantedUnit, applyReviewAction, buildAIPromptForSEWidget, buildBootstrapUrl, classifyConfigState, decodeJwtPayload, diagnoseSEAuth, extractSEOverlayId, extractSEPreviewParts, extractTriggerVars, fetchElementWidgetInstanceForClient, fetchElementWidgetInstancePublic, fetchSEBootstrap, fetchSEFiltersRaw, fetchSEOverlays, fetchUsableChannels, fetchWithProxyFallback, filenameFromURL, findSEAssetURLs, getAILandingBounds, getJwtInstructionSteps, getMarketplaceCandidates, hasMarketplaceCandidates, importElementOverlay, importSEBootstrap, isSEBootstrap, isSEElementResponse, isWidgetFlaggedOff, listTransplantableLayers, looksLikeCorsError, mirrorOneAsset, parseElementConfigData, parseElementShareUrl, readElementProvider, rewriteAssetURLs, streamElementsCopyJwt, substituteElementTokens, substituteSeTokens, transplantLayer };