@viasoftbr/shared-ui 0.0.5 → 0.0.7

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.
@@ -4,7 +4,7 @@ import { AudioGroup, FilterGroup, MiddlewareAuthGroup, MiddlewareChannelsGroup,
4
4
  import { DvB, Livecast, ViewLog } from './encoder';
5
5
  import { CheckboxField, ColorField, DatePicker, EditInPlaceField, InputField, Protocol, RangeField, SelectField, SliderField, SwitchField } from './input';
6
6
  import { Footer, Header, PageHeader, SaveDiscard, Sidebar } from './main';
7
- import { AddNetwork, InterfacesTable, InterfacesTimeseries } from './network';
7
+ import { AddNetwork, InterfacesTable, InterfacesTimeseries, isValidIPv4, isValidIPv6 } from './network';
8
8
  import { ConfigWizard, RequireAuth } from './system';
9
9
  import { Fflog, MetricBar, Panel, Preview, StreamControl, VideoPlayer, VUBar } from './xcoder';
10
- export { Accordion, AddNetwork, AudioGroup, CheckboxField, ConfigWizard, Copy2Clipboard, ColorField, getGridLabel, GridSelectionModal, DatePicker, DvB, EditInPlaceField, Fflog, FilterGroup, Footer, Header, InputField, InterfacesTable, InterfacesTimeseries, SwitchField, Livecast, MetricBar, MiddlewareAuthGroup, MiddlewareChannelsGroup, MiddlewareMOSGroup, MiddlewareServiceGroup, Modal, PageHeader, Panel, Preview, PreviewGroup, ProtocolGroup, Protocol, RangeField, RequireAuth, SaveDiscard, Section, SelectField, Sidebar, SliderField, StreamControl, ValidationItem, VideoGroup, VideoPlayer, ViewLog, VUBar };
10
+ export { Accordion, AddNetwork, AudioGroup, CheckboxField, ConfigWizard, Copy2Clipboard, ColorField, getGridLabel, GridSelectionModal, DatePicker, DvB, EditInPlaceField, Fflog, FilterGroup, Footer, Header, InputField, InterfacesTable, InterfacesTimeseries, isValidIPv4, isValidIPv6, SwitchField, Livecast, MetricBar, MiddlewareAuthGroup, MiddlewareChannelsGroup, MiddlewareMOSGroup, MiddlewareServiceGroup, Modal, PageHeader, Panel, Preview, PreviewGroup, ProtocolGroup, Protocol, RangeField, RequireAuth, SaveDiscard, Section, SelectField, Sidebar, SliderField, StreamControl, ValidationItem, VideoGroup, VideoPlayer, ViewLog, VUBar };
@@ -1,4 +1,5 @@
1
- import AddNetwork from "./AddNetwork.tsx";
2
- import InterfacesTable from "./InterfacesTable.tsx";
3
- import InterfacesTimeseries from "./InterfacesTimeseries.tsx";
4
- export { AddNetwork, InterfacesTable, InterfacesTimeseries, };
1
+ import AddNetwork from "./AddNetwork";
2
+ import InterfacesTable from "./InterfacesTable";
3
+ import InterfacesTimeseries from "./InterfacesTimeseries";
4
+ import { isValidIPv4, isValidIPv6 } from "./validators";
5
+ export { AddNetwork, InterfacesTable, InterfacesTimeseries, isValidIPv4, isValidIPv6, };
@@ -165,7 +165,9 @@ __export(components_exports, {
165
165
  VideoGroup: () => VideoGroup_default,
166
166
  VideoPlayer: () => VideoPlayer_default,
167
167
  ViewLog: () => ViewLog_default,
168
- getGridLabel: () => getGridLabel
168
+ getGridLabel: () => getGridLabel,
169
+ isValidIPv4: () => isValidIPv4,
170
+ isValidIPv6: () => isValidIPv6
169
171
  });
170
172
  module.exports = __toCommonJS(components_exports);
171
173
 
@@ -25626,12 +25628,61 @@ function buildWsUrl(path = "/") {
25626
25628
  return `${proto}://${host}${path.startsWith("/") ? path : "/" + path}`;
25627
25629
  }
25628
25630
  }
25631
+ function extractBearerToken(headers, explicitToken) {
25632
+ if (explicitToken)
25633
+ return explicitToken;
25634
+ if (!headers)
25635
+ return null;
25636
+ const authHeader = headers.Authorization || headers.authorization;
25637
+ if (!authHeader)
25638
+ return null;
25639
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
25640
+ return match ? match[1] : null;
25641
+ }
25642
+ function appendWsQueryParam(url, key, value) {
25643
+ try {
25644
+ const parsed = new URL(
25645
+ url,
25646
+ typeof window !== "undefined" ? window.location.href : void 0
25647
+ );
25648
+ parsed.searchParams.set(key, value);
25649
+ return parsed.toString();
25650
+ } catch {
25651
+ const separator = url.includes("?") ? "&" : "?";
25652
+ return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
25653
+ }
25654
+ }
25655
+ function normalizeProtocols(protocols) {
25656
+ if (!protocols)
25657
+ return void 0;
25658
+ return Array.isArray(protocols) ? protocols.filter(Boolean) : [protocols];
25659
+ }
25629
25660
  async function decodeFfurl(ffurl) {
25630
25661
  const { settings } = await fetchApi.postJson("/auth/protocols/ffurl/decode", { ffurl });
25631
25662
  return settings;
25632
25663
  }
25633
- function subscribeToWebsocket(url, onMessage) {
25634
- const socket = new WebSocket(url);
25664
+ function subscribeToWebsocket(url, onMessage, options = {}) {
25665
+ const bearerToken = extractBearerToken(options.headers, options.bearerToken);
25666
+ const bearerStrategy = options.bearerStrategy ?? "query";
25667
+ let resolvedUrl = url;
25668
+ const protocols = normalizeProtocols(options.protocols) ?? [];
25669
+ if (options.headers && Object.keys(options.headers).length > 0) {
25670
+ console.warn(
25671
+ "WebSocket connections in browsers do not support custom HTTP headers. shared-ui will derive bearer auth from Authorization and forward it using query string or subprotocol."
25672
+ );
25673
+ }
25674
+ if (bearerToken) {
25675
+ if (bearerStrategy === "protocol") {
25676
+ protocols.push("bearer", bearerToken);
25677
+ } else {
25678
+ resolvedUrl = appendWsQueryParam(
25679
+ url,
25680
+ options.bearerQueryParam ?? "access_token",
25681
+ bearerToken
25682
+ );
25683
+ }
25684
+ }
25685
+ const socket = protocols.length > 0 ? new WebSocket(resolvedUrl, protocols) : new WebSocket(resolvedUrl);
25635
25686
  socket.onmessage = (event) => {
25636
25687
  try {
25637
25688
  const data = JSON.parse(event.data);
@@ -35286,7 +35337,7 @@ var Footer = () => {
35286
35337
  var Footer_default = Footer;
35287
35338
 
35288
35339
  // src/components/main/Header.tsx
35289
- var import_react86 = __toESM(require("react"), 1);
35340
+ var import_react86 = __toESM(require("react"));
35290
35341
  var import_react_router_dom = require("react-router-dom");
35291
35342
  var import_jsx_runtime33 = require("react/jsx-runtime");
35292
35343
  function classNames(...classes) {
@@ -35656,7 +35707,7 @@ var Header = ({ isSidebarOpen, setSidebarOpen, onNavigate }) => {
35656
35707
  var Header_default = Header;
35657
35708
 
35658
35709
  // src/components/main/PageHeader.tsx
35659
- var import_react88 = __toESM(require("react"), 1);
35710
+ var import_react88 = __toESM(require("react"));
35660
35711
  var import_jsx_runtime34 = require("react/jsx-runtime");
35661
35712
  var PageHeader = ({
35662
35713
  icon,
@@ -36546,6 +36597,20 @@ var InterfacesTimeseries = ({
36546
36597
  };
36547
36598
  var InterfacesTimeseries_default = InterfacesTimeseries;
36548
36599
 
36600
+ // src/components/network/validators.ts
36601
+ var isValidIPv4 = (ip) => {
36602
+ if (!ip)
36603
+ return false;
36604
+ const ipv4Regex = /^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/;
36605
+ return ipv4Regex.test(ip.trim());
36606
+ };
36607
+ var isValidIPv6 = (ip) => {
36608
+ if (!ip)
36609
+ return false;
36610
+ const ipv6Regex = /^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$|^((?:[A-F0-9]{1,4}(?::|$)){1,8})$/i;
36611
+ return ipv6Regex.test(ip.trim());
36612
+ };
36613
+
36549
36614
  // src/components/system/RequireAuth.tsx
36550
36615
  var import_react_router_dom3 = require("react-router-dom");
36551
36616
  var import_jsx_runtime40 = require("react/jsx-runtime");
@@ -40019,7 +40084,7 @@ instance.use(initReactI18next).init({
40019
40084
  var i18n_default = instance;
40020
40085
 
40021
40086
  // src/context/SharedUiProvider.tsx
40022
- var import_react104 = __toESM(require("react"), 1);
40087
+ var import_react104 = __toESM(require("react"));
40023
40088
  var import_react_query2 = require("@tanstack/react-query");
40024
40089
  var import_jsx_runtime41 = require("react/jsx-runtime");
40025
40090
 
@@ -25571,12 +25571,61 @@ function buildWsUrl(path = "/") {
25571
25571
  return `${proto}://${host}${path.startsWith("/") ? path : "/" + path}`;
25572
25572
  }
25573
25573
  }
25574
+ function extractBearerToken(headers, explicitToken) {
25575
+ if (explicitToken)
25576
+ return explicitToken;
25577
+ if (!headers)
25578
+ return null;
25579
+ const authHeader = headers.Authorization || headers.authorization;
25580
+ if (!authHeader)
25581
+ return null;
25582
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
25583
+ return match ? match[1] : null;
25584
+ }
25585
+ function appendWsQueryParam(url, key, value) {
25586
+ try {
25587
+ const parsed = new URL(
25588
+ url,
25589
+ typeof window !== "undefined" ? window.location.href : void 0
25590
+ );
25591
+ parsed.searchParams.set(key, value);
25592
+ return parsed.toString();
25593
+ } catch {
25594
+ const separator = url.includes("?") ? "&" : "?";
25595
+ return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
25596
+ }
25597
+ }
25598
+ function normalizeProtocols(protocols) {
25599
+ if (!protocols)
25600
+ return void 0;
25601
+ return Array.isArray(protocols) ? protocols.filter(Boolean) : [protocols];
25602
+ }
25574
25603
  async function decodeFfurl(ffurl) {
25575
25604
  const { settings } = await fetchApi.postJson("/auth/protocols/ffurl/decode", { ffurl });
25576
25605
  return settings;
25577
25606
  }
25578
- function subscribeToWebsocket(url, onMessage) {
25579
- const socket = new WebSocket(url);
25607
+ function subscribeToWebsocket(url, onMessage, options = {}) {
25608
+ const bearerToken = extractBearerToken(options.headers, options.bearerToken);
25609
+ const bearerStrategy = options.bearerStrategy ?? "query";
25610
+ let resolvedUrl = url;
25611
+ const protocols = normalizeProtocols(options.protocols) ?? [];
25612
+ if (options.headers && Object.keys(options.headers).length > 0) {
25613
+ console.warn(
25614
+ "WebSocket connections in browsers do not support custom HTTP headers. shared-ui will derive bearer auth from Authorization and forward it using query string or subprotocol."
25615
+ );
25616
+ }
25617
+ if (bearerToken) {
25618
+ if (bearerStrategy === "protocol") {
25619
+ protocols.push("bearer", bearerToken);
25620
+ } else {
25621
+ resolvedUrl = appendWsQueryParam(
25622
+ url,
25623
+ options.bearerQueryParam ?? "access_token",
25624
+ bearerToken
25625
+ );
25626
+ }
25627
+ }
25628
+ const socket = protocols.length > 0 ? new WebSocket(resolvedUrl, protocols) : new WebSocket(resolvedUrl);
25580
25629
  socket.onmessage = (event) => {
25581
25630
  try {
25582
25631
  const data = JSON.parse(event.data);
@@ -36491,6 +36540,20 @@ var InterfacesTimeseries = ({
36491
36540
  };
36492
36541
  var InterfacesTimeseries_default = InterfacesTimeseries;
36493
36542
 
36543
+ // src/components/network/validators.ts
36544
+ var isValidIPv4 = (ip) => {
36545
+ if (!ip)
36546
+ return false;
36547
+ const ipv4Regex = /^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/;
36548
+ return ipv4Regex.test(ip.trim());
36549
+ };
36550
+ var isValidIPv6 = (ip) => {
36551
+ if (!ip)
36552
+ return false;
36553
+ const ipv6Regex = /^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$|^((?:[A-F0-9]{1,4}(?::|$)){1,8})$/i;
36554
+ return ipv6Regex.test(ip.trim());
36555
+ };
36556
+
36494
36557
  // src/components/system/RequireAuth.tsx
36495
36558
  import { Navigate } from "react-router-dom";
36496
36559
  import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
@@ -40891,7 +40954,9 @@ export {
40891
40954
  VideoGroup_default as VideoGroup,
40892
40955
  VideoPlayer_default as VideoPlayer,
40893
40956
  ViewLog_default as ViewLog,
40894
- getGridLabel
40957
+ getGridLabel,
40958
+ isValidIPv4,
40959
+ isValidIPv6
40895
40960
  };
40896
40961
  /*! Bundled license information:
40897
40962
 
package/dist/context.cjs CHANGED
@@ -3027,7 +3027,7 @@ function useAuth() {
3027
3027
  }
3028
3028
 
3029
3029
  // src/context/SharedUiProvider.tsx
3030
- var import_react3 = __toESM(require("react"), 1);
3030
+ var import_react3 = __toESM(require("react"));
3031
3031
  var import_react_query = require("@tanstack/react-query");
3032
3032
  var import_jsx_runtime3 = require("react/jsx-runtime");
3033
3033
  function SharedUiProvider({ children, client }) {
package/dist/index.cjs CHANGED
@@ -186,6 +186,8 @@ __export(src_exports, {
186
186
  getRefreshToken: () => getRefreshToken,
187
187
  hostConfigLoader: () => hostConfigLoader,
188
188
  isFirstRun: () => isFirstRun,
189
+ isValidIPv4: () => isValidIPv4,
190
+ isValidIPv6: () => isValidIPv6,
189
191
  registry: () => registry,
190
192
  saveConfig: () => saveConfig,
191
193
  setAccessToken: () => setAccessToken,
@@ -3038,6 +3040,35 @@ function buildWsUrl(path = "/") {
3038
3040
  return `${proto}://${host}${path.startsWith("/") ? path : "/" + path}`;
3039
3041
  }
3040
3042
  }
3043
+ function extractBearerToken(headers, explicitToken) {
3044
+ if (explicitToken)
3045
+ return explicitToken;
3046
+ if (!headers)
3047
+ return null;
3048
+ const authHeader = headers.Authorization || headers.authorization;
3049
+ if (!authHeader)
3050
+ return null;
3051
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
3052
+ return match ? match[1] : null;
3053
+ }
3054
+ function appendWsQueryParam(url, key, value) {
3055
+ try {
3056
+ const parsed = new URL(
3057
+ url,
3058
+ typeof window !== "undefined" ? window.location.href : void 0
3059
+ );
3060
+ parsed.searchParams.set(key, value);
3061
+ return parsed.toString();
3062
+ } catch {
3063
+ const separator = url.includes("?") ? "&" : "?";
3064
+ return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
3065
+ }
3066
+ }
3067
+ function normalizeProtocols(protocols) {
3068
+ if (!protocols)
3069
+ return void 0;
3070
+ return Array.isArray(protocols) ? protocols.filter(Boolean) : [protocols];
3071
+ }
3041
3072
  async function encodeFfurl(settings) {
3042
3073
  const { ffurl } = await fetchApi.postJson("/auth/protocols/ffurl/encode", settings);
3043
3074
  return ffurl;
@@ -3046,8 +3077,28 @@ async function decodeFfurl(ffurl) {
3046
3077
  const { settings } = await fetchApi.postJson("/auth/protocols/ffurl/decode", { ffurl });
3047
3078
  return settings;
3048
3079
  }
3049
- function subscribeToWebsocket(url, onMessage) {
3050
- const socket = new WebSocket(url);
3080
+ function subscribeToWebsocket(url, onMessage, options = {}) {
3081
+ const bearerToken = extractBearerToken(options.headers, options.bearerToken);
3082
+ const bearerStrategy = options.bearerStrategy ?? "query";
3083
+ let resolvedUrl = url;
3084
+ const protocols = normalizeProtocols(options.protocols) ?? [];
3085
+ if (options.headers && Object.keys(options.headers).length > 0) {
3086
+ console.warn(
3087
+ "WebSocket connections in browsers do not support custom HTTP headers. shared-ui will derive bearer auth from Authorization and forward it using query string or subprotocol."
3088
+ );
3089
+ }
3090
+ if (bearerToken) {
3091
+ if (bearerStrategy === "protocol") {
3092
+ protocols.push("bearer", bearerToken);
3093
+ } else {
3094
+ resolvedUrl = appendWsQueryParam(
3095
+ url,
3096
+ options.bearerQueryParam ?? "access_token",
3097
+ bearerToken
3098
+ );
3099
+ }
3100
+ }
3101
+ const socket = protocols.length > 0 ? new WebSocket(resolvedUrl, protocols) : new WebSocket(resolvedUrl);
3051
3102
  socket.onmessage = (event) => {
3052
3103
  try {
3053
3104
  const data = JSON.parse(event.data);
@@ -35545,7 +35596,7 @@ var Footer = () => {
35545
35596
  var Footer_default = Footer;
35546
35597
 
35547
35598
  // src/components/main/Header.tsx
35548
- var import_react86 = __toESM(require("react"), 1);
35599
+ var import_react86 = __toESM(require("react"));
35549
35600
  var import_react_router_dom = require("react-router-dom");
35550
35601
  var import_jsx_runtime33 = require("react/jsx-runtime");
35551
35602
  function classNames(...classes) {
@@ -35915,7 +35966,7 @@ var Header = ({ isSidebarOpen, setSidebarOpen, onNavigate }) => {
35915
35966
  var Header_default = Header;
35916
35967
 
35917
35968
  // src/components/main/PageHeader.tsx
35918
- var import_react88 = __toESM(require("react"), 1);
35969
+ var import_react88 = __toESM(require("react"));
35919
35970
  var import_jsx_runtime34 = require("react/jsx-runtime");
35920
35971
  var PageHeader = ({
35921
35972
  icon,
@@ -36805,6 +36856,20 @@ var InterfacesTimeseries = ({
36805
36856
  };
36806
36857
  var InterfacesTimeseries_default = InterfacesTimeseries;
36807
36858
 
36859
+ // src/components/network/validators.ts
36860
+ var isValidIPv4 = (ip) => {
36861
+ if (!ip)
36862
+ return false;
36863
+ const ipv4Regex = /^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/;
36864
+ return ipv4Regex.test(ip.trim());
36865
+ };
36866
+ var isValidIPv6 = (ip) => {
36867
+ if (!ip)
36868
+ return false;
36869
+ const ipv6Regex = /^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$|^((?:[A-F0-9]{1,4}(?::|$)){1,8})$/i;
36870
+ return ipv6Regex.test(ip.trim());
36871
+ };
36872
+
36808
36873
  // src/components/system/RequireAuth.tsx
36809
36874
  var import_react_router_dom3 = require("react-router-dom");
36810
36875
  var import_jsx_runtime40 = require("react/jsx-runtime");
@@ -40278,7 +40343,7 @@ instance.use(initReactI18next).init({
40278
40343
  var i18n_default = instance;
40279
40344
 
40280
40345
  // src/context/SharedUiProvider.tsx
40281
- var import_react104 = __toESM(require("react"), 1);
40346
+ var import_react104 = __toESM(require("react"));
40282
40347
  var import_react_query2 = require("@tanstack/react-query");
40283
40348
  var import_jsx_runtime41 = require("react/jsx-runtime");
40284
40349
  function SharedUiProvider({ children, client }) {
package/dist/index.js CHANGED
@@ -2953,6 +2953,35 @@ function buildWsUrl(path = "/") {
2953
2953
  return `${proto}://${host}${path.startsWith("/") ? path : "/" + path}`;
2954
2954
  }
2955
2955
  }
2956
+ function extractBearerToken(headers, explicitToken) {
2957
+ if (explicitToken)
2958
+ return explicitToken;
2959
+ if (!headers)
2960
+ return null;
2961
+ const authHeader = headers.Authorization || headers.authorization;
2962
+ if (!authHeader)
2963
+ return null;
2964
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
2965
+ return match ? match[1] : null;
2966
+ }
2967
+ function appendWsQueryParam(url, key, value) {
2968
+ try {
2969
+ const parsed = new URL(
2970
+ url,
2971
+ typeof window !== "undefined" ? window.location.href : void 0
2972
+ );
2973
+ parsed.searchParams.set(key, value);
2974
+ return parsed.toString();
2975
+ } catch {
2976
+ const separator = url.includes("?") ? "&" : "?";
2977
+ return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
2978
+ }
2979
+ }
2980
+ function normalizeProtocols(protocols) {
2981
+ if (!protocols)
2982
+ return void 0;
2983
+ return Array.isArray(protocols) ? protocols.filter(Boolean) : [protocols];
2984
+ }
2956
2985
  async function encodeFfurl(settings) {
2957
2986
  const { ffurl } = await fetchApi.postJson("/auth/protocols/ffurl/encode", settings);
2958
2987
  return ffurl;
@@ -2961,8 +2990,28 @@ async function decodeFfurl(ffurl) {
2961
2990
  const { settings } = await fetchApi.postJson("/auth/protocols/ffurl/decode", { ffurl });
2962
2991
  return settings;
2963
2992
  }
2964
- function subscribeToWebsocket(url, onMessage) {
2965
- const socket = new WebSocket(url);
2993
+ function subscribeToWebsocket(url, onMessage, options = {}) {
2994
+ const bearerToken = extractBearerToken(options.headers, options.bearerToken);
2995
+ const bearerStrategy = options.bearerStrategy ?? "query";
2996
+ let resolvedUrl = url;
2997
+ const protocols = normalizeProtocols(options.protocols) ?? [];
2998
+ if (options.headers && Object.keys(options.headers).length > 0) {
2999
+ console.warn(
3000
+ "WebSocket connections in browsers do not support custom HTTP headers. shared-ui will derive bearer auth from Authorization and forward it using query string or subprotocol."
3001
+ );
3002
+ }
3003
+ if (bearerToken) {
3004
+ if (bearerStrategy === "protocol") {
3005
+ protocols.push("bearer", bearerToken);
3006
+ } else {
3007
+ resolvedUrl = appendWsQueryParam(
3008
+ url,
3009
+ options.bearerQueryParam ?? "access_token",
3010
+ bearerToken
3011
+ );
3012
+ }
3013
+ }
3014
+ const socket = protocols.length > 0 ? new WebSocket(resolvedUrl, protocols) : new WebSocket(resolvedUrl);
2966
3015
  socket.onmessage = (event) => {
2967
3016
  try {
2968
3017
  const data = JSON.parse(event.data);
@@ -36720,6 +36769,20 @@ var InterfacesTimeseries = ({
36720
36769
  };
36721
36770
  var InterfacesTimeseries_default = InterfacesTimeseries;
36722
36771
 
36772
+ // src/components/network/validators.ts
36773
+ var isValidIPv4 = (ip) => {
36774
+ if (!ip)
36775
+ return false;
36776
+ const ipv4Regex = /^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/;
36777
+ return ipv4Regex.test(ip.trim());
36778
+ };
36779
+ var isValidIPv6 = (ip) => {
36780
+ if (!ip)
36781
+ return false;
36782
+ const ipv6Regex = /^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$|^((?:[A-F0-9]{1,4}(?::|$)){1,8})$/i;
36783
+ return ipv6Regex.test(ip.trim());
36784
+ };
36785
+
36723
36786
  // src/components/system/RequireAuth.tsx
36724
36787
  import { Navigate } from "react-router-dom";
36725
36788
  import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
@@ -41279,6 +41342,8 @@ export {
41279
41342
  getRefreshToken,
41280
41343
  hostConfigLoader,
41281
41344
  isFirstRun,
41345
+ isValidIPv4,
41346
+ isValidIPv6,
41282
41347
  registry,
41283
41348
  saveConfig,
41284
41349
  setAccessToken,
@@ -1,4 +1,5 @@
1
1
  import { ProtocolSettings } from '../types/protocol';
2
+ import { WebSocketSubscribeOptions } from '../types/websocket';
2
3
  export declare const api: import("axios").AxiosInstance;
3
4
  export declare const authApi: import("axios").AxiosInstance;
4
5
  export declare function getAccessToken(): string | null;
@@ -19,4 +20,4 @@ export declare const fetchApi: {
19
20
  export declare function buildWsUrl(path?: string): string;
20
21
  export declare function encodeFfurl(settings: ProtocolSettings): Promise<string>;
21
22
  export declare function decodeFfurl(ffurl: string): Promise<ProtocolSettings>;
22
- export declare function subscribeToWebsocket(url: string, onMessage: (data: any) => void): () => void;
23
+ export declare function subscribeToWebsocket(url: string, onMessage: (data: any) => void, options?: WebSocketSubscribeOptions): () => void;
package/dist/services.cjs CHANGED
@@ -2887,6 +2887,35 @@ function buildWsUrl(path = "/") {
2887
2887
  return `${proto}://${host}${path.startsWith("/") ? path : "/" + path}`;
2888
2888
  }
2889
2889
  }
2890
+ function extractBearerToken(headers, explicitToken) {
2891
+ if (explicitToken)
2892
+ return explicitToken;
2893
+ if (!headers)
2894
+ return null;
2895
+ const authHeader = headers.Authorization || headers.authorization;
2896
+ if (!authHeader)
2897
+ return null;
2898
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
2899
+ return match ? match[1] : null;
2900
+ }
2901
+ function appendWsQueryParam(url, key, value) {
2902
+ try {
2903
+ const parsed = new URL(
2904
+ url,
2905
+ typeof window !== "undefined" ? window.location.href : void 0
2906
+ );
2907
+ parsed.searchParams.set(key, value);
2908
+ return parsed.toString();
2909
+ } catch {
2910
+ const separator = url.includes("?") ? "&" : "?";
2911
+ return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
2912
+ }
2913
+ }
2914
+ function normalizeProtocols(protocols) {
2915
+ if (!protocols)
2916
+ return void 0;
2917
+ return Array.isArray(protocols) ? protocols.filter(Boolean) : [protocols];
2918
+ }
2890
2919
  async function encodeFfurl(settings) {
2891
2920
  const { ffurl } = await fetchApi.postJson("/auth/protocols/ffurl/encode", settings);
2892
2921
  return ffurl;
@@ -2895,8 +2924,28 @@ async function decodeFfurl(ffurl) {
2895
2924
  const { settings } = await fetchApi.postJson("/auth/protocols/ffurl/decode", { ffurl });
2896
2925
  return settings;
2897
2926
  }
2898
- function subscribeToWebsocket(url, onMessage) {
2899
- const socket = new WebSocket(url);
2927
+ function subscribeToWebsocket(url, onMessage, options = {}) {
2928
+ const bearerToken = extractBearerToken(options.headers, options.bearerToken);
2929
+ const bearerStrategy = options.bearerStrategy ?? "query";
2930
+ let resolvedUrl = url;
2931
+ const protocols = normalizeProtocols(options.protocols) ?? [];
2932
+ if (options.headers && Object.keys(options.headers).length > 0) {
2933
+ console.warn(
2934
+ "WebSocket connections in browsers do not support custom HTTP headers. shared-ui will derive bearer auth from Authorization and forward it using query string or subprotocol."
2935
+ );
2936
+ }
2937
+ if (bearerToken) {
2938
+ if (bearerStrategy === "protocol") {
2939
+ protocols.push("bearer", bearerToken);
2940
+ } else {
2941
+ resolvedUrl = appendWsQueryParam(
2942
+ url,
2943
+ options.bearerQueryParam ?? "access_token",
2944
+ bearerToken
2945
+ );
2946
+ }
2947
+ }
2948
+ const socket = protocols.length > 0 ? new WebSocket(resolvedUrl, protocols) : new WebSocket(resolvedUrl);
2900
2949
  socket.onmessage = (event) => {
2901
2950
  try {
2902
2951
  const data = JSON.parse(event.data);
package/dist/services.js CHANGED
@@ -2847,6 +2847,35 @@ function buildWsUrl(path = "/") {
2847
2847
  return `${proto}://${host}${path.startsWith("/") ? path : "/" + path}`;
2848
2848
  }
2849
2849
  }
2850
+ function extractBearerToken(headers, explicitToken) {
2851
+ if (explicitToken)
2852
+ return explicitToken;
2853
+ if (!headers)
2854
+ return null;
2855
+ const authHeader = headers.Authorization || headers.authorization;
2856
+ if (!authHeader)
2857
+ return null;
2858
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
2859
+ return match ? match[1] : null;
2860
+ }
2861
+ function appendWsQueryParam(url, key, value) {
2862
+ try {
2863
+ const parsed = new URL(
2864
+ url,
2865
+ typeof window !== "undefined" ? window.location.href : void 0
2866
+ );
2867
+ parsed.searchParams.set(key, value);
2868
+ return parsed.toString();
2869
+ } catch {
2870
+ const separator = url.includes("?") ? "&" : "?";
2871
+ return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
2872
+ }
2873
+ }
2874
+ function normalizeProtocols(protocols) {
2875
+ if (!protocols)
2876
+ return void 0;
2877
+ return Array.isArray(protocols) ? protocols.filter(Boolean) : [protocols];
2878
+ }
2850
2879
  async function encodeFfurl(settings) {
2851
2880
  const { ffurl } = await fetchApi.postJson("/auth/protocols/ffurl/encode", settings);
2852
2881
  return ffurl;
@@ -2855,8 +2884,28 @@ async function decodeFfurl(ffurl) {
2855
2884
  const { settings } = await fetchApi.postJson("/auth/protocols/ffurl/decode", { ffurl });
2856
2885
  return settings;
2857
2886
  }
2858
- function subscribeToWebsocket(url, onMessage) {
2859
- const socket = new WebSocket(url);
2887
+ function subscribeToWebsocket(url, onMessage, options = {}) {
2888
+ const bearerToken = extractBearerToken(options.headers, options.bearerToken);
2889
+ const bearerStrategy = options.bearerStrategy ?? "query";
2890
+ let resolvedUrl = url;
2891
+ const protocols = normalizeProtocols(options.protocols) ?? [];
2892
+ if (options.headers && Object.keys(options.headers).length > 0) {
2893
+ console.warn(
2894
+ "WebSocket connections in browsers do not support custom HTTP headers. shared-ui will derive bearer auth from Authorization and forward it using query string or subprotocol."
2895
+ );
2896
+ }
2897
+ if (bearerToken) {
2898
+ if (bearerStrategy === "protocol") {
2899
+ protocols.push("bearer", bearerToken);
2900
+ } else {
2901
+ resolvedUrl = appendWsQueryParam(
2902
+ url,
2903
+ options.bearerQueryParam ?? "access_token",
2904
+ bearerToken
2905
+ );
2906
+ }
2907
+ }
2908
+ const socket = protocols.length > 0 ? new WebSocket(resolvedUrl, protocols) : new WebSocket(resolvedUrl);
2860
2909
  socket.onmessage = (event) => {
2861
2910
  try {
2862
2911
  const data = JSON.parse(event.data);
@@ -1,6 +1,6 @@
1
- export * from './auth.ts';
2
- export * from './module.ts';
3
- export * from './plugin.types.ts';
4
- export * from './protocol.ts';
5
- export * from './websocket.ts';
6
- export * from './wizard.ts';
1
+ export * from './auth';
2
+ export * from './module';
3
+ export * from './plugin.types';
4
+ export * from './protocol';
5
+ export * from './websocket';
6
+ export * from './wizard';
@@ -25,3 +25,10 @@ export interface WebSocketData {
25
25
  };
26
26
  system: SystemInfo;
27
27
  }
28
+ export interface WebSocketSubscribeOptions {
29
+ headers?: Record<string, string>;
30
+ protocols?: string | string[];
31
+ bearerToken?: string | null;
32
+ bearerStrategy?: 'query' | 'protocol';
33
+ bearerQueryParam?: string;
34
+ }
package/package.json CHANGED
@@ -1,52 +1,32 @@
1
1
  {
2
2
  "name": "@viasoftbr/shared-ui",
3
- "description": "Shared frontend utilities, components and i18n for Viasoft plugins and micro-frontends",
4
- "type": "module",
5
- "main": "dist/index.js",
6
- "module": "./dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
+ "main": "./dist/index.js",
5
+ "types": "./dist/types/index.d.ts",
9
6
  "exports": {
10
- ".": {
7
+ ".": {
11
8
  "import": "./dist/index.js",
12
- "require": "./dist/index.cjs",
13
- "types": "./dist/index.d.ts"
14
- },
15
- "./index": {
16
- "import": "./dist/index.js",
17
- "require": "./dist/index.cjs",
18
- "types": "./dist/index.d.ts"
19
- },
20
- "./context": {
21
- "import": "./dist/context.js",
22
- "require": "./dist/context.cjs",
23
- "types": "./dist/context/index.d.ts"
9
+ "types": "./dist/types/index.d.ts"
24
10
  },
25
11
  "./components": {
26
- "import": "./dist/components.js",
27
- "require": "./dist/components.cjs",
28
- "types": "./dist/components/index.d.ts"
29
- },
30
- "./services": {
31
- "import": "./dist/services.js",
32
- "require": "./dist/services.cjs",
33
- "types": "./dist/services/index.d.ts"
12
+ "import": "./dist/components/index.js",
13
+ "types": "./dist/types/components/index.d.ts"
34
14
  },
35
15
  "./types": {
36
- "import": "./dist/types.js",
37
- "require": "./dist/types.cjs",
38
- "types": "./dist/types/index.d.ts"
16
+ "import": "./dist/types-module/index.js",
17
+ "types": "./dist/types/types/index.d.ts"
39
18
  },
40
- "./i18n": {
41
- "import": "./dist/i18n.js",
42
- "require": "./dist/i18n.cjs",
43
- "types": "./dist/i18n.d.ts"
19
+ "./services": {
20
+ "import": "./dist/services/index.js",
21
+ "types": "./dist/types/services/index.d.ts"
44
22
  },
45
- "./jsmpeg": {
46
- "default": "./dist/jsmpeg.vu.min.js"
23
+ "./context": {
24
+ "import": "./dist/context/index.js",
25
+ "types": "./dist/types/context/index.d.ts"
47
26
  },
48
- "./locales/*": {
49
- "default": "./dist/locales/*"
27
+ "./hooks": {
28
+ "import": "./dist/hooks/index.js",
29
+ "types": "./dist/types/hooks/index.d.ts"
50
30
  }
51
31
  },
52
32
  "scripts": {