@epcc-sdk/sdks-shopper 0.0.36 → 0.0.38

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.
Files changed (44) hide show
  1. package/README.md +79 -0
  2. package/dist/auth/configure-client.cjs +94 -0
  3. package/dist/auth/configure-client.cjs.map +1 -0
  4. package/dist/auth/configure-client.d.cts +59 -0
  5. package/dist/auth/configure-client.d.ts +59 -0
  6. package/dist/auth/configure-client.mjs +74 -0
  7. package/dist/auth/configure-client.mjs.map +1 -0
  8. package/dist/auth/kit.cjs +97 -0
  9. package/dist/auth/kit.cjs.map +1 -0
  10. package/dist/auth/kit.d.cts +15 -0
  11. package/dist/auth/kit.d.ts +15 -0
  12. package/dist/auth/kit.mjs +73 -0
  13. package/dist/auth/kit.mjs.map +1 -0
  14. package/dist/auth/make-auth-fetch.cjs +53 -0
  15. package/dist/auth/make-auth-fetch.cjs.map +1 -0
  16. package/dist/auth/make-auth-fetch.d.cts +16 -0
  17. package/dist/auth/make-auth-fetch.d.ts +16 -0
  18. package/dist/auth/make-auth-fetch.mjs +29 -0
  19. package/dist/auth/make-auth-fetch.mjs.map +1 -0
  20. package/dist/auth/storage.cjs +118 -0
  21. package/dist/auth/storage.cjs.map +1 -0
  22. package/dist/auth/storage.d.cts +23 -0
  23. package/dist/auth/storage.d.ts +23 -0
  24. package/dist/auth/storage.mjs +92 -0
  25. package/dist/auth/storage.mjs.map +1 -0
  26. package/dist/auth/token-providers.cjs +82 -0
  27. package/dist/auth/token-providers.cjs.map +1 -0
  28. package/dist/auth/token-providers.d.cts +28 -0
  29. package/dist/auth/token-providers.d.ts +28 -0
  30. package/dist/auth/token-providers.mjs +57 -0
  31. package/dist/auth/token-providers.mjs.map +1 -0
  32. package/dist/index.cjs +5 -0
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +3 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.mjs +3 -0
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/test/utils.cjs +38 -0
  39. package/dist/test/utils.cjs.map +1 -0
  40. package/dist/test/utils.d.cts +10 -0
  41. package/dist/test/utils.d.ts +10 -0
  42. package/dist/test/utils.mjs +13 -0
  43. package/dist/test/utils.mjs.map +1 -0
  44. package/package.json +1 -1
package/README.md CHANGED
@@ -3,6 +3,85 @@
3
3
  Below you'll find instructions on how to install, set up, and use the client, along with a list of available operations.
4
4
 
5
5
 
6
+ ## Authentication (Browser)
7
+
8
+ The SDK includes built-in authentication support for browser environments using Elastic Path's implicit authentication flow. It handles token management, automatic refresh, and storage.
9
+
10
+ ### Quick Start
11
+
12
+ > **Note**: This authentication mechanism is designed for browser environments where state persistence (localStorage, cookies) is available. The built-in storage adapters and cross-tab synchronization features require browser APIs.
13
+
14
+ ```typescript
15
+ import { configureClient } from "@epcc-sdk/sdks-shopper/auth/configure-client";
16
+
17
+ // Configure the singleton client with authentication
18
+ configureClient(
19
+ {
20
+ baseUrl: "https://useast.api.elasticpath.com"
21
+ },
22
+ {
23
+ clientId: "your-client-id",
24
+ storage: "localStorage" // or "cookie" or custom adapter
25
+ }
26
+ );
27
+ ```
28
+
29
+ ### Storage Options
30
+
31
+ - **localStorage** (default): Tokens stored in browser localStorage with cross-tab synchronization
32
+ - **cookie**: Tokens stored in JavaScript-readable cookies
33
+ - **Custom adapter**: Implement your own storage mechanism
34
+
35
+ ```typescript
36
+ // Cookie storage with options
37
+ configureClient(config, {
38
+ clientId: "your-client-id",
39
+ storage: "cookie",
40
+ cookie: {
41
+ sameSite: "Strict",
42
+ secure: true,
43
+ maxAge: 3600 // 1 hour
44
+ }
45
+ });
46
+ ```
47
+
48
+ ### Creating Standalone Clients
49
+
50
+ For multiple stores or isolated instances:
51
+
52
+ ```typescript
53
+ import { createShopperClient } from "@epcc-sdk/sdks-shopper/auth/configure-client";
54
+
55
+ const { client, auth } = createShopperClient(
56
+ { baseUrl: "https://useast.api.elasticpath.com" },
57
+ { clientId: "your-client-id" }
58
+ );
59
+ ```
60
+
61
+ ### Manual Auth Control
62
+
63
+ Access the underlying auth instance for manual control:
64
+
65
+ ```typescript
66
+ const { client, auth } = configureClient(config, authOptions);
67
+
68
+ // Check authentication status
69
+ if (auth.isAuthenticated()) {
70
+ console.log("Authenticated!");
71
+ }
72
+
73
+ // Manually clear tokens
74
+ auth.clearToken();
75
+ ```
76
+
77
+ ### Features
78
+
79
+ - **Automatic token refresh**: Refreshes expired tokens automatically
80
+ - **Request retry**: Retries failed requests once after refreshing token
81
+ - **Cross-tab sync**: localStorage adapter syncs auth state across browser tabs
82
+ - **Type-safe**: Full TypeScript support with proper types
83
+ - **Flexible storage**: Built-in adapters or bring your own
84
+
6
85
  ## React Query Support
7
86
 
8
87
  This SDK provides optional React Query hooks for React applications. To use them, you need to:
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var configure_client_exports = {};
20
+ __export(configure_client_exports, {
21
+ configureClient: () => configureClient,
22
+ createShopperClient: () => createShopperClient
23
+ });
24
+ module.exports = __toCommonJS(configure_client_exports);
25
+ var import_sdk = require('../client/sdk.gen.cjs');
26
+ var import_client_fetch = require("@hey-api/client-fetch");
27
+ var import_kit = require('./kit.cjs');
28
+ var import_storage = require('./storage.cjs');
29
+ var import_make_auth_fetch = require('./make-auth-fetch.cjs');
30
+ var import_token_providers = require('./token-providers.cjs');
31
+ function resolveStorage(storage, cookie) {
32
+ return storage === "cookie" ? (0, import_storage.cookieAdapter)({ sameSite: "Lax", ...cookie }) : storage === "localStorage" || !storage ? (0, import_storage.localStorageAdapter)() : storage;
33
+ }
34
+ function normalizeHeaders(headers) {
35
+ if (!headers) return void 0;
36
+ if (headers instanceof Headers || Array.isArray(headers)) return headers;
37
+ const out = {};
38
+ for (const [k, v] of Object.entries(headers)) out[k] = String(v);
39
+ return out;
40
+ }
41
+ function resolveFetch(auth, userFetch, wrapUserFetch) {
42
+ const authedStd = (0, import_make_auth_fetch.makeAuthFetch)(auth, userFetch, {
43
+ isAuthRequest: (u) => u.includes("/oauth/")
44
+ });
45
+ return wrapUserFetch !== false ? authedStd : userFetch;
46
+ }
47
+ function configureClient(config, authOpts) {
48
+ const { fetch: userFetch, headers, ...rest } = config;
49
+ const baseUrl = config.baseUrl;
50
+ const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie);
51
+ const headersNorm = normalizeHeaders(headers);
52
+ const provider = authOpts.tokenProvider ?? (0, import_token_providers.makeImplicitTokenProviderWithFreshSdk)({
53
+ baseUrl: String(baseUrl),
54
+ clientId: authOpts.clientId,
55
+ fetch: userFetch,
56
+ headers: headersNorm
57
+ });
58
+ const auth = (0, import_kit.createAuth)(storageImpl, provider);
59
+ const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch);
60
+ import_sdk.client.setConfig({
61
+ ...rest,
62
+ baseUrl,
63
+ headers: headersNorm,
64
+ fetch: finalFetch
65
+ });
66
+ return { client: import_sdk.client, auth };
67
+ }
68
+ function createShopperClient(config, authOpts) {
69
+ const { fetch: userFetch, headers, ...rest } = config;
70
+ const baseUrl = config.baseUrl;
71
+ const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie);
72
+ const headersNorm = normalizeHeaders(headers);
73
+ const provider = authOpts.tokenProvider ?? (0, import_token_providers.makeImplicitTokenProviderWithFreshSdk)({
74
+ baseUrl: String(baseUrl),
75
+ clientId: authOpts.clientId,
76
+ fetch: userFetch,
77
+ headers: headersNorm
78
+ });
79
+ const auth = (0, import_kit.createAuth)(storageImpl, provider);
80
+ const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch);
81
+ const instance = (0, import_client_fetch.createClient)({
82
+ ...rest,
83
+ baseUrl,
84
+ headers: headersNorm,
85
+ fetch: finalFetch
86
+ });
87
+ return { client: instance, auth };
88
+ }
89
+ // Annotate the CommonJS export names for ESM import in node:
90
+ 0 && (module.exports = {
91
+ configureClient,
92
+ createShopperClient
93
+ });
94
+ //# sourceMappingURL=configure-client.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/auth/configure-client.ts"],"sourcesContent":["import { client as singleton } from \"../client/sdk.gen\"\nimport {\n type Config,\n createClient as sdkCreateClient,\n} from \"@hey-api/client-fetch\"\nimport { createAuth, type TokenProvider } from \"./kit\"\nimport {\n localStorageAdapter,\n cookieAdapter,\n type StorageAdapter,\n} from \"./storage\"\nimport { makeAuthFetch } from \"./make-auth-fetch\"\nimport { makeImplicitTokenProviderWithFreshSdk } from \"./token-providers\"\n\ntype HeyApiConfig = Parameters<typeof singleton.setConfig>[0]\ntype HeyApiCreateConfig = Parameters<typeof sdkCreateClient>[0]\n\nexport type AuthOptions = {\n /**\n * Elastic Path key (Client ID) for your store. Required.\n */\n clientId: string\n /**\n * Optional: supply your own provider. If omitted, we call the SDK’s OAuth op via a fresh bare client.\n */\n tokenProvider?: TokenProvider\n /**\n * Where to store the access token. Defaults to localStorage; use \"cookie\" for JS-readable cookies.\n */\n storage?: \"localStorage\" | \"cookie\" | StorageAdapter\n /**\n * Cookie options when storage = \"cookie\".\n */\n cookie?: Omit<Parameters<typeof cookieAdapter>[0], \"name\">\n /**\n * Wrap the provided `fetch` with auth logic (attach Bearer + retry once on 401). Defaults to true.\n */\n wrapUserFetch?: boolean\n}\n\nfunction resolveStorage(\n storage: AuthOptions[\"storage\"],\n cookie?: AuthOptions[\"cookie\"],\n): StorageAdapter {\n return storage === \"cookie\"\n ? cookieAdapter({ sameSite: \"Lax\", ...cookie })\n : storage === \"localStorage\" || !storage\n ? localStorageAdapter()\n : storage\n}\n\nfunction normalizeHeaders(\n headers: HeadersInit | Record<string, unknown> | undefined,\n): HeadersInit | undefined {\n if (!headers) return undefined\n if (headers instanceof Headers || Array.isArray(headers)) return headers\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(headers)) out[k] = String(v)\n return out\n}\n\nfunction resolveFetch(\n auth: ReturnType<typeof createAuth>,\n userFetch: Config[\"fetch\"],\n wrapUserFetch: boolean | undefined,\n) {\n const authedStd = makeAuthFetch(auth, userFetch, {\n isAuthRequest: (u) => u.includes(\"/oauth/\"),\n })\n // If user opts out, still return a standard-shaped fetch\n return wrapUserFetch !== false ? authedStd : userFetch\n}\n\n/**\n * Configure the generated singleton client using the *exact* Hey API config,\n * plus separate Auth options.\n */\nexport function configureClient(config: HeyApiConfig, authOpts: AuthOptions) {\n const { fetch: userFetch, headers, ...rest } = config\n\n // Some codegens mark baseUrl optional in the type; we rely on what the caller passed.\n const baseUrl = (config as any).baseUrl as string\n\n const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie)\n const headersNorm = normalizeHeaders(headers)\n\n const provider: TokenProvider =\n authOpts.tokenProvider ??\n makeImplicitTokenProviderWithFreshSdk({\n baseUrl: String(baseUrl),\n clientId: authOpts.clientId,\n fetch: userFetch,\n headers: headersNorm,\n })\n\n const auth = createAuth(storageImpl, provider)\n const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch)\n\n singleton.setConfig({\n ...rest,\n baseUrl,\n headers: headersNorm,\n fetch: finalFetch,\n })\n\n return { client: singleton, auth }\n}\n\n/**\n * Create and return a brand-new client instance (does not mutate the singleton),\n * using the *exact* Hey API createClient config + separate Auth options.\n */\nexport function createShopperClient<T extends NonNullable<HeyApiCreateConfig>>(\n config: T,\n authOpts: AuthOptions,\n) {\n const { fetch: userFetch, headers, ...rest } = config\n const baseUrl = (config as any).baseUrl as string\n\n const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie)\n const headersNorm = normalizeHeaders(headers)\n\n const provider: TokenProvider =\n authOpts.tokenProvider ??\n makeImplicitTokenProviderWithFreshSdk({\n baseUrl: String(baseUrl),\n clientId: authOpts.clientId,\n fetch: userFetch as any,\n headers: headersNorm,\n })\n\n const auth = createAuth(storageImpl, provider)\n const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch)\n\n const instance = sdkCreateClient({\n ...rest,\n baseUrl,\n headers: headersNorm,\n fetch: finalFetch,\n })\n\n return { client: instance, auth }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoC;AACpC,0BAGO;AACP,iBAA+C;AAC/C,qBAIO;AACP,6BAA8B;AAC9B,6BAAsD;AA4BtD,SAAS,eACP,SACA,QACgB;AAChB,SAAO,YAAY,eACf,8BAAc,EAAE,UAAU,OAAO,GAAG,OAAO,CAAC,IAC5C,YAAY,kBAAkB,CAAC,cAC/B,oCAAoB,IACpB;AACN;AAEA,SAAS,iBACP,SACyB;AACzB,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,mBAAmB,WAAW,MAAM,QAAQ,OAAO,EAAG,QAAO;AACjE,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,OAAO,EAAG,KAAI,CAAC,IAAI,OAAO,CAAC;AAC/D,SAAO;AACT;AAEA,SAAS,aACP,MACA,WACA,eACA;AACA,QAAM,gBAAY,sCAAc,MAAM,WAAW;AAAA,IAC/C,eAAe,CAAC,MAAM,EAAE,SAAS,SAAS;AAAA,EAC5C,CAAC;AAED,SAAO,kBAAkB,QAAQ,YAAY;AAC/C;AAMO,SAAS,gBAAgB,QAAsB,UAAuB;AAC3E,QAAM,EAAE,OAAO,WAAW,SAAS,GAAG,KAAK,IAAI;AAG/C,QAAM,UAAW,OAAe;AAEhC,QAAM,cAAc,eAAe,SAAS,SAAS,SAAS,MAAM;AACpE,QAAM,cAAc,iBAAiB,OAAO;AAE5C,QAAM,WACJ,SAAS,qBACT,8DAAsC;AAAA,IACpC,SAAS,OAAO,OAAO;AAAA,IACvB,UAAU,SAAS;AAAA,IACnB,OAAO;AAAA,IACP,SAAS;AAAA,EACX,CAAC;AAEH,QAAM,WAAO,uBAAW,aAAa,QAAQ;AAC7C,QAAM,aAAa,aAAa,MAAM,WAAW,SAAS,aAAa;AAEvE,aAAAA,OAAU,UAAU;AAAA,IAClB,GAAG;AAAA,IACH;AAAA,IACA,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,QAAQ,WAAAA,QAAW,KAAK;AACnC;AAMO,SAAS,oBACd,QACA,UACA;AACA,QAAM,EAAE,OAAO,WAAW,SAAS,GAAG,KAAK,IAAI;AAC/C,QAAM,UAAW,OAAe;AAEhC,QAAM,cAAc,eAAe,SAAS,SAAS,SAAS,MAAM;AACpE,QAAM,cAAc,iBAAiB,OAAO;AAE5C,QAAM,WACJ,SAAS,qBACT,8DAAsC;AAAA,IACpC,SAAS,OAAO,OAAO;AAAA,IACvB,UAAU,SAAS;AAAA,IACnB,OAAO;AAAA,IACP,SAAS;AAAA,EACX,CAAC;AAEH,QAAM,WAAO,uBAAW,aAAa,QAAQ;AAC7C,QAAM,aAAa,aAAa,MAAM,WAAW,SAAS,aAAa;AAEvE,QAAM,eAAW,oBAAAC,cAAgB;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,IACA,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,QAAQ,UAAU,KAAK;AAClC;","names":["singleton","sdkCreateClient"]}
@@ -0,0 +1,59 @@
1
+ import * as _hey_api_client_fetch from '@hey-api/client-fetch';
2
+ import { createClient } from '@hey-api/client-fetch';
3
+ import { client } from '../client/sdk.gen.cjs';
4
+ import { TokenProvider } from './kit.cjs';
5
+ import { StorageAdapter, cookieAdapter } from './storage.cjs';
6
+ import '../client/types.gen.cjs';
7
+
8
+ type HeyApiConfig = Parameters<typeof client.setConfig>[0];
9
+ type HeyApiCreateConfig = Parameters<typeof createClient>[0];
10
+ type AuthOptions = {
11
+ /**
12
+ * Elastic Path key (Client ID) for your store. Required.
13
+ */
14
+ clientId: string;
15
+ /**
16
+ * Optional: supply your own provider. If omitted, we call the SDK’s OAuth op via a fresh bare client.
17
+ */
18
+ tokenProvider?: TokenProvider;
19
+ /**
20
+ * Where to store the access token. Defaults to localStorage; use "cookie" for JS-readable cookies.
21
+ */
22
+ storage?: "localStorage" | "cookie" | StorageAdapter;
23
+ /**
24
+ * Cookie options when storage = "cookie".
25
+ */
26
+ cookie?: Omit<Parameters<typeof cookieAdapter>[0], "name">;
27
+ /**
28
+ * Wrap the provided `fetch` with auth logic (attach Bearer + retry once on 401). Defaults to true.
29
+ */
30
+ wrapUserFetch?: boolean;
31
+ };
32
+ /**
33
+ * Configure the generated singleton client using the *exact* Hey API config,
34
+ * plus separate Auth options.
35
+ */
36
+ declare function configureClient(config: HeyApiConfig, authOpts: AuthOptions): {
37
+ client: _hey_api_client_fetch.Client<Request, Response, unknown, _hey_api_client_fetch.RequestOptions<boolean, string>>;
38
+ auth: {
39
+ getValidAccessToken: () => Promise<string>;
40
+ refresh: () => Promise<string>;
41
+ clear: () => void;
42
+ getSnapshot: () => string | undefined;
43
+ };
44
+ };
45
+ /**
46
+ * Create and return a brand-new client instance (does not mutate the singleton),
47
+ * using the *exact* Hey API createClient config + separate Auth options.
48
+ */
49
+ declare function createShopperClient<T extends NonNullable<HeyApiCreateConfig>>(config: T, authOpts: AuthOptions): {
50
+ client: _hey_api_client_fetch.Client<Request, Response, unknown, _hey_api_client_fetch.RequestOptions<boolean, string>>;
51
+ auth: {
52
+ getValidAccessToken: () => Promise<string>;
53
+ refresh: () => Promise<string>;
54
+ clear: () => void;
55
+ getSnapshot: () => string | undefined;
56
+ };
57
+ };
58
+
59
+ export { type AuthOptions, configureClient, createShopperClient };
@@ -0,0 +1,59 @@
1
+ import * as _hey_api_client_fetch from '@hey-api/client-fetch';
2
+ import { createClient } from '@hey-api/client-fetch';
3
+ import { client } from '../client/sdk.gen.js';
4
+ import { TokenProvider } from './kit.js';
5
+ import { StorageAdapter, cookieAdapter } from './storage.js';
6
+ import '../client/types.gen.js';
7
+
8
+ type HeyApiConfig = Parameters<typeof client.setConfig>[0];
9
+ type HeyApiCreateConfig = Parameters<typeof createClient>[0];
10
+ type AuthOptions = {
11
+ /**
12
+ * Elastic Path key (Client ID) for your store. Required.
13
+ */
14
+ clientId: string;
15
+ /**
16
+ * Optional: supply your own provider. If omitted, we call the SDK’s OAuth op via a fresh bare client.
17
+ */
18
+ tokenProvider?: TokenProvider;
19
+ /**
20
+ * Where to store the access token. Defaults to localStorage; use "cookie" for JS-readable cookies.
21
+ */
22
+ storage?: "localStorage" | "cookie" | StorageAdapter;
23
+ /**
24
+ * Cookie options when storage = "cookie".
25
+ */
26
+ cookie?: Omit<Parameters<typeof cookieAdapter>[0], "name">;
27
+ /**
28
+ * Wrap the provided `fetch` with auth logic (attach Bearer + retry once on 401). Defaults to true.
29
+ */
30
+ wrapUserFetch?: boolean;
31
+ };
32
+ /**
33
+ * Configure the generated singleton client using the *exact* Hey API config,
34
+ * plus separate Auth options.
35
+ */
36
+ declare function configureClient(config: HeyApiConfig, authOpts: AuthOptions): {
37
+ client: _hey_api_client_fetch.Client<Request, Response, unknown, _hey_api_client_fetch.RequestOptions<boolean, string>>;
38
+ auth: {
39
+ getValidAccessToken: () => Promise<string>;
40
+ refresh: () => Promise<string>;
41
+ clear: () => void;
42
+ getSnapshot: () => string | undefined;
43
+ };
44
+ };
45
+ /**
46
+ * Create and return a brand-new client instance (does not mutate the singleton),
47
+ * using the *exact* Hey API createClient config + separate Auth options.
48
+ */
49
+ declare function createShopperClient<T extends NonNullable<HeyApiCreateConfig>>(config: T, authOpts: AuthOptions): {
50
+ client: _hey_api_client_fetch.Client<Request, Response, unknown, _hey_api_client_fetch.RequestOptions<boolean, string>>;
51
+ auth: {
52
+ getValidAccessToken: () => Promise<string>;
53
+ refresh: () => Promise<string>;
54
+ clear: () => void;
55
+ getSnapshot: () => string | undefined;
56
+ };
57
+ };
58
+
59
+ export { type AuthOptions, configureClient, createShopperClient };
@@ -0,0 +1,74 @@
1
+ import { client as singleton } from "../client/sdk.gen.mjs";
2
+ import {
3
+ createClient as sdkCreateClient
4
+ } from "@hey-api/client-fetch";
5
+ import { createAuth } from "./kit.mjs";
6
+ import {
7
+ localStorageAdapter,
8
+ cookieAdapter
9
+ } from "./storage.mjs";
10
+ import { makeAuthFetch } from "./make-auth-fetch.mjs";
11
+ import { makeImplicitTokenProviderWithFreshSdk } from "./token-providers.mjs";
12
+ function resolveStorage(storage, cookie) {
13
+ return storage === "cookie" ? cookieAdapter({ sameSite: "Lax", ...cookie }) : storage === "localStorage" || !storage ? localStorageAdapter() : storage;
14
+ }
15
+ function normalizeHeaders(headers) {
16
+ if (!headers) return void 0;
17
+ if (headers instanceof Headers || Array.isArray(headers)) return headers;
18
+ const out = {};
19
+ for (const [k, v] of Object.entries(headers)) out[k] = String(v);
20
+ return out;
21
+ }
22
+ function resolveFetch(auth, userFetch, wrapUserFetch) {
23
+ const authedStd = makeAuthFetch(auth, userFetch, {
24
+ isAuthRequest: (u) => u.includes("/oauth/")
25
+ });
26
+ return wrapUserFetch !== false ? authedStd : userFetch;
27
+ }
28
+ function configureClient(config, authOpts) {
29
+ const { fetch: userFetch, headers, ...rest } = config;
30
+ const baseUrl = config.baseUrl;
31
+ const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie);
32
+ const headersNorm = normalizeHeaders(headers);
33
+ const provider = authOpts.tokenProvider ?? makeImplicitTokenProviderWithFreshSdk({
34
+ baseUrl: String(baseUrl),
35
+ clientId: authOpts.clientId,
36
+ fetch: userFetch,
37
+ headers: headersNorm
38
+ });
39
+ const auth = createAuth(storageImpl, provider);
40
+ const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch);
41
+ singleton.setConfig({
42
+ ...rest,
43
+ baseUrl,
44
+ headers: headersNorm,
45
+ fetch: finalFetch
46
+ });
47
+ return { client: singleton, auth };
48
+ }
49
+ function createShopperClient(config, authOpts) {
50
+ const { fetch: userFetch, headers, ...rest } = config;
51
+ const baseUrl = config.baseUrl;
52
+ const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie);
53
+ const headersNorm = normalizeHeaders(headers);
54
+ const provider = authOpts.tokenProvider ?? makeImplicitTokenProviderWithFreshSdk({
55
+ baseUrl: String(baseUrl),
56
+ clientId: authOpts.clientId,
57
+ fetch: userFetch,
58
+ headers: headersNorm
59
+ });
60
+ const auth = createAuth(storageImpl, provider);
61
+ const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch);
62
+ const instance = sdkCreateClient({
63
+ ...rest,
64
+ baseUrl,
65
+ headers: headersNorm,
66
+ fetch: finalFetch
67
+ });
68
+ return { client: instance, auth };
69
+ }
70
+ export {
71
+ configureClient,
72
+ createShopperClient
73
+ };
74
+ //# sourceMappingURL=configure-client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/auth/configure-client.ts"],"sourcesContent":["import { client as singleton } from \"../client/sdk.gen\"\nimport {\n type Config,\n createClient as sdkCreateClient,\n} from \"@hey-api/client-fetch\"\nimport { createAuth, type TokenProvider } from \"./kit\"\nimport {\n localStorageAdapter,\n cookieAdapter,\n type StorageAdapter,\n} from \"./storage\"\nimport { makeAuthFetch } from \"./make-auth-fetch\"\nimport { makeImplicitTokenProviderWithFreshSdk } from \"./token-providers\"\n\ntype HeyApiConfig = Parameters<typeof singleton.setConfig>[0]\ntype HeyApiCreateConfig = Parameters<typeof sdkCreateClient>[0]\n\nexport type AuthOptions = {\n /**\n * Elastic Path key (Client ID) for your store. Required.\n */\n clientId: string\n /**\n * Optional: supply your own provider. If omitted, we call the SDK’s OAuth op via a fresh bare client.\n */\n tokenProvider?: TokenProvider\n /**\n * Where to store the access token. Defaults to localStorage; use \"cookie\" for JS-readable cookies.\n */\n storage?: \"localStorage\" | \"cookie\" | StorageAdapter\n /**\n * Cookie options when storage = \"cookie\".\n */\n cookie?: Omit<Parameters<typeof cookieAdapter>[0], \"name\">\n /**\n * Wrap the provided `fetch` with auth logic (attach Bearer + retry once on 401). Defaults to true.\n */\n wrapUserFetch?: boolean\n}\n\nfunction resolveStorage(\n storage: AuthOptions[\"storage\"],\n cookie?: AuthOptions[\"cookie\"],\n): StorageAdapter {\n return storage === \"cookie\"\n ? cookieAdapter({ sameSite: \"Lax\", ...cookie })\n : storage === \"localStorage\" || !storage\n ? localStorageAdapter()\n : storage\n}\n\nfunction normalizeHeaders(\n headers: HeadersInit | Record<string, unknown> | undefined,\n): HeadersInit | undefined {\n if (!headers) return undefined\n if (headers instanceof Headers || Array.isArray(headers)) return headers\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(headers)) out[k] = String(v)\n return out\n}\n\nfunction resolveFetch(\n auth: ReturnType<typeof createAuth>,\n userFetch: Config[\"fetch\"],\n wrapUserFetch: boolean | undefined,\n) {\n const authedStd = makeAuthFetch(auth, userFetch, {\n isAuthRequest: (u) => u.includes(\"/oauth/\"),\n })\n // If user opts out, still return a standard-shaped fetch\n return wrapUserFetch !== false ? authedStd : userFetch\n}\n\n/**\n * Configure the generated singleton client using the *exact* Hey API config,\n * plus separate Auth options.\n */\nexport function configureClient(config: HeyApiConfig, authOpts: AuthOptions) {\n const { fetch: userFetch, headers, ...rest } = config\n\n // Some codegens mark baseUrl optional in the type; we rely on what the caller passed.\n const baseUrl = (config as any).baseUrl as string\n\n const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie)\n const headersNorm = normalizeHeaders(headers)\n\n const provider: TokenProvider =\n authOpts.tokenProvider ??\n makeImplicitTokenProviderWithFreshSdk({\n baseUrl: String(baseUrl),\n clientId: authOpts.clientId,\n fetch: userFetch,\n headers: headersNorm,\n })\n\n const auth = createAuth(storageImpl, provider)\n const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch)\n\n singleton.setConfig({\n ...rest,\n baseUrl,\n headers: headersNorm,\n fetch: finalFetch,\n })\n\n return { client: singleton, auth }\n}\n\n/**\n * Create and return a brand-new client instance (does not mutate the singleton),\n * using the *exact* Hey API createClient config + separate Auth options.\n */\nexport function createShopperClient<T extends NonNullable<HeyApiCreateConfig>>(\n config: T,\n authOpts: AuthOptions,\n) {\n const { fetch: userFetch, headers, ...rest } = config\n const baseUrl = (config as any).baseUrl as string\n\n const storageImpl = resolveStorage(authOpts.storage, authOpts.cookie)\n const headersNorm = normalizeHeaders(headers)\n\n const provider: TokenProvider =\n authOpts.tokenProvider ??\n makeImplicitTokenProviderWithFreshSdk({\n baseUrl: String(baseUrl),\n clientId: authOpts.clientId,\n fetch: userFetch as any,\n headers: headersNorm,\n })\n\n const auth = createAuth(storageImpl, provider)\n const finalFetch = resolveFetch(auth, userFetch, authOpts.wrapUserFetch)\n\n const instance = sdkCreateClient({\n ...rest,\n baseUrl,\n headers: headersNorm,\n fetch: finalFetch,\n })\n\n return { client: instance, auth }\n}\n"],"mappings":"AAAA,SAAS,UAAU,iBAAiB;AACpC;AAAA,EAEE,gBAAgB;AAAA,OACX;AACP,SAAS,kBAAsC;AAC/C;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,qBAAqB;AAC9B,SAAS,6CAA6C;AA4BtD,SAAS,eACP,SACA,QACgB;AAChB,SAAO,YAAY,WACf,cAAc,EAAE,UAAU,OAAO,GAAG,OAAO,CAAC,IAC5C,YAAY,kBAAkB,CAAC,UAC/B,oBAAoB,IACpB;AACN;AAEA,SAAS,iBACP,SACyB;AACzB,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,mBAAmB,WAAW,MAAM,QAAQ,OAAO,EAAG,QAAO;AACjE,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,OAAO,EAAG,KAAI,CAAC,IAAI,OAAO,CAAC;AAC/D,SAAO;AACT;AAEA,SAAS,aACP,MACA,WACA,eACA;AACA,QAAM,YAAY,cAAc,MAAM,WAAW;AAAA,IAC/C,eAAe,CAAC,MAAM,EAAE,SAAS,SAAS;AAAA,EAC5C,CAAC;AAED,SAAO,kBAAkB,QAAQ,YAAY;AAC/C;AAMO,SAAS,gBAAgB,QAAsB,UAAuB;AAC3E,QAAM,EAAE,OAAO,WAAW,SAAS,GAAG,KAAK,IAAI;AAG/C,QAAM,UAAW,OAAe;AAEhC,QAAM,cAAc,eAAe,SAAS,SAAS,SAAS,MAAM;AACpE,QAAM,cAAc,iBAAiB,OAAO;AAE5C,QAAM,WACJ,SAAS,iBACT,sCAAsC;AAAA,IACpC,SAAS,OAAO,OAAO;AAAA,IACvB,UAAU,SAAS;AAAA,IACnB,OAAO;AAAA,IACP,SAAS;AAAA,EACX,CAAC;AAEH,QAAM,OAAO,WAAW,aAAa,QAAQ;AAC7C,QAAM,aAAa,aAAa,MAAM,WAAW,SAAS,aAAa;AAEvE,YAAU,UAAU;AAAA,IAClB,GAAG;AAAA,IACH;AAAA,IACA,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,QAAQ,WAAW,KAAK;AACnC;AAMO,SAAS,oBACd,QACA,UACA;AACA,QAAM,EAAE,OAAO,WAAW,SAAS,GAAG,KAAK,IAAI;AAC/C,QAAM,UAAW,OAAe;AAEhC,QAAM,cAAc,eAAe,SAAS,SAAS,SAAS,MAAM;AACpE,QAAM,cAAc,iBAAiB,OAAO;AAE5C,QAAM,WACJ,SAAS,iBACT,sCAAsC;AAAA,IACpC,SAAS,OAAO,OAAO;AAAA,IACvB,UAAU,SAAS;AAAA,IACnB,OAAO;AAAA,IACP,SAAS;AAAA,EACX,CAAC;AAEH,QAAM,OAAO,WAAW,aAAa,QAAQ;AAC7C,QAAM,aAAa,aAAa,MAAM,WAAW,SAAS,aAAa;AAEvE,QAAM,WAAW,gBAAgB;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,IACA,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,QAAQ,UAAU,KAAK;AAClC;","names":[]}
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var kit_exports = {};
20
+ __export(kit_exports, {
21
+ createAuth: () => createAuth
22
+ });
23
+ module.exports = __toCommonJS(kit_exports);
24
+ function createAuth(storage, tokenProvider, leewaySec = 60) {
25
+ let credentials;
26
+ let refreshing;
27
+ function loadStoredCredentials() {
28
+ const storedData = storage.get();
29
+ if (storedData) {
30
+ try {
31
+ const parsed = JSON.parse(storedData);
32
+ if (parsed.access_token) {
33
+ credentials = parsed;
34
+ }
35
+ } catch {
36
+ credentials = { access_token: storedData };
37
+ }
38
+ }
39
+ }
40
+ loadStoredCredentials();
41
+ storage.subscribe?.(() => {
42
+ loadStoredCredentials();
43
+ });
44
+ function decodeExp(jwt) {
45
+ if (!jwt) return void 0;
46
+ try {
47
+ const payload = JSON.parse(atob(jwt.split(".")[1]));
48
+ return typeof payload?.exp === "number" ? payload.exp : void 0;
49
+ } catch {
50
+ return void 0;
51
+ }
52
+ }
53
+ function isExpired() {
54
+ if (!credentials?.access_token) return true;
55
+ const jwtExp = decodeExp(credentials.access_token);
56
+ if (jwtExp) {
57
+ const now = Math.floor(Date.now() / 1e3);
58
+ return now >= jwtExp - leewaySec;
59
+ }
60
+ if (credentials.expires) {
61
+ const now = Math.floor(Date.now() / 1e3);
62
+ return now >= credentials.expires - leewaySec;
63
+ }
64
+ return true;
65
+ }
66
+ async function refresh() {
67
+ if (refreshing) return refreshing;
68
+ refreshing = (async () => {
69
+ const res = await tokenProvider({ current: credentials?.access_token });
70
+ credentials = res;
71
+ storage.set(JSON.stringify(res));
72
+ return credentials.access_token;
73
+ })();
74
+ try {
75
+ return await refreshing;
76
+ } finally {
77
+ refreshing = void 0;
78
+ }
79
+ }
80
+ async function getValidAccessToken() {
81
+ if (credentials?.access_token && !isExpired()) return credentials.access_token;
82
+ return refresh();
83
+ }
84
+ function clear() {
85
+ credentials = void 0;
86
+ storage.set(void 0);
87
+ }
88
+ function getSnapshot() {
89
+ return credentials?.access_token;
90
+ }
91
+ return { getValidAccessToken, refresh, clear, getSnapshot };
92
+ }
93
+ // Annotate the CommonJS export names for ESM import in node:
94
+ 0 && (module.exports = {
95
+ createAuth
96
+ });
97
+ //# sourceMappingURL=kit.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/auth/kit.ts"],"sourcesContent":["import { AccessTokenResponse } from \"../client\"\n\nexport type TokenProvider = (opts: {\n current?: string\n}) => Promise<AccessTokenResponse>\n\nexport function createAuth(\n storage: import(\"./storage\").StorageAdapter,\n tokenProvider: TokenProvider,\n leewaySec = 60,\n) {\n let credentials: AccessTokenResponse | undefined\n let refreshing: Promise<string> | undefined\n\n // Load stored credentials on initialization\n function loadStoredCredentials() {\n const storedData = storage.get()\n if (storedData) {\n try {\n const parsed = JSON.parse(storedData)\n if (parsed.access_token) {\n credentials = parsed\n }\n } catch {\n // Not JSON, assume it's a legacy plain token\n credentials = { access_token: storedData } as AccessTokenResponse\n }\n }\n }\n\n loadStoredCredentials()\n\n // Optional cross-tab sync (localStorage adapter implements subscribe)\n storage.subscribe?.(() => {\n loadStoredCredentials()\n })\n\n function decodeExp(jwt?: string): number | undefined {\n if (!jwt) return undefined\n try {\n const payload = JSON.parse(atob(jwt.split(\".\")[1]))\n return typeof payload?.exp === \"number\" ? payload.exp : undefined\n } catch {\n return undefined\n }\n }\n\n function isExpired(): boolean {\n if (!credentials?.access_token) return true\n \n // Try to decode exp from JWT\n const jwtExp = decodeExp(credentials.access_token)\n if (jwtExp) {\n const now = Math.floor(Date.now() / 1000)\n return now >= jwtExp - leewaySec\n }\n \n // Use the expires field if available (absolute timestamp)\n if (credentials.expires) {\n const now = Math.floor(Date.now() / 1000)\n return now >= credentials.expires - leewaySec\n }\n \n // If we can't determine expiration, consider it expired\n return true\n }\n\n async function refresh(): Promise<string> {\n if (refreshing) return refreshing\n refreshing = (async () => {\n const res = await tokenProvider({ current: credentials?.access_token })\n credentials = res\n \n // Store the credentials object directly\n storage.set(JSON.stringify(res))\n \n return credentials.access_token!\n })()\n try {\n return await refreshing\n } finally {\n refreshing = undefined\n }\n }\n\n async function getValidAccessToken(): Promise<string> {\n if (credentials?.access_token && !isExpired()) return credentials.access_token\n return refresh()\n }\n\n function clear() {\n credentials = undefined\n storage.set(undefined)\n }\n\n function getSnapshot() {\n return credentials?.access_token\n }\n\n return { getValidAccessToken, refresh, clear, getSnapshot }\n}\n\nexport type Auth = ReturnType<typeof createAuth>\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,SAAS,WACd,SACA,eACA,YAAY,IACZ;AACA,MAAI;AACJ,MAAI;AAGJ,WAAS,wBAAwB;AAC/B,UAAM,aAAa,QAAQ,IAAI;AAC/B,QAAI,YAAY;AACd,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,UAAU;AACpC,YAAI,OAAO,cAAc;AACvB,wBAAc;AAAA,QAChB;AAAA,MACF,QAAQ;AAEN,sBAAc,EAAE,cAAc,WAAW;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,wBAAsB;AAGtB,UAAQ,YAAY,MAAM;AACxB,0BAAsB;AAAA,EACxB,CAAC;AAED,WAAS,UAAU,KAAkC;AACnD,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,KAAK,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AAClD,aAAO,OAAO,SAAS,QAAQ,WAAW,QAAQ,MAAM;AAAA,IAC1D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,YAAqB;AAC5B,QAAI,CAAC,aAAa,aAAc,QAAO;AAGvC,UAAM,SAAS,UAAU,YAAY,YAAY;AACjD,QAAI,QAAQ;AACV,YAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,aAAO,OAAO,SAAS;AAAA,IACzB;AAGA,QAAI,YAAY,SAAS;AACvB,YAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,aAAO,OAAO,YAAY,UAAU;AAAA,IACtC;AAGA,WAAO;AAAA,EACT;AAEA,iBAAe,UAA2B;AACxC,QAAI,WAAY,QAAO;AACvB,kBAAc,YAAY;AACxB,YAAM,MAAM,MAAM,cAAc,EAAE,SAAS,aAAa,aAAa,CAAC;AACtE,oBAAc;AAGd,cAAQ,IAAI,KAAK,UAAU,GAAG,CAAC;AAE/B,aAAO,YAAY;AAAA,IACrB,GAAG;AACH,QAAI;AACF,aAAO,MAAM;AAAA,IACf,UAAE;AACA,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,iBAAe,sBAAuC;AACpD,QAAI,aAAa,gBAAgB,CAAC,UAAU,EAAG,QAAO,YAAY;AAClE,WAAO,QAAQ;AAAA,EACjB;AAEA,WAAS,QAAQ;AACf,kBAAc;AACd,YAAQ,IAAI,MAAS;AAAA,EACvB;AAEA,WAAS,cAAc;AACrB,WAAO,aAAa;AAAA,EACtB;AAEA,SAAO,EAAE,qBAAqB,SAAS,OAAO,YAAY;AAC5D;","names":[]}
@@ -0,0 +1,15 @@
1
+ import { StorageAdapter } from './storage.cjs';
2
+ import { AccessTokenResponse } from '../client/types.gen.cjs';
3
+
4
+ type TokenProvider = (opts: {
5
+ current?: string;
6
+ }) => Promise<AccessTokenResponse>;
7
+ declare function createAuth(storage: StorageAdapter, tokenProvider: TokenProvider, leewaySec?: number): {
8
+ getValidAccessToken: () => Promise<string>;
9
+ refresh: () => Promise<string>;
10
+ clear: () => void;
11
+ getSnapshot: () => string | undefined;
12
+ };
13
+ type Auth = ReturnType<typeof createAuth>;
14
+
15
+ export { type Auth, type TokenProvider, createAuth };
@@ -0,0 +1,15 @@
1
+ import { StorageAdapter } from './storage.js';
2
+ import { AccessTokenResponse } from '../client/types.gen.js';
3
+
4
+ type TokenProvider = (opts: {
5
+ current?: string;
6
+ }) => Promise<AccessTokenResponse>;
7
+ declare function createAuth(storage: StorageAdapter, tokenProvider: TokenProvider, leewaySec?: number): {
8
+ getValidAccessToken: () => Promise<string>;
9
+ refresh: () => Promise<string>;
10
+ clear: () => void;
11
+ getSnapshot: () => string | undefined;
12
+ };
13
+ type Auth = ReturnType<typeof createAuth>;
14
+
15
+ export { type Auth, type TokenProvider, createAuth };
@@ -0,0 +1,73 @@
1
+ function createAuth(storage, tokenProvider, leewaySec = 60) {
2
+ let credentials;
3
+ let refreshing;
4
+ function loadStoredCredentials() {
5
+ const storedData = storage.get();
6
+ if (storedData) {
7
+ try {
8
+ const parsed = JSON.parse(storedData);
9
+ if (parsed.access_token) {
10
+ credentials = parsed;
11
+ }
12
+ } catch {
13
+ credentials = { access_token: storedData };
14
+ }
15
+ }
16
+ }
17
+ loadStoredCredentials();
18
+ storage.subscribe?.(() => {
19
+ loadStoredCredentials();
20
+ });
21
+ function decodeExp(jwt) {
22
+ if (!jwt) return void 0;
23
+ try {
24
+ const payload = JSON.parse(atob(jwt.split(".")[1]));
25
+ return typeof payload?.exp === "number" ? payload.exp : void 0;
26
+ } catch {
27
+ return void 0;
28
+ }
29
+ }
30
+ function isExpired() {
31
+ if (!credentials?.access_token) return true;
32
+ const jwtExp = decodeExp(credentials.access_token);
33
+ if (jwtExp) {
34
+ const now = Math.floor(Date.now() / 1e3);
35
+ return now >= jwtExp - leewaySec;
36
+ }
37
+ if (credentials.expires) {
38
+ const now = Math.floor(Date.now() / 1e3);
39
+ return now >= credentials.expires - leewaySec;
40
+ }
41
+ return true;
42
+ }
43
+ async function refresh() {
44
+ if (refreshing) return refreshing;
45
+ refreshing = (async () => {
46
+ const res = await tokenProvider({ current: credentials?.access_token });
47
+ credentials = res;
48
+ storage.set(JSON.stringify(res));
49
+ return credentials.access_token;
50
+ })();
51
+ try {
52
+ return await refreshing;
53
+ } finally {
54
+ refreshing = void 0;
55
+ }
56
+ }
57
+ async function getValidAccessToken() {
58
+ if (credentials?.access_token && !isExpired()) return credentials.access_token;
59
+ return refresh();
60
+ }
61
+ function clear() {
62
+ credentials = void 0;
63
+ storage.set(void 0);
64
+ }
65
+ function getSnapshot() {
66
+ return credentials?.access_token;
67
+ }
68
+ return { getValidAccessToken, refresh, clear, getSnapshot };
69
+ }
70
+ export {
71
+ createAuth
72
+ };
73
+ //# sourceMappingURL=kit.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/auth/kit.ts"],"sourcesContent":["import { AccessTokenResponse } from \"../client\"\n\nexport type TokenProvider = (opts: {\n current?: string\n}) => Promise<AccessTokenResponse>\n\nexport function createAuth(\n storage: import(\"./storage\").StorageAdapter,\n tokenProvider: TokenProvider,\n leewaySec = 60,\n) {\n let credentials: AccessTokenResponse | undefined\n let refreshing: Promise<string> | undefined\n\n // Load stored credentials on initialization\n function loadStoredCredentials() {\n const storedData = storage.get()\n if (storedData) {\n try {\n const parsed = JSON.parse(storedData)\n if (parsed.access_token) {\n credentials = parsed\n }\n } catch {\n // Not JSON, assume it's a legacy plain token\n credentials = { access_token: storedData } as AccessTokenResponse\n }\n }\n }\n\n loadStoredCredentials()\n\n // Optional cross-tab sync (localStorage adapter implements subscribe)\n storage.subscribe?.(() => {\n loadStoredCredentials()\n })\n\n function decodeExp(jwt?: string): number | undefined {\n if (!jwt) return undefined\n try {\n const payload = JSON.parse(atob(jwt.split(\".\")[1]))\n return typeof payload?.exp === \"number\" ? payload.exp : undefined\n } catch {\n return undefined\n }\n }\n\n function isExpired(): boolean {\n if (!credentials?.access_token) return true\n \n // Try to decode exp from JWT\n const jwtExp = decodeExp(credentials.access_token)\n if (jwtExp) {\n const now = Math.floor(Date.now() / 1000)\n return now >= jwtExp - leewaySec\n }\n \n // Use the expires field if available (absolute timestamp)\n if (credentials.expires) {\n const now = Math.floor(Date.now() / 1000)\n return now >= credentials.expires - leewaySec\n }\n \n // If we can't determine expiration, consider it expired\n return true\n }\n\n async function refresh(): Promise<string> {\n if (refreshing) return refreshing\n refreshing = (async () => {\n const res = await tokenProvider({ current: credentials?.access_token })\n credentials = res\n \n // Store the credentials object directly\n storage.set(JSON.stringify(res))\n \n return credentials.access_token!\n })()\n try {\n return await refreshing\n } finally {\n refreshing = undefined\n }\n }\n\n async function getValidAccessToken(): Promise<string> {\n if (credentials?.access_token && !isExpired()) return credentials.access_token\n return refresh()\n }\n\n function clear() {\n credentials = undefined\n storage.set(undefined)\n }\n\n function getSnapshot() {\n return credentials?.access_token\n }\n\n return { getValidAccessToken, refresh, clear, getSnapshot }\n}\n\nexport type Auth = ReturnType<typeof createAuth>\n"],"mappings":"AAMO,SAAS,WACd,SACA,eACA,YAAY,IACZ;AACA,MAAI;AACJ,MAAI;AAGJ,WAAS,wBAAwB;AAC/B,UAAM,aAAa,QAAQ,IAAI;AAC/B,QAAI,YAAY;AACd,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,UAAU;AACpC,YAAI,OAAO,cAAc;AACvB,wBAAc;AAAA,QAChB;AAAA,MACF,QAAQ;AAEN,sBAAc,EAAE,cAAc,WAAW;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,wBAAsB;AAGtB,UAAQ,YAAY,MAAM;AACxB,0BAAsB;AAAA,EACxB,CAAC;AAED,WAAS,UAAU,KAAkC;AACnD,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,KAAK,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AAClD,aAAO,OAAO,SAAS,QAAQ,WAAW,QAAQ,MAAM;AAAA,IAC1D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,YAAqB;AAC5B,QAAI,CAAC,aAAa,aAAc,QAAO;AAGvC,UAAM,SAAS,UAAU,YAAY,YAAY;AACjD,QAAI,QAAQ;AACV,YAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,aAAO,OAAO,SAAS;AAAA,IACzB;AAGA,QAAI,YAAY,SAAS;AACvB,YAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,aAAO,OAAO,YAAY,UAAU;AAAA,IACtC;AAGA,WAAO;AAAA,EACT;AAEA,iBAAe,UAA2B;AACxC,QAAI,WAAY,QAAO;AACvB,kBAAc,YAAY;AACxB,YAAM,MAAM,MAAM,cAAc,EAAE,SAAS,aAAa,aAAa,CAAC;AACtE,oBAAc;AAGd,cAAQ,IAAI,KAAK,UAAU,GAAG,CAAC;AAE/B,aAAO,YAAY;AAAA,IACrB,GAAG;AACH,QAAI;AACF,aAAO,MAAM;AAAA,IACf,UAAE;AACA,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,iBAAe,sBAAuC;AACpD,QAAI,aAAa,gBAAgB,CAAC,UAAU,EAAG,QAAO,YAAY;AAClE,WAAO,QAAQ;AAAA,EACjB;AAEA,WAAS,QAAQ;AACf,kBAAc;AACd,YAAQ,IAAI,MAAS;AAAA,EACvB;AAEA,WAAS,cAAc;AACrB,WAAO,aAAa;AAAA,EACtB;AAEA,SAAO,EAAE,qBAAqB,SAAS,OAAO,YAAY;AAC5D;","names":[]}