@lumiastream/ui 0.5.0 → 0.5.3

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.js CHANGED
@@ -3154,7 +3154,40 @@ var SE_TO_LUMIA_PLACEHOLDER = {
3154
3154
  // tied to an alert payload), so we route it at the *global* template
3155
3155
  // variable `{{streamer}}` populated by VariablesManager.refreshStreamerVariable
3156
3156
  // (Twitch → Kick → YouTube → Facebook → TikTok fallback chain).
3157
- streamer: "streamer"
3157
+ streamer: "streamer",
3158
+ // Sub / resub months — SL and SE both expose `{months}` inside sub-event
3159
+ // variation templates ("{name} just resubbed for {months} months!"). Lumia
3160
+ // surfaces this on the subscriber alert payload as `subMonths` (see
3161
+ // lumia-types/src/variables.types.ts). Mapping is global because `{months}`
3162
+ // only ever appears in subscriber-context templates in the wild — neither
3163
+ // SE nor SL emit it for follower / cheer / tip alerts.
3164
+ months: "subMonths",
3165
+ // Merch / loyalty redemption product name — SL emits `{product}` in
3166
+ // merch_message_template and loyalty_store_redemption_message_template,
3167
+ // SE emits it the same way. Lumia's shopOrder alert exposes the first
3168
+ // item's name as `firstItem.name`; alias to `item` (which already maps
3169
+ // there) so both tokens resolve identically.
3170
+ product: "firstItem.name",
3171
+ // Treatstream title — SL `treat_message_template`
3172
+ // ("{name} bought you a {title} treat"). Lumia's treat alert exposes the
3173
+ // gift name as `treat` (see treatstream entry in variables.types.ts).
3174
+ title: "treat",
3175
+ // SL custom-HTML alias for the chat message — `{userMessage}` and
3176
+ // `{message}` mean the same thing. Both should resolve to Lumia's
3177
+ // `{{message}}`.
3178
+ userMessage: "message",
3179
+ // Prime-gaming gift tier — SL `prime_sub_gift_message_template`
3180
+ // ("{name} gifted {giftType} Ultra subscription to {streamer}"). The gift
3181
+ // type carries the subscription tier ("1000" / "2000" / "3000" / "prime")
3182
+ // which Lumia exposes as `tier` on every sub-related alert payload.
3183
+ giftType: "tier",
3184
+ // TikTok-style jewel gift quantity — SL `jewel_gift_message_template`
3185
+ // ("{name} gifted {giftName} x{jewelsAmount} jewels!"). Lumia's tiktok-gift
3186
+ // alert exposes the quantity as `amount`. `{giftName}` (the gift's display
3187
+ // name) doesn't have a 1:1 Lumia variable — TikTok's gift catalog isn't
3188
+ // directly imported — so we leave it unmapped and the streamer can adjust
3189
+ // the template in the Lumia editor.
3190
+ jewelsAmount: "amount"
3158
3191
  };
3159
3192
  var TWITCH_CONTEXTS = {
3160
3193
  "follower-latest": {
@@ -6886,9 +6919,9 @@ async function fetchWithProxyFallback(url, options = {}) {
6886
6919
  }
6887
6920
 
6888
6921
  // src/se-import/assets.ts
6889
- var IMPORTABLE_CDN_REGEX = /https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\/[^\s"'\\)]+/g;
6922
+ var IMPORTABLE_CDN_REGEX = /https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|streamlabs\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\/[^\s"'\\)]+/g;
6890
6923
  var CSS_URL_REGEX = /url\(\s*['"]?([^'")]+)['"]?\s*\)/g;
6891
- var IMPORTABLE_CDN_HOST_REGEX = /^https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\//;
6924
+ var IMPORTABLE_CDN_HOST_REGEX = /^https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|streamlabs\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\//;
6892
6925
  function isImportableAssetUrl(url) {
6893
6926
  return IMPORTABLE_CDN_HOST_REGEX.test(url);
6894
6927
  }
@@ -7631,7 +7664,7 @@ function absolutizeSLUrl(raw) {
7631
7664
  if (typeof raw !== "string" || raw.length === 0) return "";
7632
7665
  if (raw.startsWith("http://") || raw.startsWith("https://")) return raw;
7633
7666
  if (raw.startsWith("//")) return `https:${raw}`;
7634
- if (raw.startsWith("/")) return `https://cdn.streamlabs.com${raw}`;
7667
+ if (raw.startsWith("/")) return `https://streamlabs.com${raw}`;
7635
7668
  return raw;
7636
7669
  }
7637
7670
  function buildBaseAlertEvent(settings, prefix, defaultMessage) {
@@ -7642,13 +7675,7 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
7642
7675
  const fontWeight = getField(settings, prefix, "font_weight") ?? 600;
7643
7676
  const fontColor = getField(settings, prefix, "font_color") ?? "#FFFFFF";
7644
7677
  const highlightColor = getField(settings, prefix, "font_color2") ?? "#32C3A6";
7645
- const messageFontSize = pxToNumber(
7646
- getField(settings, prefix, "message_font_size"),
7647
- 20
7648
- );
7649
- const messageFontFamily = getField(settings, prefix, "message_font") ?? fontFamily;
7650
- const messageFontWeight = getField(settings, prefix, "message_font_weight") ?? 400;
7651
- const messageFontColor = getField(settings, prefix, "message_font_color") ?? "#FFFFFF";
7678
+ const secondaryMessage = readSecondaryMessageConfig(settings, prefix, fontFamily);
7652
7679
  const imageHref = absolutizeSLUrl(getField(settings, prefix, "image_href"));
7653
7680
  const soundHref = absolutizeSLUrl(getField(settings, prefix, "sound_href"));
7654
7681
  const soundVolume = getField(settings, prefix, "sound_volume") ?? 50;
@@ -7667,7 +7694,7 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
7667
7694
  accentColor: null,
7668
7695
  highlightColor,
7669
7696
  firstMessageTemplate: translateSeText(messageTemplate),
7670
- secondMessageTemplate: "",
7697
+ secondMessageTemplate: secondaryMessage?.template ?? "",
7671
7698
  thirdMessageTemplate: "",
7672
7699
  showAvatar: false,
7673
7700
  showAmount: true,
@@ -7690,12 +7717,10 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
7690
7717
  textShadow: "rgba(0, 0, 0, 0.8) 1px 1px 1px",
7691
7718
  textAlign: "center"
7692
7719
  },
7693
- messageCss: {
7694
- fontFamily: messageFontFamily,
7695
- fontSize: messageFontSize,
7696
- color: messageFontColor,
7697
- fontWeight: messageFontWeight
7698
- },
7720
+ // `messageCss` only matters when secondMessageTemplate is set;
7721
+ // leave it empty when SL didn't ship a secondary-message block
7722
+ // so Lumia's renderer falls back to its own default styling.
7723
+ messageCss: secondaryMessage?.css ?? {},
7699
7724
  content: { value: translateSeText(messageTemplate) }
7700
7725
  },
7701
7726
  media: {
@@ -7738,6 +7763,36 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
7738
7763
  variations: []
7739
7764
  };
7740
7765
  }
7766
+ var SECONDARY_MESSAGE_PREFIX_OVERRIDE = {
7767
+ sub: "resub"
7768
+ };
7769
+ function readSecondaryMessageConfig(settings, prefix, primaryFontFamily) {
7770
+ const secondaryPrefix = SECONDARY_MESSAGE_PREFIX_OVERRIDE[prefix] ?? prefix;
7771
+ const showKey = `show_${secondaryPrefix}_message`;
7772
+ const enabled = settings[showKey];
7773
+ if (enabled !== true) return null;
7774
+ const fontFamily = getField(settings, secondaryPrefix, "message_font") ?? primaryFontFamily;
7775
+ const fontSize = pxToNumber(
7776
+ getField(settings, secondaryPrefix, "message_font_size"),
7777
+ 20
7778
+ );
7779
+ const fontWeight = getField(settings, secondaryPrefix, "message_font_weight") ?? 400;
7780
+ const fontColor = getField(settings, secondaryPrefix, "message_font_color") ?? "#FFFFFF";
7781
+ return {
7782
+ // `{message}` is the SE/SL chat-message token (mapped to Lumia's
7783
+ // `{{message}}` in translate.ts). It resolves at render time from
7784
+ // the alert payload's `message` field — populated for every event
7785
+ // where SL ships a secondary-message line (donations, resubs,
7786
+ // cheers, charity, merch, etc.).
7787
+ template: translateSeText("{message}"),
7788
+ css: {
7789
+ fontFamily,
7790
+ fontSize,
7791
+ color: fontColor,
7792
+ fontWeight
7793
+ }
7794
+ };
7795
+ }
7741
7796
  function clampVolume(slVolume) {
7742
7797
  if (typeof slVolume !== "number" || !Number.isFinite(slVolume)) return 0.5;
7743
7798
  return Math.max(0, Math.min(1, slVolume / 100));
package/dist/se-import.js CHANGED
@@ -20,7 +20,40 @@ var SE_TO_LUMIA_PLACEHOLDER = {
20
20
  // tied to an alert payload), so we route it at the *global* template
21
21
  // variable `{{streamer}}` populated by VariablesManager.refreshStreamerVariable
22
22
  // (Twitch → Kick → YouTube → Facebook → TikTok fallback chain).
23
- streamer: "streamer"
23
+ streamer: "streamer",
24
+ // Sub / resub months — SL and SE both expose `{months}` inside sub-event
25
+ // variation templates ("{name} just resubbed for {months} months!"). Lumia
26
+ // surfaces this on the subscriber alert payload as `subMonths` (see
27
+ // lumia-types/src/variables.types.ts). Mapping is global because `{months}`
28
+ // only ever appears in subscriber-context templates in the wild — neither
29
+ // SE nor SL emit it for follower / cheer / tip alerts.
30
+ months: "subMonths",
31
+ // Merch / loyalty redemption product name — SL emits `{product}` in
32
+ // merch_message_template and loyalty_store_redemption_message_template,
33
+ // SE emits it the same way. Lumia's shopOrder alert exposes the first
34
+ // item's name as `firstItem.name`; alias to `item` (which already maps
35
+ // there) so both tokens resolve identically.
36
+ product: "firstItem.name",
37
+ // Treatstream title — SL `treat_message_template`
38
+ // ("{name} bought you a {title} treat"). Lumia's treat alert exposes the
39
+ // gift name as `treat` (see treatstream entry in variables.types.ts).
40
+ title: "treat",
41
+ // SL custom-HTML alias for the chat message — `{userMessage}` and
42
+ // `{message}` mean the same thing. Both should resolve to Lumia's
43
+ // `{{message}}`.
44
+ userMessage: "message",
45
+ // Prime-gaming gift tier — SL `prime_sub_gift_message_template`
46
+ // ("{name} gifted {giftType} Ultra subscription to {streamer}"). The gift
47
+ // type carries the subscription tier ("1000" / "2000" / "3000" / "prime")
48
+ // which Lumia exposes as `tier` on every sub-related alert payload.
49
+ giftType: "tier",
50
+ // TikTok-style jewel gift quantity — SL `jewel_gift_message_template`
51
+ // ("{name} gifted {giftName} x{jewelsAmount} jewels!"). Lumia's tiktok-gift
52
+ // alert exposes the quantity as `amount`. `{giftName}` (the gift's display
53
+ // name) doesn't have a 1:1 Lumia variable — TikTok's gift catalog isn't
54
+ // directly imported — so we leave it unmapped and the streamer can adjust
55
+ // the template in the Lumia editor.
56
+ jewelsAmount: "amount"
24
57
  };
25
58
  var TWITCH_CONTEXTS = {
26
59
  "follower-latest": {
@@ -3752,9 +3785,9 @@ async function fetchWithProxyFallback(url, options = {}) {
3752
3785
  }
3753
3786
 
3754
3787
  // src/se-import/assets.ts
3755
- var IMPORTABLE_CDN_REGEX = /https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\/[^\s"'\\)]+/g;
3788
+ var IMPORTABLE_CDN_REGEX = /https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|streamlabs\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\/[^\s"'\\)]+/g;
3756
3789
  var CSS_URL_REGEX = /url\(\s*['"]?([^'")]+)['"]?\s*\)/g;
3757
- var IMPORTABLE_CDN_HOST_REGEX = /^https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\//;
3790
+ var IMPORTABLE_CDN_HOST_REGEX = /^https?:\/\/(?:(?:cdn|static)\.streamelements\.com|streamelements-cdn\.com|streamlabs\.com|cdn\.streamlabs\.com|(?:cdn|uploads)\.twitchalerts\.com)\//;
3758
3791
  function isImportableAssetUrl(url) {
3759
3792
  return IMPORTABLE_CDN_HOST_REGEX.test(url);
3760
3793
  }
@@ -6479,7 +6512,7 @@ function absolutizeSLUrl(raw) {
6479
6512
  if (typeof raw !== "string" || raw.length === 0) return "";
6480
6513
  if (raw.startsWith("http://") || raw.startsWith("https://")) return raw;
6481
6514
  if (raw.startsWith("//")) return `https:${raw}`;
6482
- if (raw.startsWith("/")) return `https://cdn.streamlabs.com${raw}`;
6515
+ if (raw.startsWith("/")) return `https://streamlabs.com${raw}`;
6483
6516
  return raw;
6484
6517
  }
6485
6518
  function buildBaseAlertEvent(settings, prefix, defaultMessage) {
@@ -6490,13 +6523,7 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
6490
6523
  const fontWeight = getField(settings, prefix, "font_weight") ?? 600;
6491
6524
  const fontColor = getField(settings, prefix, "font_color") ?? "#FFFFFF";
6492
6525
  const highlightColor = getField(settings, prefix, "font_color2") ?? "#32C3A6";
6493
- const messageFontSize = pxToNumber(
6494
- getField(settings, prefix, "message_font_size"),
6495
- 20
6496
- );
6497
- const messageFontFamily = getField(settings, prefix, "message_font") ?? fontFamily;
6498
- const messageFontWeight = getField(settings, prefix, "message_font_weight") ?? 400;
6499
- const messageFontColor = getField(settings, prefix, "message_font_color") ?? "#FFFFFF";
6526
+ const secondaryMessage = readSecondaryMessageConfig(settings, prefix, fontFamily);
6500
6527
  const imageHref = absolutizeSLUrl(getField(settings, prefix, "image_href"));
6501
6528
  const soundHref = absolutizeSLUrl(getField(settings, prefix, "sound_href"));
6502
6529
  const soundVolume = getField(settings, prefix, "sound_volume") ?? 50;
@@ -6515,7 +6542,7 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
6515
6542
  accentColor: null,
6516
6543
  highlightColor,
6517
6544
  firstMessageTemplate: translateSeText(messageTemplate),
6518
- secondMessageTemplate: "",
6545
+ secondMessageTemplate: secondaryMessage?.template ?? "",
6519
6546
  thirdMessageTemplate: "",
6520
6547
  showAvatar: false,
6521
6548
  showAmount: true,
@@ -6538,12 +6565,10 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
6538
6565
  textShadow: "rgba(0, 0, 0, 0.8) 1px 1px 1px",
6539
6566
  textAlign: "center"
6540
6567
  },
6541
- messageCss: {
6542
- fontFamily: messageFontFamily,
6543
- fontSize: messageFontSize,
6544
- color: messageFontColor,
6545
- fontWeight: messageFontWeight
6546
- },
6568
+ // `messageCss` only matters when secondMessageTemplate is set;
6569
+ // leave it empty when SL didn't ship a secondary-message block
6570
+ // so Lumia's renderer falls back to its own default styling.
6571
+ messageCss: secondaryMessage?.css ?? {},
6547
6572
  content: { value: translateSeText(messageTemplate) }
6548
6573
  },
6549
6574
  media: {
@@ -6586,6 +6611,36 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
6586
6611
  variations: []
6587
6612
  };
6588
6613
  }
6614
+ var SECONDARY_MESSAGE_PREFIX_OVERRIDE = {
6615
+ sub: "resub"
6616
+ };
6617
+ function readSecondaryMessageConfig(settings, prefix, primaryFontFamily) {
6618
+ const secondaryPrefix = SECONDARY_MESSAGE_PREFIX_OVERRIDE[prefix] ?? prefix;
6619
+ const showKey = `show_${secondaryPrefix}_message`;
6620
+ const enabled = settings[showKey];
6621
+ if (enabled !== true) return null;
6622
+ const fontFamily = getField(settings, secondaryPrefix, "message_font") ?? primaryFontFamily;
6623
+ const fontSize = pxToNumber(
6624
+ getField(settings, secondaryPrefix, "message_font_size"),
6625
+ 20
6626
+ );
6627
+ const fontWeight = getField(settings, secondaryPrefix, "message_font_weight") ?? 400;
6628
+ const fontColor = getField(settings, secondaryPrefix, "message_font_color") ?? "#FFFFFF";
6629
+ return {
6630
+ // `{message}` is the SE/SL chat-message token (mapped to Lumia's
6631
+ // `{{message}}` in translate.ts). It resolves at render time from
6632
+ // the alert payload's `message` field — populated for every event
6633
+ // where SL ships a secondary-message line (donations, resubs,
6634
+ // cheers, charity, merch, etc.).
6635
+ template: translateSeText("{message}"),
6636
+ css: {
6637
+ fontFamily,
6638
+ fontSize,
6639
+ color: fontColor,
6640
+ fontWeight
6641
+ }
6642
+ };
6643
+ }
6589
6644
  function clampVolume(slVolume) {
6590
6645
  if (typeof slVolume !== "number" || !Number.isFinite(slVolume)) return 0.5;
6591
6646
  return Math.max(0, Math.min(1, slVolume / 100));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumiastream/ui",
3
- "version": "0.5.0",
3
+ "version": "0.5.3",
4
4
  "author": "Lumia Stream",
5
5
  "license": "ISC",
6
6
  "description": "Lumia UI Kit",