@multiplatform.one/keycloak 7.6.3 → 7.7.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.
@@ -58,8 +58,128 @@ __export(index_exports, {
58
58
  });
59
59
  module.exports = __toCommonJS(index_exports);
60
60
 
61
+ // ../platform/src/platform/platformBase.ts
62
+ var import_constants = require("@tamagui/constants");
63
+ var platformOrder = [
64
+ "Ios",
65
+ "Android",
66
+ // Gnome outranks Native: the GTK target reports isNative (it is not a
67
+ // browser) but "gnome" is the precise answer callers want.
68
+ "Gnome",
69
+ "Native",
70
+ // Tauri outranks Desktop/Web the same way: the webview host reports isWeb
71
+ // and isDesktop, but "tauri" is the precise answer.
72
+ "Tauri",
73
+ "Desktop",
74
+ "ChromeExtension",
75
+ "FirefoxExtension",
76
+ "WebExtension",
77
+ "Next",
78
+ "Expo",
79
+ "Chrome",
80
+ "Firefox",
81
+ "Web",
82
+ "Browser",
83
+ "Client",
84
+ "Server",
85
+ "Iframe",
86
+ "Storybook"
87
+ ];
88
+ var platformBase = {
89
+ isAndroid: false,
90
+ isBrowser: false,
91
+ isChrome: import_constants.isChrome,
92
+ isChromeExtension: false,
93
+ isClient: import_constants.isClient,
94
+ isDesktop: false,
95
+ isExpo: false,
96
+ isFirefox: false,
97
+ isFirefoxExtension: false,
98
+ isGnome: false,
99
+ isIframe: false,
100
+ isIos: false,
101
+ isNative: false,
102
+ isNext: false,
103
+ isServer: import_constants.isServer,
104
+ isStorybook: import_constants.isWindowDefined && typeof window.__STORYBOOK_ADDONS_PREVIEW === "object",
105
+ isTauri: false,
106
+ isTouchable: import_constants.isTouchable,
107
+ isWeb: import_constants.isWeb,
108
+ isWebExtension: false,
109
+ isWebTouchable: import_constants.isWebTouchable,
110
+ isWindowDefined: import_constants.isWindowDefined,
111
+ preciseName: "unknown",
112
+ broadName: "unknown"
113
+ };
114
+ function getPreciseName(platform2) {
115
+ const flags = platform2;
116
+ for (const name of platformOrder) {
117
+ if (flags[`is${name}`]) {
118
+ return `${name[0].toLowerCase()}${name.slice(1)}`;
119
+ }
120
+ }
121
+ return "unknown";
122
+ }
123
+ function getBroadName(platform2) {
124
+ const flags = platform2;
125
+ for (const name of platformOrder.slice().reverse()) {
126
+ if (flags[`is${name}`]) {
127
+ return `${name[0].toLowerCase()}${name.slice(1)}`;
128
+ }
129
+ }
130
+ return "unknown";
131
+ }
132
+
133
+ // ../platform/src/platform/index.ts
134
+ var isIframe = (() => {
135
+ if (!platformBase.isWindowDefined) return false;
136
+ try {
137
+ return window.self !== window.top;
138
+ } catch {
139
+ return true;
140
+ }
141
+ })();
142
+ var isWebExtension = !!(typeof chrome !== "undefined" && !!chrome?.runtime?.id || typeof browser !== "undefined" && !!browser?.runtime?.id);
143
+ var platform = {
144
+ ...platformBase,
145
+ isChromeExtension: typeof chrome !== "undefined" && !!chrome?.runtime?.id,
146
+ isFirefoxExtension: typeof browser !== "undefined" && !!browser?.runtime?.id,
147
+ isIframe,
148
+ isWebExtension,
149
+ isBrowser: !!(platformBase.isWeb && platformBase.isWindowDefined && !isWebExtension),
150
+ isNext: platformBase.isWeb && (!platformBase.isWindowDefined || typeof window.__NEXT_DATA__ === "object"),
151
+ isFirefox: platformBase.isWindowDefined && !!(window?.navigator?.userAgent?.toLowerCase().indexOf("firefox") > -1)
152
+ };
153
+ platform.preciseName = getPreciseName(platform);
154
+ platform.broadName = getBroadName(platform);
155
+
156
+ // ../platform/src/index.ts
157
+ var {
158
+ isAndroid,
159
+ isBrowser,
160
+ isChrome: isChrome2,
161
+ isChromeExtension,
162
+ isClient: isClient2,
163
+ isExpo,
164
+ isFirefox,
165
+ isFirefoxExtension,
166
+ isGnome,
167
+ isIframe: isIframe2,
168
+ isIos,
169
+ isNative,
170
+ isNext,
171
+ isServer: isServer2,
172
+ isStorybook,
173
+ isTauri,
174
+ isDesktop,
175
+ isTouchable: isTouchable2,
176
+ isWeb: isWeb2,
177
+ isWebExtension: isWebExtension2,
178
+ isWebTouchable: isWebTouchable2,
179
+ isWindowDefined: isWindowDefined2
180
+ } = platform;
181
+
61
182
  // src/Authenticated.tsx
62
- var import_platform3 = require("@multiplatform.one/platform");
63
183
  var import_react7 = require("react");
64
184
  var import_react_native = require("react-native");
65
185
 
@@ -79,16 +199,155 @@ function useAuthConfig() {
79
199
  // src/hooks/useTokensFromQuery/index.native.ts
80
200
  var useTokensFromQuery = () => false;
81
201
 
202
+ // ../store/src/createStore.ts
203
+ var import_store2 = require("@tanstack/store");
204
+
205
+ // ../store/src/persist.ts
206
+ var import_store = require("@tanstack/store");
207
+ function createPersistStore(initialState, persistOptions) {
208
+ const { key, storage: storage2, serialize = JSON.stringify, deserialize = JSON.parse } = persistOptions;
209
+ let hydrated = false;
210
+ const store = new import_store.Store(initialState);
211
+ store.subscribe(() => {
212
+ if (hydrated) {
213
+ const serialized = serialize(store.state);
214
+ void Promise.resolve(storage2.setItem(key, serialized));
215
+ }
216
+ });
217
+ const rehydrate = async () => {
218
+ const raw = await Promise.resolve(storage2.getItem(key));
219
+ if (raw !== null) {
220
+ const deserialized = deserialize(raw);
221
+ store.setState(() => deserialized);
222
+ }
223
+ hydrated = true;
224
+ };
225
+ const clearPersistedState = async () => {
226
+ await Promise.resolve(storage2.removeItem(key));
227
+ };
228
+ void rehydrate();
229
+ const persistStore = store;
230
+ persistStore.rehydrate = rehydrate;
231
+ persistStore.clearPersistedState = clearPersistedState;
232
+ return persistStore;
233
+ }
234
+
235
+ // ../store/src/storage/index.native.ts
236
+ var defaultLoaders = {
237
+ // Literal require(...) calls on purpose: metro resolves them natively and
238
+ // vxrn/rolldown rewrites literal requires into bundled module inits (a
239
+ // passed-around `require` reference would survive as a bare identifier and
240
+ // crash). Lazy so a genuinely missing native module throws HERE — inside
241
+ // the try/catch — instead of at bundle evaluation.
242
+ loadMMKV: () => require("react-native-mmkv"),
243
+ loadAsyncStorage: () => require("@react-native-async-storage/async-storage")
244
+ };
245
+ function resolveNativeStorage(loaders = defaultLoaders) {
246
+ const errors = {};
247
+ try {
248
+ const mmkvModule = loaders.loadMMKV();
249
+ if (typeof mmkvModule?.createMMKV !== "function") {
250
+ throw new Error("no createMMKV() export (react-native-mmkv v4 API expected)");
251
+ }
252
+ const mmkv = mmkvModule.createMMKV();
253
+ return {
254
+ backend: "mmkv",
255
+ errors,
256
+ storage: {
257
+ getItem: (name) => mmkv.getString(name) ?? null,
258
+ setItem: (name, value) => {
259
+ mmkv.set(name, value);
260
+ },
261
+ removeItem: (name) => {
262
+ mmkv.remove(name);
263
+ }
264
+ }
265
+ };
266
+ } catch (err) {
267
+ errors.mmkv = err;
268
+ }
269
+ try {
270
+ const asyncStorageModule = loaders.loadAsyncStorage();
271
+ const asyncStorage = asyncStorageModule?.default;
272
+ if (!asyncStorage || typeof asyncStorage.getItem !== "function") {
273
+ throw new Error("no usable default export on @react-native-async-storage/async-storage");
274
+ }
275
+ return {
276
+ backend: "async-storage",
277
+ errors,
278
+ storage: {
279
+ getItem: (name) => asyncStorage.getItem(name),
280
+ setItem: (name, value) => asyncStorage.setItem(name, value),
281
+ removeItem: (name) => asyncStorage.removeItem(name)
282
+ }
283
+ };
284
+ } catch (err) {
285
+ errors.asyncStorage = err;
286
+ }
287
+ const map = /* @__PURE__ */ new Map();
288
+ return {
289
+ backend: "memory",
290
+ errors,
291
+ storage: {
292
+ getItem: (name) => map.get(name) ?? null,
293
+ setItem: (name, value) => {
294
+ map.set(name, value);
295
+ },
296
+ removeItem: (name) => {
297
+ map.delete(name);
298
+ }
299
+ }
300
+ };
301
+ }
302
+ function describeError(err) {
303
+ return err instanceof Error ? err.message : String(err);
304
+ }
305
+ function logNativeStorageResolution(resolution2, logger2 = console) {
306
+ if (resolution2.backend === "mmkv") {
307
+ logger2.info("[@multiplatform.one/store] native storage backend: mmkv");
308
+ return;
309
+ }
310
+ const causes = [`react-native-mmkv unavailable: ${describeError(resolution2.errors.mmkv)}`];
311
+ if (resolution2.backend === "memory") {
312
+ causes.push(`async-storage unavailable: ${describeError(resolution2.errors.asyncStorage)}`);
313
+ }
314
+ logger2.warn(
315
+ `[@multiplatform.one/store] native storage fell back to ${resolution2.backend}` + (resolution2.backend === "memory" ? " \u2014 persisted state will NOT survive app restarts" : "") + ` (${causes.join("; ")})`
316
+ );
317
+ }
318
+ var resolution = resolveNativeStorage();
319
+ if (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test") {
320
+ logNativeStorageResolution(resolution);
321
+ }
322
+ var storage = resolution.storage;
323
+
324
+ // ../store/src/createStore.ts
325
+ function createStore(initialState, options) {
326
+ if (options?.persist) {
327
+ return createPersistStore(initialState, {
328
+ key: options.name,
329
+ storage: options.storage ?? storage
330
+ });
331
+ }
332
+ return new import_store2.Store(initialState);
333
+ }
334
+
335
+ // ../store/src/index.ts
336
+ var import_store3 = require("@tanstack/store");
337
+ var import_react_store = require("@tanstack/react-store");
338
+ var import_react_store2 = require("@tanstack/react-store");
339
+ function useStore2(store, selector) {
340
+ return (0, import_react_store2.useStore)(store, selector ?? ((s) => s));
341
+ }
342
+
82
343
  // src/state.ts
83
- var import_store = require("@multiplatform.one/store");
84
- var import_platform = require("@multiplatform.one/platform");
85
- var persist = import_platform.isIframe || !import_platform.isBrowser && !import_platform.isServer;
86
- var authStore = (0, import_store.createStore)(
344
+ var persist = isIframe2 || !isBrowser && !isServer2;
345
+ var authStore = createStore(
87
346
  { idToken: "", refreshToken: "", token: "" },
88
347
  { name: "auth", persist }
89
348
  );
90
349
  function useAuthStore() {
91
- const state2 = (0, import_store.useStore)(authStore);
350
+ const state2 = useStore2(authStore);
92
351
  return {
93
352
  ...state2,
94
353
  setIdToken: (idToken) => authStore.setState((prev) => ({ ...prev, idToken })),
@@ -151,7 +410,6 @@ function useTokensFromStore() {
151
410
  }
152
411
 
153
412
  // src/keycloak/index.native.ts
154
- var import_platform2 = require("@multiplatform.one/platform");
155
413
  var import_react6 = require("react");
156
414
 
157
415
  // src/keycloak/base.ts
@@ -301,7 +559,7 @@ function useKeycloak() {
301
559
  const { disabled } = useAuthConfig();
302
560
  if (disabled) return null;
303
561
  if (keycloak) return keycloak;
304
- if (import_platform2.isStorybook) {
562
+ if (isStorybook) {
305
563
  return new Keycloak(keycloakConfig, {
306
564
  email: "storybook@example.com",
307
565
  username: "storybook"
@@ -321,7 +579,7 @@ function Authenticated({
321
579
  const keycloak = useKeycloak();
322
580
  const tokensFromQuery = useTokensFromQuery();
323
581
  (0, import_react7.useEffect)(() => {
324
- if (!keycloak || !authConfig.iframeSso && import_platform3.isIframe || import_platform3.isServer || keycloak.authenticated || tokensFromQuery) {
582
+ if (!keycloak || !authConfig.iframeSso && isIframe2 || isServer2 || keycloak.authenticated || tokensFromQuery) {
325
583
  return;
326
584
  }
327
585
  keycloak?.login({
@@ -342,8 +600,86 @@ function withAuthenticated(Component, options = {}) {
342
600
  return (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Authenticated, { ...options, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props }) });
343
601
  }
344
602
 
603
+ // ../logger/src/base.ts
604
+ var import_loglevel = __toESM(require("loglevel"));
605
+ var defaultLoggerConfig = {
606
+ name: "default",
607
+ type: "pretty",
608
+ level: process.env.NODE_ENV === "development" ? 1 /* Debug */ : 2 /* Info */
609
+ };
610
+ var BaseLogger = class {
611
+ constructor(config = {}) {
612
+ const { metadata, name, level } = typeof config === "string" ? { metadata: void 0, name: config, level: void 0 } : config;
613
+ this.metadata = metadata || {};
614
+ this.name = name || "default";
615
+ this.logger = name ? import_loglevel.default.getLogger(name) : import_loglevel.default;
616
+ if (level !== void 0) this.logger.setLevel(level);
617
+ this.transport = this.createTransport?.();
618
+ }
619
+ trace(...args) {
620
+ this.logger.trace(...args);
621
+ this.sendToTransport(0 /* Trace */, args);
622
+ }
623
+ debug(...args) {
624
+ this.logger.debug(...args);
625
+ this.sendToTransport(1 /* Debug */, args);
626
+ }
627
+ info(...args) {
628
+ this.logger.info(...args);
629
+ this.sendToTransport(2 /* Info */, args);
630
+ }
631
+ warn(...args) {
632
+ this.logger.warn(...args);
633
+ this.sendToTransport(3 /* Warn */, args);
634
+ }
635
+ error(...args) {
636
+ this.logger.error(...args);
637
+ this.sendToTransport(4 /* Error */, args);
638
+ }
639
+ log(...args) {
640
+ this.logger.debug(...args);
641
+ this.sendToTransport(1 /* Debug */, args);
642
+ }
643
+ sendToTransport(level, args) {
644
+ if (this.transport) {
645
+ this.transport.send({
646
+ level,
647
+ message: args[0],
648
+ args: args.slice(1),
649
+ platform: platform.preciseName,
650
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
651
+ });
652
+ }
653
+ }
654
+ getSubLogger(input) {
655
+ const subConfig = typeof input === "string" ? {
656
+ name: input,
657
+ metadata: this.metadata,
658
+ level: this.logger.getLevel()
659
+ } : {
660
+ ...input,
661
+ metadata: { ...this.metadata, ...input.metadata }
662
+ };
663
+ return new this.constructor(subConfig);
664
+ }
665
+ };
666
+
667
+ // ../logger/src/index.ts
668
+ var Logger = class extends BaseLogger {
669
+ constructor(config = {}) {
670
+ const metadata = {
671
+ platform: platform.preciseName
672
+ };
673
+ super({
674
+ name: metadata.platform,
675
+ ...typeof config === "string" ? { name: config } : config,
676
+ metadata
677
+ });
678
+ }
679
+ };
680
+ var logger = new Logger();
681
+
345
682
  // src/provider/AfterAuth.tsx
346
- var import_logger = require("@multiplatform.one/logger");
347
683
  var import_react8 = require("react");
348
684
 
349
685
  // src/frappeToken.native.ts
@@ -354,6 +690,35 @@ var import_react_native2 = require("react-native");
354
690
  var Linking = __toESM(require("expo-linking"));
355
691
  var SecureStore = __toESM(require("expo-secure-store"));
356
692
  var WebBrowser = __toESM(require("expo-web-browser"));
693
+
694
+ // src/betterAuth/accountSelection.ts
695
+ var validationErrorCode = "VALIDATION_ERROR";
696
+ var known;
697
+ function currentSelection(userId) {
698
+ return userId ? { useAccountCookie: true, userId } : { useAccountCookie: true };
699
+ }
700
+ function legacySelection(providerId, userId) {
701
+ return userId ? { providerId, userId } : { providerId };
702
+ }
703
+ function isBodyRefusal(res) {
704
+ return res.status === 400 && res.body?.code === validationErrorCode;
705
+ }
706
+ async function requestAccessToken(providerId, send, userId) {
707
+ const current = () => currentSelection(userId);
708
+ const legacy = () => legacySelection(providerId, userId);
709
+ if (known === "legacy") return send(legacy());
710
+ if (known === "current") return send(current());
711
+ const first = await send(current());
712
+ if (!isBodyRefusal(first)) {
713
+ if (first.status !== 400) known = "current";
714
+ return first;
715
+ }
716
+ const second = await send(legacy());
717
+ if (!isBodyRefusal(second)) known = "legacy";
718
+ return second;
719
+ }
720
+
721
+ // src/betterAuth/expoAuthFlow.native.ts
357
722
  try {
358
723
  WebBrowser.maybeCompleteAuthSession?.();
359
724
  } catch {
@@ -567,12 +932,17 @@ function createExpoAuthFlow(baseURL, scheme) {
567
932
  return data && Object.keys(data).length ? data : null;
568
933
  },
569
934
  async getAccessToken(providerId) {
570
- const res = await authFetch("/get-access-token", {
571
- method: "POST",
572
- body: JSON.stringify({ providerId })
935
+ let payload = null;
936
+ const res = await requestAccessToken(providerId, async (body) => {
937
+ const response = await authFetch("/get-access-token", {
938
+ method: "POST",
939
+ body: JSON.stringify(body)
940
+ });
941
+ payload = await response.json().catch(() => null);
942
+ return { status: response.status, body: payload };
573
943
  });
574
- if (!res.ok) return null;
575
- return await res.json().catch(() => null);
944
+ if (res.status < 200 || res.status >= 300) return null;
945
+ return payload;
576
946
  }
577
947
  };
578
948
  activeFlow = flow;
@@ -657,27 +1027,27 @@ function AfterAuth({ children, loadingComponent: _loadingComponent }) {
657
1027
  ]);
658
1028
  (0, import_react8.useEffect)(() => {
659
1029
  if (authConfig.debug && keycloak?.token) {
660
- import_logger.logger.debug("token", keycloak.token);
1030
+ logger.debug("token", keycloak.token);
661
1031
  }
662
1032
  }, [authConfig.debug, keycloak?.token]);
663
1033
  (0, import_react8.useEffect)(() => {
664
1034
  if (authConfig.debug && keycloak?.idToken) {
665
- import_logger.logger.debug("idToken", keycloak.idToken);
1035
+ logger.debug("idToken", keycloak.idToken);
666
1036
  }
667
1037
  }, [authConfig.debug, keycloak?.idToken]);
668
1038
  (0, import_react8.useEffect)(() => {
669
1039
  if (authConfig.debug && keycloak?.refreshToken) {
670
- import_logger.logger.debug("refreshToken", keycloak.refreshToken);
1040
+ logger.debug("refreshToken", keycloak.refreshToken);
671
1041
  }
672
1042
  }, [authConfig.debug, keycloak?.refreshToken]);
673
1043
  (0, import_react8.useEffect)(() => {
674
1044
  if (authConfig.debug && keycloak?.authenticated) {
675
- import_logger.logger.debug("authenticated", keycloak.authenticated);
1045
+ logger.debug("authenticated", keycloak.authenticated);
676
1046
  }
677
1047
  }, [authConfig.debug, keycloak?.authenticated]);
678
1048
  (0, import_react8.useEffect)(() => {
679
1049
  if (authConfig.debug && keycloak === null) {
680
- import_logger.logger.debug("keycloak disabled");
1050
+ logger.debug("keycloak disabled");
681
1051
  }
682
1052
  }, [authConfig.debug, keycloak]);
683
1053
  (0, import_react8.useEffect)(() => watchKeycloakBearerTokenRevalidate(), []);