@rixl/sdk 0.8.2 → 0.8.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 +156 -38
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -625,6 +625,117 @@ const createClient = (config = {}) => {
|
|
|
625
625
|
//#region src/generated/client.gen.ts
|
|
626
626
|
const client = createClient(createConfig({ baseUrl: "https://raw.githubusercontent.com" }));
|
|
627
627
|
|
|
628
|
+
//#endregion
|
|
629
|
+
//#region src/shared-runtime.ts
|
|
630
|
+
/**
|
|
631
|
+
* Cross-instance runtime state for the SDK.
|
|
632
|
+
*
|
|
633
|
+
* Every store and client in this package is module-level singleton state that
|
|
634
|
+
* `connect()` mutates. That only works while exactly one copy of `@rixl/sdk`
|
|
635
|
+
* is evaluated. Bundlers routinely break that assumption: Vite's dependency
|
|
636
|
+
* pre-bundling, for example, inlines a private copy of the SDK into any
|
|
637
|
+
* optimized dependency that imports it, so a consumer's `connect()` configures
|
|
638
|
+
* one copy while a library's requests read another — with a wrong baseUrl and,
|
|
639
|
+
* worse, no auth tokens.
|
|
640
|
+
*
|
|
641
|
+
* Anchoring the state to a `Symbol.for` key on `globalThis` makes every copy
|
|
642
|
+
* resolve the same objects, so duplication becomes harmless instead of a
|
|
643
|
+
* silent, hard-to-trace failure.
|
|
644
|
+
*/
|
|
645
|
+
const REGISTRY_KEY = Symbol.for("@rixl/sdk.runtime");
|
|
646
|
+
/** Bumped only if the shape below changes incompatibly. */
|
|
647
|
+
const STATE_VERSION = 1;
|
|
648
|
+
function registry() {
|
|
649
|
+
const host = globalThis;
|
|
650
|
+
const existing = host[REGISTRY_KEY];
|
|
651
|
+
if (existing && existing.version === STATE_VERSION) return existing;
|
|
652
|
+
const created = {
|
|
653
|
+
version: STATE_VERSION,
|
|
654
|
+
copies: 0,
|
|
655
|
+
values: /* @__PURE__ */ new Map()
|
|
656
|
+
};
|
|
657
|
+
host[REGISTRY_KEY] = created;
|
|
658
|
+
return created;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Returns the one shared value for `name`, creating it on first use.
|
|
662
|
+
*
|
|
663
|
+
* `create` runs at most once per realm no matter how many copies of the SDK are
|
|
664
|
+
* loaded, so callers get object identity (a nanostore atom, a Set) rather than
|
|
665
|
+
* a per-copy clone.
|
|
666
|
+
*/
|
|
667
|
+
function shared(name, create) {
|
|
668
|
+
const { values } = registry();
|
|
669
|
+
if (!values.has(name)) values.set(name, create());
|
|
670
|
+
return values.get(name);
|
|
671
|
+
}
|
|
672
|
+
const copies = registry().copies += 1;
|
|
673
|
+
if (copies > 1) console.warn(`[@rixl/sdk] ${copies} copies of this package were loaded in one page. Shared state is deduplicated, so this is not fatal, but it doubles bundle size and usually means a bundler inlined a private copy — with Vite, add "@rixl/sdk" to optimizeDeps.include and resolve.dedupe. Ensure libraries depending on @rixl/sdk declare it as a peerDependency.`);
|
|
674
|
+
|
|
675
|
+
//#endregion
|
|
676
|
+
//#region src/client-registry.ts
|
|
677
|
+
/**
|
|
678
|
+
* The baseUrl the code generator bakes in. It is derived from the origin of the
|
|
679
|
+
* OpenAPI input URL, not from a real server, so a client still holding it has
|
|
680
|
+
* simply never been configured. Captured from the client itself rather than
|
|
681
|
+
* hardcoded so it stays correct if the generator input ever moves.
|
|
682
|
+
*/
|
|
683
|
+
const placeholderBaseUrl = shared("placeholderBaseUrl", () => client.getConfig().baseUrl);
|
|
684
|
+
const clients = shared("clients", () => /* @__PURE__ */ new Set());
|
|
685
|
+
/** Setup applied to every client copy, including ones registered later. */
|
|
686
|
+
const initializers = shared("clientInitializers", () => []);
|
|
687
|
+
/** Last baseUrl passed to {@link configureAllClients}, replayed onto late joiners. */
|
|
688
|
+
const appliedConfig = shared("appliedConfig", () => ({ baseUrl: void 0 }));
|
|
689
|
+
function isUnconfigured(target) {
|
|
690
|
+
const { baseUrl } = target.getConfig();
|
|
691
|
+
return !baseUrl || baseUrl === placeholderBaseUrl;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Fails a request that would otherwise be sent to the generator's placeholder
|
|
695
|
+
* host. Without this the request goes out looking legitimate and comes back a
|
|
696
|
+
* 404 from an unrelated origin, which reads like a backend fault instead of
|
|
697
|
+
* "the SDK was never initialised".
|
|
698
|
+
*/
|
|
699
|
+
function installUnconfiguredGuard(target) {
|
|
700
|
+
target.interceptors.request.use((request) => {
|
|
701
|
+
if (isUnconfigured(target)) throw new Error(`[@rixl/sdk] Cannot send ${request.method} ${new URL(request.url).pathname}: no baseUrl is configured. Call connect({baseUrl}) before issuing requests.`);
|
|
702
|
+
return request;
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Registers setup to run against every client copy — those already known and
|
|
707
|
+
* any that register afterwards. Interceptors added through here therefore reach
|
|
708
|
+
* a copy that loads from a lazy chunk after `connect()` has already run.
|
|
709
|
+
*/
|
|
710
|
+
function addClientInitializer(initialize) {
|
|
711
|
+
initializers.push(initialize);
|
|
712
|
+
for (const target of clients) initialize(target);
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Adds a client to the shared registry so configuration reaches it. Registering
|
|
716
|
+
* is idempotent, and a client that joins late is brought fully up to date.
|
|
717
|
+
*/
|
|
718
|
+
function registerClient(target) {
|
|
719
|
+
if (clients.has(target)) return;
|
|
720
|
+
clients.add(target);
|
|
721
|
+
installUnconfiguredGuard(target);
|
|
722
|
+
for (const initialize of initializers) initialize(target);
|
|
723
|
+
if (appliedConfig.baseUrl !== void 0) target.setConfig({ baseUrl: appliedConfig.baseUrl });
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Points every known client copy at `baseUrl`.
|
|
727
|
+
*
|
|
728
|
+
* Duplicate copies of this package each construct their own client object, and
|
|
729
|
+
* the generated request functions close over whichever one their copy owns.
|
|
730
|
+
* Configuring only the caller's copy is what leaves a bundled library issuing
|
|
731
|
+
* requests to the placeholder host.
|
|
732
|
+
*/
|
|
733
|
+
function configureAllClients(baseUrl) {
|
|
734
|
+
appliedConfig.baseUrl = baseUrl;
|
|
735
|
+
for (const target of clients) target.setConfig({ baseUrl });
|
|
736
|
+
}
|
|
737
|
+
registerClient(client);
|
|
738
|
+
|
|
628
739
|
//#endregion
|
|
629
740
|
//#region src/generated/sdk.gen.ts
|
|
630
741
|
/**
|
|
@@ -2472,11 +2583,14 @@ const parseUser = () => {
|
|
|
2472
2583
|
return;
|
|
2473
2584
|
}
|
|
2474
2585
|
};
|
|
2475
|
-
const user =
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2586
|
+
const user = shared("user", () => {
|
|
2587
|
+
const store = atom(parseUser());
|
|
2588
|
+
store.subscribe((value) => {
|
|
2589
|
+
if (typeof localStorage === "undefined" || !localStorage || typeof localStorage.setItem !== "function") return;
|
|
2590
|
+
if (value) localStorage.setItem(userPath, JSON.stringify(value));
|
|
2591
|
+
else localStorage.removeItem(userPath);
|
|
2592
|
+
});
|
|
2593
|
+
return store;
|
|
2480
2594
|
});
|
|
2481
2595
|
|
|
2482
2596
|
//#endregion
|
|
@@ -2530,13 +2644,13 @@ const isTokenExpired = (expireAt) => {
|
|
|
2530
2644
|
|
|
2531
2645
|
//#endregion
|
|
2532
2646
|
//#region src/auth/authStore.ts
|
|
2533
|
-
const isLogged = atom(initVals["isLogged"] === "true" || detectProvider() !== void 0);
|
|
2534
|
-
const accessToken = atom(initVals["accessToken"]);
|
|
2535
|
-
const refreshToken = atom(initVals["refreshToken"]);
|
|
2536
|
-
const expireAt = atom(Number(initVals["expireAt"]));
|
|
2537
|
-
const authError = atom(null);
|
|
2538
|
-
const requiresAction = atom(initVals["requiresAction"] || null);
|
|
2539
|
-
const limitedAccessToken = atom(initVals["limitedAccessToken"] || null);
|
|
2647
|
+
const isLogged = shared("isLogged", () => atom(initVals["isLogged"] === "true" || detectProvider() !== void 0));
|
|
2648
|
+
const accessToken = shared("accessToken", () => atom(initVals["accessToken"]));
|
|
2649
|
+
const refreshToken = shared("refreshToken", () => atom(initVals["refreshToken"]));
|
|
2650
|
+
const expireAt = shared("expireAt", () => atom(Number(initVals["expireAt"])));
|
|
2651
|
+
const authError = shared("authError", () => atom(null));
|
|
2652
|
+
const requiresAction = shared("requiresAction", () => atom(initVals["requiresAction"] || null));
|
|
2653
|
+
const limitedAccessToken = shared("limitedAccessToken", () => atom(initVals["limitedAccessToken"] || null));
|
|
2540
2654
|
let currentTokenPromise = null;
|
|
2541
2655
|
const PROVIDER_URL_MAP = {
|
|
2542
2656
|
google: googleAuthUrl,
|
|
@@ -2678,17 +2792,19 @@ var ApiError = class extends Error {
|
|
|
2678
2792
|
/**
|
|
2679
2793
|
* Global API base URL store
|
|
2680
2794
|
*/
|
|
2681
|
-
const apiURL = atom("");
|
|
2795
|
+
const apiURL = shared("apiURL", () => atom(""));
|
|
2682
2796
|
|
|
2683
2797
|
//#endregion
|
|
2684
2798
|
//#region src/auth/api/sdk-client.ts
|
|
2685
2799
|
function isWireErrorBody(error) {
|
|
2686
2800
|
return typeof error === "object" && error !== null;
|
|
2687
2801
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
2802
|
+
const state = shared("sdkClientState", () => ({
|
|
2803
|
+
configured: false,
|
|
2804
|
+
tokenResolver: getToken
|
|
2805
|
+
}));
|
|
2690
2806
|
function setTokenResolver(resolver) {
|
|
2691
|
-
tokenResolver = resolver;
|
|
2807
|
+
state.tokenResolver = resolver;
|
|
2692
2808
|
}
|
|
2693
2809
|
/**
|
|
2694
2810
|
* Routes that do not require a Bearer token at the gateway edge. These
|
|
@@ -2800,26 +2916,28 @@ function isPublicRoute(method, pathname) {
|
|
|
2800
2916
|
return publicRoutes.some(({ method: m, path, prefix }) => match === m && (prefix ? pathname.startsWith(path) : pathname === path));
|
|
2801
2917
|
}
|
|
2802
2918
|
function configureSdkClient() {
|
|
2803
|
-
if (configured) return;
|
|
2804
|
-
configured = true;
|
|
2805
|
-
|
|
2919
|
+
if (state.configured) return;
|
|
2920
|
+
state.configured = true;
|
|
2921
|
+
configureAllClients(apiURL.get());
|
|
2806
2922
|
apiURL.subscribe((url) => {
|
|
2807
|
-
|
|
2923
|
+
configureAllClients(url);
|
|
2808
2924
|
});
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2925
|
+
addClientInitializer((client) => {
|
|
2926
|
+
client.interceptors.request.use(async (request) => {
|
|
2927
|
+
if (request.headers.has("Authorization")) return request;
|
|
2928
|
+
const { pathname } = new URL(request.url);
|
|
2929
|
+
if (isPublicRoute(request.method, pathname)) return request;
|
|
2930
|
+
const token = await state.tokenResolver();
|
|
2931
|
+
if (!token) throw new ApiError("No access token available for an authenticated request", HTTP_STATUS.UNAUTHORIZED, pathname);
|
|
2932
|
+
request.headers.set("Authorization", `Bearer ${token}`);
|
|
2933
|
+
return request;
|
|
2934
|
+
});
|
|
2935
|
+
client.interceptors.error.use((error, response, request) => {
|
|
2936
|
+
if (error instanceof Error) return error;
|
|
2937
|
+
const body = isWireErrorBody(error) ? error : void 0;
|
|
2938
|
+
const status = response?.status ?? body?.code ?? 0;
|
|
2939
|
+
return new ApiError(body?.error || body?.details || (typeof error === "string" ? error : "Request failed"), status, request ? new URL(request.url).pathname : "", error);
|
|
2940
|
+
});
|
|
2823
2941
|
});
|
|
2824
2942
|
}
|
|
2825
2943
|
|
|
@@ -3180,9 +3298,9 @@ const initSocials = async () => {
|
|
|
3180
3298
|
|
|
3181
3299
|
//#endregion
|
|
3182
3300
|
//#region src/platform/platformAuthStore.ts
|
|
3183
|
-
const platformAccessToken = atom(void 0);
|
|
3184
|
-
const platformRefreshToken = atom(void 0);
|
|
3185
|
-
const platformExpireAt = atom(0);
|
|
3301
|
+
const platformAccessToken = shared("platformAccessToken", () => atom(void 0));
|
|
3302
|
+
const platformRefreshToken = shared("platformRefreshToken", () => atom(void 0));
|
|
3303
|
+
const platformExpireAt = shared("platformExpireAt", () => atom(0));
|
|
3186
3304
|
let currentPlatformTokenPromise = null;
|
|
3187
3305
|
const setPlatformTokens = (access, refresh, expiresIn) => {
|
|
3188
3306
|
platformAccessToken.set(access);
|
|
@@ -3239,7 +3357,7 @@ const getPlatformToken = async () => {
|
|
|
3239
3357
|
//#region src/connect.ts
|
|
3240
3358
|
const connect = async (config) => {
|
|
3241
3359
|
apiURL.set(config.baseUrl);
|
|
3242
|
-
|
|
3360
|
+
configureAllClients(config.baseUrl);
|
|
3243
3361
|
if (config.apiKey) {
|
|
3244
3362
|
await exchangeApiKey(config.apiKey);
|
|
3245
3363
|
setTokenResolver(getPlatformToken);
|