@tern-secure/auth 1.1.0-canary.v20250916132854 → 1.1.0-canary.v20250919131424

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.
@@ -0,0 +1,237 @@
1
+ import { camelToSnake, jitteredDelay } from "@tern-secure/shared/caseUtils";
2
+ import { buildURL as buildUrlUtil, stringifyQueryParams } from "../utils";
3
+ class NetworkError extends Error {
4
+ constructor(url, original) {
5
+ super(`Network error for ${url}: ${original.message}`);
6
+ this.url = url;
7
+ this.original = original;
8
+ this.name = "NetworkError";
9
+ }
10
+ }
11
+ class TimeoutError extends Error {
12
+ constructor() {
13
+ super("Request timed out");
14
+ this.name = "TimeoutError";
15
+ }
16
+ }
17
+ class CircuitOpenError extends Error {
18
+ constructor() {
19
+ super("Circuit breaker is open");
20
+ this.name = "CircuitOpenError";
21
+ }
22
+ }
23
+ class HTTPError extends Error {
24
+ constructor(status, url, body) {
25
+ super(`HTTP ${status} error for ${url}`);
26
+ this.status = status;
27
+ this.url = url;
28
+ this.body = body;
29
+ this.name = "HTTPError";
30
+ }
31
+ }
32
+ function createInitialState(clientOptions = {}) {
33
+ return {
34
+ circuitBreaker: {
35
+ failures: 0,
36
+ lastFailureTime: 0,
37
+ state: "closed"
38
+ },
39
+ beforeRequestHooks: [],
40
+ afterResponseHooks: [],
41
+ clientOptions
42
+ };
43
+ }
44
+ function addBeforeRequestHook(state, hook) {
45
+ state.beforeRequestHooks.push(hook);
46
+ }
47
+ function addAfterResponseHook(state, hook) {
48
+ state.afterResponseHooks.push(hook);
49
+ }
50
+ async function runBeforeRequestHooks(state) {
51
+ for (const hook of state.beforeRequestHooks) {
52
+ const result = await hook();
53
+ if (result === false) return false;
54
+ }
55
+ return true;
56
+ }
57
+ async function runAfterResponseHooks(state, response) {
58
+ for (const hook of state.afterResponseHooks) {
59
+ await hook(response);
60
+ }
61
+ }
62
+ function checkCircuitBreaker(state, requestOptions) {
63
+ const { recoveryTimeoutMs = 6e4 } = requestOptions;
64
+ const now = Date.now();
65
+ if (state.circuitBreaker.state === "open") {
66
+ if (now - state.circuitBreaker.lastFailureTime >= recoveryTimeoutMs) {
67
+ state.circuitBreaker.state = "half-open";
68
+ } else {
69
+ throw new CircuitOpenError();
70
+ }
71
+ }
72
+ }
73
+ function recordSuccess(state) {
74
+ state.circuitBreaker.failures = 0;
75
+ state.circuitBreaker.state = "closed";
76
+ }
77
+ function recordFailure(state, requestOptions) {
78
+ const { failureThreshold = 5 } = requestOptions;
79
+ state.circuitBreaker.failures++;
80
+ state.circuitBreaker.lastFailureTime = Date.now();
81
+ if (state.circuitBreaker.failures >= failureThreshold) {
82
+ state.circuitBreaker.state = "open";
83
+ }
84
+ }
85
+ function shouldRetry(state, requestOptions, error, method, attempt, maxTries) {
86
+ const isRetryable = error instanceof NetworkError && method.toUpperCase() === "GET" && attempt < maxTries;
87
+ if (!isRetryable) {
88
+ recordFailure(state, requestOptions);
89
+ }
90
+ return isRetryable;
91
+ }
92
+ async function retryWithBackoff(state, requestOptions, attemptFn, shouldRetryFn) {
93
+ const {
94
+ initialDelay = 700,
95
+ factor = 2,
96
+ maxDelay = 5e3,
97
+ maxTries = typeof navigator !== "undefined" && navigator.onLine ? 4 : 11
98
+ } = requestOptions;
99
+ let lastError;
100
+ for (let attempt = 1; attempt <= maxTries; attempt++) {
101
+ try {
102
+ const result = await attemptFn();
103
+ recordSuccess(state);
104
+ return result;
105
+ } catch (error) {
106
+ lastError = error;
107
+ if (!shouldRetryFn(error, attempt)) {
108
+ throw error;
109
+ }
110
+ recordFailure(state, requestOptions);
111
+ if (attempt < maxTries) {
112
+ const delay = Math.min(initialDelay * Math.pow(factor, attempt - 1), maxDelay);
113
+ await new Promise((resolve) => setTimeout(resolve, jitteredDelay(delay)));
114
+ }
115
+ }
116
+ }
117
+ throw lastError;
118
+ }
119
+ function createCoreApiClient(clientOptions) {
120
+ function buildUrl(requestInit) {
121
+ var _a, _b;
122
+ const isLocalhost = ((_a = clientOptions.apiUrl) == null ? void 0 : _a.includes("localhost")) || ((_b = clientOptions.apiUrl) == null ? void 0 : _b.includes("127.0.0.1"));
123
+ const { path } = requestInit;
124
+ const { instanceType, domain, apiUrl, apiBasePath = "/api/auth" } = clientOptions;
125
+ const domainInProd = instanceType === "production" ? domain : "";
126
+ let baseUrl;
127
+ if (isLocalhost) {
128
+ baseUrl = (apiUrl == null ? void 0 : apiUrl.startsWith("http")) ? apiUrl : `http://${apiUrl}`;
129
+ } else {
130
+ baseUrl = `https://${domainInProd || apiUrl}`;
131
+ }
132
+ const fullPath = `${apiBasePath}/${path}`.replace(/\/+/g, "/");
133
+ return buildUrlUtil(
134
+ {
135
+ base: baseUrl,
136
+ pathname: fullPath,
137
+ searchParams: requestInit.search ? new URLSearchParams(requestInit.search) : void 0
138
+ },
139
+ { stringify: false }
140
+ );
141
+ }
142
+ async function makeRequest(state2, init, opts = {}) {
143
+ const requestInit = { ...init };
144
+ const { method = "GET", body } = requestInit;
145
+ const requestOptions = { ...opts };
146
+ requestInit.url = buildUrl({ ...requestInit });
147
+ checkCircuitBreaker(state2, requestOptions);
148
+ const shouldContinue = await runBeforeRequestHooks(state2);
149
+ if (!shouldContinue) {
150
+ const mockResponse = new Response("{}", {
151
+ status: 200
152
+ });
153
+ mockResponse.payload = { response: {} };
154
+ await runAfterResponseHooks(state2, mockResponse);
155
+ return mockResponse;
156
+ }
157
+ const { timeoutMs } = requestOptions;
158
+ const overwrittenRequestMethod = method === "GET" ? "GET" : "POST";
159
+ const url = requestInit.url.toString();
160
+ console.log("Request URL:", url);
161
+ requestInit.headers = new Headers(requestInit.headers);
162
+ if (method !== "GET" && !(body instanceof FormData) && !requestInit.headers.has("content-type")) {
163
+ requestInit.headers.set("content-type", "application/json");
164
+ }
165
+ if (requestInit.headers.get("content-type") === "application/x-www-form-urlencoded") {
166
+ requestInit.body = body ? stringifyQueryParams(body, {
167
+ keyEncoder: camelToSnake
168
+ }) : body;
169
+ } else if (requestInit.headers.get("content-type") === "application/json" && body) {
170
+ requestInit.body = typeof body === "string" ? body : JSON.stringify(body);
171
+ }
172
+ const attemptRequest = async () => {
173
+ const controller = new AbortController();
174
+ const timeoutId = timeoutMs ? setTimeout(() => {
175
+ controller.abort();
176
+ }, timeoutMs) : null;
177
+ let response;
178
+ const fetchOpts = {
179
+ ...requestInit,
180
+ credentials: "include",
181
+ method: overwrittenRequestMethod
182
+ };
183
+ try {
184
+ response = await fetch(url, fetchOpts);
185
+ if (timeoutId) clearTimeout(timeoutId);
186
+ let payload = null;
187
+ if (response.status === 204) {
188
+ payload = null;
189
+ } else {
190
+ try {
191
+ const json = await response.json();
192
+ payload = json;
193
+ } catch {
194
+ payload = { response: {} };
195
+ }
196
+ }
197
+ const apiResponse = response;
198
+ apiResponse.payload = payload;
199
+ await runAfterResponseHooks(state2, apiResponse);
200
+ return apiResponse;
201
+ } catch (error) {
202
+ if (timeoutId) clearTimeout(timeoutId);
203
+ if (error.name === "AbortError") {
204
+ throw new TimeoutError();
205
+ }
206
+ throw new NetworkError(url, error);
207
+ }
208
+ };
209
+ return retryWithBackoff(
210
+ state2,
211
+ requestOptions,
212
+ attemptRequest,
213
+ (error, attempt) => shouldRetry(
214
+ state2,
215
+ requestOptions,
216
+ error,
217
+ overwrittenRequestMethod,
218
+ attempt,
219
+ requestOptions.maxTries || (typeof navigator !== "undefined" && navigator.onLine ? 4 : 11)
220
+ )
221
+ );
222
+ }
223
+ const state = createInitialState(clientOptions);
224
+ return {
225
+ onBeforeRequest: (hook) => addBeforeRequestHook(state, hook),
226
+ onAfterResponse: (hook) => addAfterResponseHook(state, hook),
227
+ request: (init, opts = {}) => makeRequest(state, init, opts)
228
+ };
229
+ }
230
+ export {
231
+ CircuitOpenError,
232
+ HTTPError,
233
+ NetworkError,
234
+ TimeoutError,
235
+ createCoreApiClient
236
+ };
237
+ //# sourceMappingURL=c_coreApiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/instance/c_coreApiClient.ts"],"sourcesContent":["import { camelToSnake, jitteredDelay } from '@tern-secure/shared/caseUtils'\nimport type { InstanceType, TernSecureApiErrorJSON } from '@tern-secure/types';\n\nimport { buildURL as buildUrlUtil, stringifyQueryParams } from '../utils';\n\nexport type HTTPMethod =\n | 'CONNECT'\n | 'DELETE'\n | 'GET'\n | 'HEAD'\n | 'OPTIONS'\n | 'PATCH'\n | 'POST'\n | 'PUT'\n | 'TRACE';\n\nexport type ApiRequestInit = RequestInit & {\n path?: string;\n search?: ConstructorParameters<typeof URLSearchParams>[0];\n sessionId?: string;\n url?: URL;\n};\n\nexport interface ApiResponseJSON<T> {\n response: T;\n errors?: TernSecureApiErrorJSON[];\n}\n\nexport type ApiResponse<T> = Response & { payload: ApiResponseJSON<T> | null };\n\nexport type ApiRequestCallback<T> = (request: ApiRequestInit, response?: ApiResponse<T>) => unknown;\n\nexport interface ApiRequestOptions {\n timeoutMs?: number;\n maxTries?: number;\n initialDelay?: number;\n factor?: number;\n maxDelay?: number;\n failureThreshold?: number;\n recoveryTimeoutMs?: number;\n}\n\nexport interface ApiClientOptions {\n domain?: string;\n apiUrl?: string;\n frontendApi?: string;\n instanceType?: InstanceType;\n apiBasePath?: string;\n}\n\nexport interface ApiClient {\n onBeforeRequest: (hook: BeforeRequestHook) => void;\n onAfterResponse: (hook: AfterResponseHook) => void;\n request: <T>(init: ApiRequestInit, opts?: ApiRequestOptions) => Promise<ApiResponse<T>>;\n}\n\nexport type BeforeRequestHook = () => boolean | Promise<boolean>;\nexport type AfterResponseHook = (response: ApiResponse<any>) => boolean | Promise<boolean>;\n\n// Error classes\nexport class NetworkError extends Error {\n constructor(\n public url: string,\n public original: Error,\n ) {\n super(`Network error for ${url}: ${original.message}`);\n this.name = 'NetworkError';\n }\n}\n\nexport class TimeoutError extends Error {\n constructor() {\n super('Request timed out');\n this.name = 'TimeoutError';\n }\n}\n\nexport class CircuitOpenError extends Error {\n constructor() {\n super('Circuit breaker is open');\n this.name = 'CircuitOpenError';\n }\n}\n\nexport class HTTPError extends Error {\n constructor(\n public status: number,\n public url: string,\n public body?: any,\n ) {\n super(`HTTP ${status} error for ${url}`);\n this.name = 'HTTPError';\n }\n}\n\n// Circuit breaker state interface\ninterface CircuitBreakerState {\n failures: number;\n lastFailureTime: number;\n state: 'closed' | 'open' | 'half-open';\n}\n\n// Client state interface\ninterface ClientState {\n circuitBreaker: CircuitBreakerState;\n beforeRequestHooks: BeforeRequestHook[];\n afterResponseHooks: AfterResponseHook[];\n clientOptions: ApiClientOptions;\n}\n\nfunction createInitialState(clientOptions: ApiClientOptions = {}): ClientState {\n return {\n circuitBreaker: {\n failures: 0,\n lastFailureTime: 0,\n state: 'closed',\n },\n beforeRequestHooks: [],\n afterResponseHooks: [],\n clientOptions,\n };\n}\n\nfunction addBeforeRequestHook(state: ClientState, hook: BeforeRequestHook): void {\n state.beforeRequestHooks.push(hook);\n}\n\nfunction addAfterResponseHook(state: ClientState, hook: AfterResponseHook): void {\n state.afterResponseHooks.push(hook);\n}\n\nasync function runBeforeRequestHooks(state: ClientState): Promise<boolean> {\n for (const hook of state.beforeRequestHooks) {\n const result = await hook();\n if (result === false) return false;\n }\n return true;\n}\n\nasync function runAfterResponseHooks(\n state: ClientState,\n response: ApiResponse<any>,\n): Promise<void> {\n for (const hook of state.afterResponseHooks) {\n await hook(response);\n }\n}\n\nfunction checkCircuitBreaker(state: ClientState, requestOptions: ApiRequestOptions): void {\n const { recoveryTimeoutMs = 60000 } = requestOptions;\n const now = Date.now();\n\n if (state.circuitBreaker.state === 'open') {\n if (now - state.circuitBreaker.lastFailureTime >= recoveryTimeoutMs) {\n state.circuitBreaker.state = 'half-open';\n } else {\n throw new CircuitOpenError();\n }\n }\n}\n\nfunction recordSuccess(state: ClientState): void {\n state.circuitBreaker.failures = 0;\n state.circuitBreaker.state = 'closed';\n}\n\nfunction recordFailure(state: ClientState, requestOptions: ApiRequestOptions): void {\n const { failureThreshold = 5 } = requestOptions;\n state.circuitBreaker.failures++;\n state.circuitBreaker.lastFailureTime = Date.now();\n\n if (state.circuitBreaker.failures >= failureThreshold) {\n state.circuitBreaker.state = 'open';\n }\n}\n\nfunction shouldRetry(\n state: ClientState,\n requestOptions: ApiRequestOptions,\n error: any,\n method: string,\n attempt: number,\n maxTries: number,\n): boolean {\n const isRetryable =\n error instanceof NetworkError && method.toUpperCase() === 'GET' && attempt < maxTries;\n\n if (!isRetryable) {\n recordFailure(state, requestOptions);\n }\n\n return isRetryable;\n}\n\nasync function retryWithBackoff<T>(\n state: ClientState,\n requestOptions: ApiRequestOptions,\n attemptFn: () => Promise<T>,\n shouldRetryFn: (error: any, attempt: number) => boolean,\n): Promise<T> {\n const {\n initialDelay = 700,\n factor = 2,\n maxDelay = 5000,\n maxTries = typeof navigator !== 'undefined' && navigator.onLine ? 4 : 11,\n } = requestOptions;\n\n let lastError: any;\n\n for (let attempt = 1; attempt <= maxTries; attempt++) {\n try {\n const result = await attemptFn();\n recordSuccess(state);\n return result;\n } catch (error) {\n lastError = error;\n\n if (!shouldRetryFn(error, attempt)) {\n throw error;\n }\n\n recordFailure(state, requestOptions);\n\n if (attempt < maxTries) {\n const delay = Math.min(initialDelay * Math.pow(factor, attempt - 1), maxDelay);\n await new Promise(resolve => setTimeout(resolve, jitteredDelay(delay)));\n }\n }\n }\n\n throw lastError;\n}\n\nexport function createCoreApiClient(clientOptions: ApiClientOptions): ApiClient {\n function buildUrl(requestInit: ApiRequestInit): URL {\n const isLocalhost = clientOptions.apiUrl?.includes('localhost') || clientOptions.apiUrl?.includes('127.0.0.1');\n const { path } = requestInit;\n const { instanceType, domain, apiUrl, apiBasePath = '/api/auth' } = clientOptions;\n const domainInProd = instanceType === 'production' ? domain : '';\n\n let baseUrl: string;\n if (isLocalhost) {\n // For localhost, use http and the apiUrl directly\n baseUrl = apiUrl?.startsWith('http') ? apiUrl : `http://${apiUrl}`;\n } else {\n //const domainInProd = instanceType === 'production' ? domain : '';\n baseUrl = `https://${domainInProd || apiUrl}`;\n }\n\n const fullPath = `${apiBasePath}/${path}`.replace(/\\/+/g, '/'); \n return buildUrlUtil(\n {\n base: baseUrl,\n pathname: fullPath,\n searchParams: requestInit.search ? new URLSearchParams(requestInit.search) : undefined,\n },\n { stringify: false },\n );\n }\n\n async function makeRequest<T>(\n state: ClientState,\n init: ApiRequestInit,\n opts: ApiRequestOptions = {},\n ): Promise<ApiResponse<T>> {\n const requestInit = { ...init };\n const { method = 'GET', body } = requestInit;\n const requestOptions = { ...opts };\n\n requestInit.url = buildUrl({ ...requestInit });\n checkCircuitBreaker(state, requestOptions);\n\n const shouldContinue = await runBeforeRequestHooks(state);\n if (!shouldContinue) {\n const mockResponse = new Response('{}', {\n status: 200,\n }) as ApiResponse<T>;\n mockResponse.payload = { response: {} as T };\n await runAfterResponseHooks(state, mockResponse);\n return mockResponse;\n }\n\n const { timeoutMs } = requestOptions;\n\n const overwrittenRequestMethod = method === 'GET' ? 'GET' : 'POST';\n const url = requestInit.url.toString();\n\n console.log('Request URL:', url);\n\n requestInit.headers = new Headers(requestInit.headers);\n\n if (\n method !== 'GET' &&\n !(body instanceof FormData) &&\n !requestInit.headers.has('content-type')\n ) {\n requestInit.headers.set('content-type', 'application/json');\n }\n\n if (requestInit.headers.get('content-type') === 'application/x-www-form-urlencoded') {\n requestInit.body = body\n ? stringifyQueryParams(body as any as Record<string, string>, {\n keyEncoder: camelToSnake,\n })\n : body;\n } else if (requestInit.headers.get('content-type') === 'application/json' && body) {\n requestInit.body = typeof body === 'string' ? body : JSON.stringify(body);\n }\n\n const attemptRequest = async (): Promise<ApiResponse<T>> => {\n const controller = new AbortController();\n const timeoutId = timeoutMs\n ? setTimeout(() => {\n controller.abort();\n }, timeoutMs)\n : null;\n\n let response: Response;\n const fetchOpts: ApiRequestInit = {\n ...requestInit,\n credentials: 'include',\n method: overwrittenRequestMethod,\n };\n\n try {\n response = await fetch(url, fetchOpts);\n\n if (timeoutId) clearTimeout(timeoutId);\n\n let payload: ApiResponseJSON<T> | null = null;\n\n if (response.status === 204) {\n payload = null;\n } else {\n try {\n const json = await response.json();\n payload = json;\n } catch {\n payload = { response: {} as T };\n }\n }\n\n const apiResponse = response as ApiResponse<T>;\n apiResponse.payload = payload;\n\n await runAfterResponseHooks(state, apiResponse);\n\n return apiResponse;\n } catch (error: any) {\n if (timeoutId) clearTimeout(timeoutId);\n\n if (error.name === 'AbortError') {\n throw new TimeoutError();\n }\n\n throw new NetworkError(url, error);\n }\n };\n\n return retryWithBackoff(state, requestOptions, attemptRequest, (error, attempt) =>\n shouldRetry(\n state,\n requestOptions,\n error,\n overwrittenRequestMethod,\n attempt,\n requestOptions.maxTries || (typeof navigator !== 'undefined' && navigator.onLine ? 4 : 11),\n ),\n );\n }\n const state = createInitialState(clientOptions);\n\n return {\n onBeforeRequest: (hook: BeforeRequestHook) => addBeforeRequestHook(state, hook),\n onAfterResponse: (hook: AfterResponseHook) => addAfterResponseHook(state, hook),\n request: <T>(init: ApiRequestInit, opts: ApiRequestOptions = {}) =>\n makeRequest<T>(state, init, opts),\n };\n}\n"],"mappings":"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","names":["state"]}
@@ -1,10 +1,9 @@
1
1
  import { isValidBrowserOnline } from "@tern-secure/shared/browser";
2
- import { coreApiClient } from "../instance/coreApiClient";
3
2
  import { TernSecureAPIResponseError } from "./Error";
4
3
  class TernSecureBase {
5
4
  static ternsecure;
6
- static get apiUrl() {
7
- return TernSecureBase.ternsecure.getApiUrl();
5
+ static get apiClient() {
6
+ return TernSecureBase.ternsecure.getApiClient();
8
7
  }
9
8
  static get authCookieManager() {
10
9
  return this.ternsecure.authCookieManager();
@@ -18,13 +17,9 @@ class TernSecureBase {
18
17
  */
19
18
  static async fetchFromCoreApi(requestInit) {
20
19
  var _a;
21
- if (!TernSecureBase.apiUrl) {
22
- throw new Error("API URL is not defined. Make sure TernSecureAuth is properly initialized.");
23
- }
24
- const apiUrl = this.ternsecure.apiUrl;
25
20
  let apiResponse;
26
21
  try {
27
- apiResponse = await coreApiClient.request(requestInit, { apiUrl });
22
+ apiResponse = await TernSecureBase.apiClient.request(requestInit, { timeoutMs: 1e4 });
28
23
  } catch (error) {
29
24
  if (!isValidBrowserOnline()) {
30
25
  console.warn(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/resources/Base.ts"],"sourcesContent":["import { isValidBrowserOnline } from '@tern-secure/shared/browser';\nimport type { TernSecureApiErrorJSON } from '@tern-secure/types';\n\nimport type { ApiRequestInit, ApiResponse, ApiResponseJSON } from '../instance/coreApiClient';\nimport { coreApiClient } from '../instance/coreApiClient';\nimport { TernSecureAPIResponseError } from './Error';\nimport type { AuthCookieManager,TernSecureAuth } from './internal';\n\nexport type HTTPMethod =\n | 'CONNECT'\n | 'DELETE'\n | 'GET'\n | 'HEAD'\n | 'OPTIONS'\n | 'PATCH'\n | 'POST'\n | 'PUT'\n | 'TRACE';\n\nexport type PostMutateParams = {\n action?: string | undefined;\n body?: any;\n method?: HTTPMethod | undefined;\n path?: string;\n};\n\nexport abstract class TernSecureBase {\n static ternsecure: TernSecureAuth;\n\n static get apiUrl() {\n return TernSecureBase.ternsecure.getApiUrl();\n }\n\n static get authCookieManager(): AuthCookieManager | undefined {\n return this.ternsecure.authCookieManager();\n }\n protected get authCookieManager(): AuthCookieManager | undefined {\n return TernSecureBase.authCookieManager;\n }\n\n /**\n * Core method to fetch data from API endpoints using coreApiClient\n * This method handles the complete request lifecycle including error handling\n */\n static async fetchFromCoreApi(requestInit: ApiRequestInit): Promise<ApiResponseJSON<any> | null> {\n if (!TernSecureBase.apiUrl) {\n throw new Error('API URL is not defined. Make sure TernSecureAuth is properly initialized.');\n }\n\n const apiUrl = this.ternsecure.apiUrl;\n\n let apiResponse: ApiResponse<any>;\n try {\n apiResponse = await coreApiClient.request(requestInit, { apiUrl });\n } catch (error) {\n if (!isValidBrowserOnline()) {\n console.warn(error);\n return null;\n }\n throw error;\n }\n\n const { payload, status, statusText, headers } = apiResponse;\n\n if (headers) {\n const country = headers.get('x-country');\n this.ternsecure.__internal_setCountry(country ? country.toLowerCase() : null);\n }\n\n if (status >= 200 && status <= 299) {\n return payload;\n }\n\n if (status >= 400) {\n const errors = payload?.errors as TernSecureApiErrorJSON[];\n const message = errors?.[0]?.message;\n\n const apiResponseOptions: ConstructorParameters<typeof TernSecureAPIResponseError>[1] = {\n data: errors,\n status,\n };\n if (status === 429 && headers) {\n const retryAfter = headers.get('retry-After');\n if (retryAfter) {\n const value = parseInt(retryAfter, 10);\n if (!isNaN(value)) {\n apiResponseOptions.retryAfter = value;\n }\n }\n }\n\n throw new TernSecureAPIResponseError(message || statusText, apiResponseOptions);\n }\n\n return null;\n }\n\n /**\n * Convenience method for making POST requests\n */\n static async basePost(params: PostMutateParams): Promise<ApiResponseJSON<any> | null> {\n return this.fetchFromCoreApi({ ...params, method: 'POST' });\n }\n\n /**\n * Instance method to fetch data from API endpoints\n */\n protected async fetchFromCoreApi(\n requestInit: ApiRequestInit,\n ): Promise<ApiResponseJSON<any> | null> {\n return TernSecureBase.fetchFromCoreApi(requestInit);\n }\n\n /**\n * Instance method for making POST requests\n */\n protected async basePost(params: PostMutateParams): Promise<ApiResponseJSON<any> | null> {\n return TernSecureBase.basePost(params);\n }\n\n /**\n * Protected instance method for making POST requests with specific path and body\n * This is designed to be used by child classes like SignIn\n */\n protected async _post(params: PostMutateParams): Promise<ApiResponseJSON<any> | null> {\n return this.basePost({\n path: params.path,\n body: params.body\n });\n }\n\n static async makeApiRequest(requestInit: ApiRequestInit): Promise<ApiResponseJSON<any> | null> {\n return this.fetchFromCoreApi(requestInit);\n }\n\n protected async makeApiRequest(\n requestInit: ApiRequestInit,\n ): Promise<ApiResponseJSON<any> | null> {\n return this.fetchFromCoreApi(requestInit);\n }\n}\n"],"mappings":"AAAA,SAAS,4BAA4B;AAIrC,SAAS,qBAAqB;AAC9B,SAAS,kCAAkC;AAqBpC,MAAe,eAAe;AAAA,EACnC,OAAO;AAAA,EAEP,WAAW,SAAS;AAClB,WAAO,eAAe,WAAW,UAAU;AAAA,EAC7C;AAAA,EAEA,WAAW,oBAAmD;AAC5D,WAAO,KAAK,WAAW,kBAAkB;AAAA,EAC3C;AAAA,EACA,IAAc,oBAAmD;AAC/D,WAAO,eAAe;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,iBAAiB,aAAmE;AA5CnG;AA6CI,QAAI,CAAC,eAAe,QAAQ;AAC1B,YAAM,IAAI,MAAM,2EAA2E;AAAA,IAC7F;AAEA,UAAM,SAAS,KAAK,WAAW;AAE/B,QAAI;AACJ,QAAI;AACF,oBAAc,MAAM,cAAc,QAAQ,aAAa,EAAE,OAAO,CAAC;AAAA,IACnE,SAAS,OAAO;AACd,UAAI,CAAC,qBAAqB,GAAG;AAC3B,gBAAQ,KAAK,KAAK;AAClB,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAEA,UAAM,EAAE,SAAS,QAAQ,YAAY,QAAQ,IAAI;AAEjD,QAAI,SAAS;AACX,YAAM,UAAU,QAAQ,IAAI,WAAW;AACvC,WAAK,WAAW,sBAAsB,UAAU,QAAQ,YAAY,IAAI,IAAI;AAAA,IAC9E;AAEA,QAAI,UAAU,OAAO,UAAU,KAAK;AAClC,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,KAAK;AACjB,YAAM,SAAS,mCAAS;AACxB,YAAM,WAAU,sCAAS,OAAT,mBAAa;AAE7B,YAAM,qBAAkF;AAAA,QACtF,MAAM;AAAA,QACN;AAAA,MACF;AACA,UAAI,WAAW,OAAO,SAAS;AAC7B,cAAM,aAAa,QAAQ,IAAI,aAAa;AAC5C,YAAI,YAAY;AACd,gBAAM,QAAQ,SAAS,YAAY,EAAE;AACrC,cAAI,CAAC,MAAM,KAAK,GAAG;AACjB,+BAAmB,aAAa;AAAA,UAClC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,IAAI,2BAA2B,WAAW,YAAY,kBAAkB;AAAA,IAChF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAS,QAAgE;AACpF,WAAO,KAAK,iBAAiB,EAAE,GAAG,QAAQ,QAAQ,OAAO,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,iBACd,aACsC;AACtC,WAAO,eAAe,iBAAiB,WAAW;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,SAAS,QAAgE;AACvF,WAAO,eAAe,SAAS,MAAM;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAgB,MAAM,QAAgE;AACpF,WAAO,KAAK,SAAS;AAAA,MACnB,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,eAAe,aAAmE;AAC7F,WAAO,KAAK,iBAAiB,WAAW;AAAA,EAC1C;AAAA,EAEA,MAAgB,eACd,aACsC;AACtC,WAAO,KAAK,iBAAiB,WAAW;AAAA,EAC1C;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/resources/Base.ts"],"sourcesContent":["import { isValidBrowserOnline } from '@tern-secure/shared/browser';\nimport type { TernSecureApiErrorJSON } from '@tern-secure/types';\n\nimport type { ApiRequestInit, ApiResponse, ApiResponseJSON } from '../instance/coreApiClient';\n//import { coreApiClient} from '../instance/coreApiClient';\nimport { TernSecureAPIResponseError } from './Error';\nimport type { AuthCookieManager,TernSecureAuth } from './internal';\n\nexport type HTTPMethod =\n | 'CONNECT'\n | 'DELETE'\n | 'GET'\n | 'HEAD'\n | 'OPTIONS'\n | 'PATCH'\n | 'POST'\n | 'PUT'\n | 'TRACE';\n\nexport type PostMutateParams = {\n action?: string | undefined;\n body?: any;\n method?: HTTPMethod | undefined;\n path?: string;\n};\n\nexport abstract class TernSecureBase {\n static ternsecure: TernSecureAuth;\n\n static get apiClient() {\n return TernSecureBase.ternsecure.getApiClient();\n }\n\n static get authCookieManager(): AuthCookieManager | undefined {\n return this.ternsecure.authCookieManager();\n }\n protected get authCookieManager(): AuthCookieManager | undefined {\n return TernSecureBase.authCookieManager;\n }\n\n /**\n * Core method to fetch data from API endpoints using coreApiClient\n * This method handles the complete request lifecycle including error handling\n */\n static async fetchFromCoreApi(requestInit: ApiRequestInit): Promise<ApiResponseJSON<any> | null> {\n\n let apiResponse: ApiResponse<any>;\n try {\n apiResponse = await TernSecureBase.apiClient.request(requestInit, { timeoutMs: 10000 });\n } catch (error) {\n if (!isValidBrowserOnline()) {\n console.warn(error);\n return null;\n }\n throw error;\n }\n\n const { payload, status, statusText, headers } = apiResponse;\n\n if (headers) {\n const country = headers.get('x-country');\n this.ternsecure.__internal_setCountry(country ? country.toLowerCase() : null);\n }\n\n if (status >= 200 && status <= 299) {\n return payload;\n }\n\n if (status >= 400) {\n const errors = payload?.errors as TernSecureApiErrorJSON[];\n const message = errors?.[0]?.message;\n\n const apiResponseOptions: ConstructorParameters<typeof TernSecureAPIResponseError>[1] = {\n data: errors,\n status,\n };\n if (status === 429 && headers) {\n const retryAfter = headers.get('retry-After');\n if (retryAfter) {\n const value = parseInt(retryAfter, 10);\n if (!isNaN(value)) {\n apiResponseOptions.retryAfter = value;\n }\n }\n }\n\n throw new TernSecureAPIResponseError(message || statusText, apiResponseOptions);\n }\n\n return null;\n }\n\n /**\n * Convenience method for making POST requests\n */\n static async basePost(params: PostMutateParams): Promise<ApiResponseJSON<any> | null> {\n return this.fetchFromCoreApi({ ...params, method: 'POST' });\n }\n\n /**\n * Instance method to fetch data from API endpoints\n */\n protected async fetchFromCoreApi(\n requestInit: ApiRequestInit,\n ): Promise<ApiResponseJSON<any> | null> {\n return TernSecureBase.fetchFromCoreApi(requestInit);\n }\n\n /**\n * Instance method for making POST requests\n */\n protected async basePost(params: PostMutateParams): Promise<ApiResponseJSON<any> | null> {\n return TernSecureBase.basePost(params);\n }\n\n /**\n * Protected instance method for making POST requests with specific path and body\n * This is designed to be used by child classes like SignIn\n */\n protected async _post(params: PostMutateParams): Promise<ApiResponseJSON<any> | null> {\n return this.basePost({\n path: params.path,\n body: params.body\n });\n }\n\n static async makeApiRequest(requestInit: ApiRequestInit): Promise<ApiResponseJSON<any> | null> {\n return this.fetchFromCoreApi(requestInit);\n }\n\n protected async makeApiRequest(\n requestInit: ApiRequestInit,\n ): Promise<ApiResponseJSON<any> | null> {\n return this.fetchFromCoreApi(requestInit);\n }\n}\n"],"mappings":"AAAA,SAAS,4BAA4B;AAKrC,SAAS,kCAAkC;AAqBpC,MAAe,eAAe;AAAA,EACnC,OAAO;AAAA,EAEP,WAAW,YAAY;AACrB,WAAO,eAAe,WAAW,aAAa;AAAA,EAChD;AAAA,EAEA,WAAW,oBAAmD;AAC5D,WAAO,KAAK,WAAW,kBAAkB;AAAA,EAC3C;AAAA,EACA,IAAc,oBAAmD;AAC/D,WAAO,eAAe;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,iBAAiB,aAAmE;AA5CnG;AA8CI,QAAI;AACJ,QAAI;AACF,oBAAc,MAAM,eAAe,UAAU,QAAQ,aAAa,EAAE,WAAW,IAAM,CAAC;AAAA,IACxF,SAAS,OAAO;AACd,UAAI,CAAC,qBAAqB,GAAG;AAC3B,gBAAQ,KAAK,KAAK;AAClB,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAEA,UAAM,EAAE,SAAS,QAAQ,YAAY,QAAQ,IAAI;AAEjD,QAAI,SAAS;AACX,YAAM,UAAU,QAAQ,IAAI,WAAW;AACvC,WAAK,WAAW,sBAAsB,UAAU,QAAQ,YAAY,IAAI,IAAI;AAAA,IAC9E;AAEA,QAAI,UAAU,OAAO,UAAU,KAAK;AAClC,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,KAAK;AACjB,YAAM,SAAS,mCAAS;AACxB,YAAM,WAAU,sCAAS,OAAT,mBAAa;AAE7B,YAAM,qBAAkF;AAAA,QACtF,MAAM;AAAA,QACN;AAAA,MACF;AACA,UAAI,WAAW,OAAO,SAAS;AAC7B,cAAM,aAAa,QAAQ,IAAI,aAAa;AAC5C,YAAI,YAAY;AACd,gBAAM,QAAQ,SAAS,YAAY,EAAE;AACrC,cAAI,CAAC,MAAM,KAAK,GAAG;AACjB,+BAAmB,aAAa;AAAA,UAClC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,IAAI,2BAA2B,WAAW,YAAY,kBAAkB;AAAA,IAChF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAS,QAAgE;AACpF,WAAO,KAAK,iBAAiB,EAAE,GAAG,QAAQ,QAAQ,OAAO,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,iBACd,aACsC;AACtC,WAAO,eAAe,iBAAiB,WAAW;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,SAAS,QAAgE;AACvF,WAAO,eAAe,SAAS,MAAM;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAgB,MAAM,QAAgE;AACpF,WAAO,KAAK,SAAS;AAAA,MACnB,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,eAAe,aAAmE;AAC7F,WAAO,KAAK,iBAAiB,WAAW;AAAA,EAC1C;AAAA,EAEA,MAAgB,eACd,aACsC;AACtC,WAAO,KAAK,iBAAiB,WAAW;AAAA,EAC1C;AACF;","names":[]}
@@ -1,71 +1,57 @@
1
+ import { camelToSnake } from "@tern-secure/shared/caseUtils";
2
+ import { joinPaths } from "./path";
3
+ import { getQueryParams } from "./querystring";
4
+ const DUMMY_URL_BASE = "http://ternsecure-dummy";
1
5
  function buildURL(params, options = {}) {
2
6
  const { base, hashPath, hashSearch, searchParams, hashSearchParams, ...rest } = params;
3
- const { stringify = true, skipOrigin = false } = options;
4
- const baseFallback = typeof window !== "undefined" && window.location ? window.location.href : "http://react-native-fake-base-url";
5
- const appendToUrlSearchParams = (target, source) => {
6
- if (!source) {
7
- return;
8
- }
9
- if (source instanceof URLSearchParams) {
10
- source.forEach((value, key) => {
11
- target.set(key, value);
12
- });
13
- } else if (typeof source === "object") {
14
- Object.entries(source).forEach(([key, value]) => {
15
- target.set(key, String(value));
16
- });
17
- }
18
- };
19
- try {
20
- const url = new URL(base || "", baseFallback);
21
- if (searchParams) {
22
- searchParams.forEach((value, key) => {
7
+ const { stringify, skipOrigin } = options;
8
+ let baseFallback = "";
9
+ if (typeof window !== "undefined" && !!window.location) {
10
+ baseFallback = window.location.href;
11
+ } else {
12
+ baseFallback = "http://react-native-fake-base-url";
13
+ }
14
+ const url = new URL(base || "", baseFallback);
15
+ if (searchParams instanceof URLSearchParams) {
16
+ searchParams.forEach((value, key) => {
17
+ if (value !== null && value !== void 0) {
23
18
  url.searchParams.set(key, value);
24
- });
19
+ }
20
+ });
21
+ }
22
+ Object.assign(url, rest);
23
+ if (hashPath || hashSearch || hashSearchParams) {
24
+ const dummyUrlForHash = new URL(DUMMY_URL_BASE + url.hash.substring(1));
25
+ dummyUrlForHash.pathname = joinPaths(dummyUrlForHash.pathname, hashPath || "");
26
+ const searchParamsFromHashSearchString = getQueryParams(hashSearch || "");
27
+ for (const [key, val] of Object.entries(searchParamsFromHashSearchString)) {
28
+ dummyUrlForHash.searchParams.append(key, val);
25
29
  }
26
- if (hashPath || hashSearch || hashSearchParams) {
27
- const finalHashPath = hashPath || "";
28
- const queryForHash = new URLSearchParams(hashSearch || "");
29
- if (hashSearchParams) {
30
- if (Array.isArray(hashSearchParams)) {
31
- hashSearchParams.forEach((item) => appendToUrlSearchParams(queryForHash, item));
32
- } else {
33
- appendToUrlSearchParams(queryForHash, hashSearchParams);
30
+ const finalHashPath = hashPath || "";
31
+ const queryForHash = new URLSearchParams(hashSearch || "");
32
+ if (hashSearchParams) {
33
+ const paramsArr = Array.isArray(hashSearchParams) ? hashSearchParams : [hashSearchParams];
34
+ for (const _params of paramsArr) {
35
+ if (!(_params instanceof URLSearchParams) && typeof _params !== "object") {
36
+ continue;
34
37
  }
35
- }
36
- const hashQueryString = queryForHash.toString();
37
- let combinedHashString = "";
38
- if (finalHashPath) {
39
- combinedHashString = finalHashPath;
40
- if (hashQueryString) {
41
- if (combinedHashString.includes("?")) {
42
- combinedHashString += "&" + hashQueryString;
43
- } else {
44
- combinedHashString += "?" + hashQueryString;
38
+ const params2 = new URLSearchParams(_params);
39
+ params2.forEach((value, key) => {
40
+ if (value !== null && value !== void 0) {
41
+ dummyUrlForHash.searchParams.set(camelToSnake(key), value);
45
42
  }
46
- }
47
- } else {
48
- if (hashQueryString) {
49
- combinedHashString = hashQueryString;
50
- }
43
+ });
51
44
  }
52
- if (combinedHashString) {
53
- url.hash = combinedHashString;
54
- }
55
- }
56
- if (stringify) {
57
- return skipOrigin ? url.href.replace(url.origin, "") : url.href;
58
45
  }
59
- return url;
60
- } catch (error) {
61
- console.error("[TernSecure] Error building URL:", error);
62
- const fallbackUrlString = base || "/";
63
- if (stringify) {
64
- return fallbackUrlString;
65
- } else {
66
- return new URL(fallbackUrlString, baseFallback);
46
+ const newHash = dummyUrlForHash.href.replace(DUMMY_URL_BASE, "");
47
+ if (newHash !== "/") {
48
+ url.hash = newHash;
67
49
  }
68
50
  }
51
+ if (stringify) {
52
+ return skipOrigin ? url.href.replace(url.origin, "") : url.href;
53
+ }
54
+ return url;
69
55
  }
70
56
  const constructFullUrl = (path) => {
71
57
  if (typeof window === "undefined") return path;
@@ -82,7 +68,13 @@ const hasRedirectLoop = (currentPath, redirectPath) => {
82
68
  return cleanCurrentPath === cleanRedirectPath;
83
69
  };
84
70
  const urlWithRedirect = (options) => {
85
- const { signInUrl, signInPathParam = "/sign-in", currentPath, signUpUrl, signUpPathParam = "/sign-up" } = options;
71
+ const {
72
+ signInUrl,
73
+ signInPathParam = "/sign-in",
74
+ currentPath,
75
+ signUpUrl,
76
+ signUpPathParam = "/sign-up"
77
+ } = options;
86
78
  const baseUrl = window.location.origin;
87
79
  if (typeof window === "undefined") {
88
80
  return signInUrl;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/construct.ts"],"sourcesContent":["//v2: redict with taking priority from the sign-in page\n\nexport type constructUrlWithRedirectProps = {\n signInUrl: string;\n signInPathParam?: string;\n currentPath: string;\n signUpUrl?: string;\n signUpPathParam?: string;\n};\n\ninterface BuildURLParams extends Partial<URL> {\n base?: string;\n hashPath?: string;\n hashSearch?: string;\n hashSearchParams?: URLSearchParams | Record<string, string> | Array<URLSearchParams | Record<string, string>>;\n}\n\ninterface BuildURLOptions<T> {\n skipOrigin?: boolean;\n stringify?: T;\n}\n\n/**\n *\n * buildURL(params: URLParams, options: BuildURLOptions): string\n *\n * Builds a URL safely by using the native URL() constructor. It can\n * also build a secondary path and search URL that lives inside the hash\n * of the main URL. For example:\n *\n * https://foo.com/bar?qux=42#/hash-bar?hash-qux=42\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param {BuildURLParams} params\n * @param {BuildURLOptions} options\n * @returns {URL | string} Returns the URL href\n */\nexport function buildURL<B extends boolean>(\n params: BuildURLParams,\n options?: BuildURLOptions<B>,\n): B extends true ? string : URL;\n\n/**\n * Builds a URL from given parameters, handling search and hash parameters\n * @param params - The parameters to construct the URL\n * @param options - Options for building the URL\n * @returns The constructed URL as a string or URL object\n */\nexport function buildURL(params: BuildURLParams, options: BuildURLOptions<boolean> = {}): URL | string {\n const { base, hashPath, hashSearch, searchParams, hashSearchParams, ...rest} = params;\n const { stringify = true, skipOrigin = false } = options;\n\n const baseFallback =\n typeof window !== 'undefined' && window.location ? window.location.href : 'http://react-native-fake-base-url';\n\n // Helper function to append parameters to a URLSearchParams object\n const appendToUrlSearchParams = (\n target: URLSearchParams,\n source: URLSearchParams | Record<string, string> | undefined | null,\n ) => {\n if (!source) {\n return;\n }\n if (source instanceof URLSearchParams) {\n source.forEach((value, key) => {\n target.set(key, value);\n });\n } else if (typeof source === 'object') {\n Object.entries(source).forEach(([key, value]) => {\n target.set(key, String(value));\n });\n }\n };\n\n try {\n const url = new URL(base || '', baseFallback);\n\n // Handle search parameters\n // params.searchParams comes from Partial<URL>, so it's URLSearchParams | undefined\n if (searchParams) {\n searchParams.forEach((value, key) => {\n url.searchParams.set(key, value);\n });\n }\n\n // Handle hash-related parameters\n if (hashPath || hashSearch || hashSearchParams) {\n const finalHashPath = hashPath || '';\n const queryForHash = new URLSearchParams(hashSearch || '');\n\n if (hashSearchParams) {\n if (Array.isArray(hashSearchParams)) {\n hashSearchParams.forEach(item => appendToUrlSearchParams(queryForHash, item));\n } else {\n appendToUrlSearchParams(queryForHash, hashSearchParams);\n }\n }\n\n const hashQueryString = queryForHash.toString();\n let combinedHashString = '';\n\n if (finalHashPath) {\n combinedHashString = finalHashPath;\n if (hashQueryString) {\n if (combinedHashString.includes('?')) {\n combinedHashString += '&' + hashQueryString;\n } else {\n combinedHashString += '?' + hashQueryString;\n }\n }\n } else {\n // No hashPath\n if (hashQueryString) {\n // If only query, it forms the hash content directly.\n // e.g. \"param=value\" or \"?param=value\" are both valid after '#'\n combinedHashString = hashQueryString;\n }\n }\n\n if (combinedHashString) {\n url.hash = combinedHashString;\n }\n }\n\n if (stringify) {\n return skipOrigin ? url.href.replace(url.origin, '') : url.href;\n }\n return url;\n } catch (error) {\n console.error('[TernSecure] Error building URL:', error);\n const fallbackUrlString = base || '/';\n if (stringify) {\n return fallbackUrlString;\n } else {\n // Attempt to create a URL object for the fallback\n return new URL(fallbackUrlString, baseFallback);\n }\n }\n}\n\n/**\n * Constructs a full URL with the current origin\n * @param path - The path to construct the URL for\n * @returns The full URL with origin\n */\nexport const constructFullUrl = (path: string) => {\n if (typeof window === 'undefined') return path;\n const baseUrl = window.location.origin;\n if (path.startsWith('http')) {\n return path;\n }\n return `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`;\n};\n\n/**\n * Checks if the current URL has a redirect loop\n * @param currentPath - The current pathname\n * @param redirectPath - The path we're trying to redirect to\n * @returns boolean indicating if there's a redirect loop\n */\nexport const hasRedirectLoop = (currentPath: string, redirectPath: string): boolean => {\n if (!currentPath || !redirectPath) return false;\n\n // Remove any query parameters for comparison\n const cleanCurrentPath = currentPath.split('?')[0];\n const cleanRedirectPath = redirectPath.split('?')[0];\n\n return cleanCurrentPath === cleanRedirectPath;\n};\n\nexport const urlWithRedirect = (options: constructUrlWithRedirectProps): string => {\n const { signInUrl, signInPathParam = '/sign-in', currentPath, signUpUrl, signUpPathParam = '/sign-up' } = options;\n\n const baseUrl = window.location.origin;\n\n if (typeof window === 'undefined') {\n return signInUrl;\n }\n\n const url = new URL(signInUrl, baseUrl);\n\n if (!currentPath.includes(signInPathParam) && !currentPath.includes(signUpPathParam)) {\n url.searchParams.set('redirect', currentPath);\n }\n\n return url.toString();\n};\n\n/**\n * Stores the current path before signing out\n */\nexport const storePreviousPath = (path: string): void => {\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('previousPath', path);\n }\n};\n\n/**\n * Gets the stored previous path\n */\nexport const getPreviousPath = (): string | null => {\n if (typeof window !== 'undefined') {\n return sessionStorage.getItem('previousPath');\n }\n return null;\n};\n\n/**\n * Gets a validated redirect URL ensuring it's from the same origin\n * @param redirectUrl - The URL to validate\n * @param searchParams - The search parameters to check for redirect\n * @returns A validated redirect URL\n */\nexport const getValidRedirectUrl = (searchParams: URLSearchParams, configuredRedirect?: string): string => {\n // Check URL search param first (highest priority)\n const urlRedirect = searchParams.get('redirect');\n if (urlRedirect) {\n return validateUrl(urlRedirect);\n }\n\n // Then check configured redirect (for first visits)\n if (configuredRedirect) {\n return validateUrl(configuredRedirect);\n }\n\n // Default fallback\n return '/';\n};\n\n/**\n * Validates and sanitizes URLs\n */\nconst validateUrl = (url: string): string => {\n try {\n // For absolute URLs\n if (url.startsWith('http')) {\n const urlObj = new URL(url);\n if (typeof window !== 'undefined' && urlObj.origin !== window.location.origin) {\n return '/';\n }\n }\n\n // For relative URLs\n return '/';\n } catch {\n return '/';\n }\n};\n\nexport function toURL(url: string | URL): URL {\n return new URL(url.toString(), window.location.origin);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/construct.ts"],"sourcesContent":["import { camelToSnake } from '@tern-secure/shared/caseUtils'\n\nimport { joinPaths } from './path';\nimport { getQueryParams } from './querystring';\n\nconst DUMMY_URL_BASE = 'http://ternsecure-dummy';\n\nexport type constructUrlWithRedirectProps = {\n signInUrl: string;\n signInPathParam?: string;\n currentPath: string;\n signUpUrl?: string;\n signUpPathParam?: string;\n};\n\ninterface BuildURLParams extends Partial<URL> {\n base?: string;\n hashPath?: string;\n hashSearch?: string;\n hashSearchParams?:\n | URLSearchParams\n | Record<string, string>\n | Array<URLSearchParams | Record<string, string>>;\n}\n\ninterface BuildURLOptions<T> {\n skipOrigin?: boolean;\n stringify?: T;\n}\n\n/**\n *\n * buildURL(params: URLParams, options: BuildURLOptions): string\n *\n * Builds a URL safely by using the native URL() constructor. It can\n * also build a secondary path and search URL that lives inside the hash\n * of the main URL. For example:\n *\n * https://foo.com/bar?qux=42#/hash-bar?hash-qux=42\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param {BuildURLParams} params\n * @param {BuildURLOptions} options\n * @returns {URL | string} Returns the URL href\n */\nexport function buildURL<B extends boolean>(\n params: BuildURLParams,\n options?: BuildURLOptions<B>,\n): B extends true ? string : URL;\n\n/**\n * Builds a URL from given parameters, handling search and hash parameters\n * @param params - The parameters to construct the URL\n * @param options - Options for building the URL\n * @returns The constructed URL as a string or URL object\n */\nexport function buildURL(\n params: BuildURLParams,\n options: BuildURLOptions<boolean> = {},\n): URL | string {\n const { base, hashPath, hashSearch, searchParams, hashSearchParams, ...rest } = params;\n const { stringify, skipOrigin } = options;\n\n let baseFallback = '';\n if (typeof window !== 'undefined' && !!window.location) {\n baseFallback = window.location.href;\n } else {\n baseFallback = 'http://react-native-fake-base-url';\n }\n\n const url = new URL(base || '', baseFallback);\n\n // Handle search parameters\n // params.searchParams comes from Partial<URL>, so it's URLSearchParams | undefined\n if (searchParams instanceof URLSearchParams) {\n searchParams.forEach((value, key) => {\n if (value !== null && value !== undefined) {\n url.searchParams.set(key, value); //camelToSnake(key), value\n }\n });\n }\n\n Object.assign(url, rest);\n\n // Handle hash-related parameters\n if (hashPath || hashSearch || hashSearchParams) {\n const dummyUrlForHash = new URL(DUMMY_URL_BASE + url.hash.substring(1));\n\n dummyUrlForHash.pathname = joinPaths(dummyUrlForHash.pathname, hashPath || '');\n\n const searchParamsFromHashSearchString = getQueryParams(hashSearch || '');\n\n for (const [key, val] of Object.entries(searchParamsFromHashSearchString)) {\n dummyUrlForHash.searchParams.append(key, val);\n }\n const finalHashPath = hashPath || '';\n const queryForHash = new URLSearchParams(hashSearch || '');\n\n if (hashSearchParams) {\n const paramsArr = Array.isArray(hashSearchParams) ? hashSearchParams : [hashSearchParams];\n for (const _params of paramsArr) {\n if (!(_params instanceof URLSearchParams) && typeof _params !== 'object') {\n continue;\n }\n const params = new URLSearchParams(_params);\n params.forEach((value, key) => {\n if (value !== null && value !== undefined) {\n dummyUrlForHash.searchParams.set(camelToSnake(key), value);\n }\n });\n }\n }\n\n const newHash = dummyUrlForHash.href.replace(DUMMY_URL_BASE, '');\n if (newHash !== '/') {\n // Assign them to the hash of the main url\n url.hash = newHash;\n }\n }\n\n if (stringify) {\n return skipOrigin ? url.href.replace(url.origin, '') : url.href;\n }\n return url;\n}\n\n/**\n * Constructs a full URL with the current origin\n * @param path - The path to construct the URL for\n * @returns The full URL with origin\n */\nexport const constructFullUrl = (path: string) => {\n if (typeof window === 'undefined') return path;\n const baseUrl = window.location.origin;\n if (path.startsWith('http')) {\n return path;\n }\n return `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`;\n};\n\n/**\n * Checks if the current URL has a redirect loop\n * @param currentPath - The current pathname\n * @param redirectPath - The path we're trying to redirect to\n * @returns boolean indicating if there's a redirect loop\n */\nexport const hasRedirectLoop = (currentPath: string, redirectPath: string): boolean => {\n if (!currentPath || !redirectPath) return false;\n\n // Remove any query parameters for comparison\n const cleanCurrentPath = currentPath.split('?')[0];\n const cleanRedirectPath = redirectPath.split('?')[0];\n\n return cleanCurrentPath === cleanRedirectPath;\n};\n\nexport const urlWithRedirect = (options: constructUrlWithRedirectProps): string => {\n const {\n signInUrl,\n signInPathParam = '/sign-in',\n currentPath,\n signUpUrl,\n signUpPathParam = '/sign-up',\n } = options;\n\n const baseUrl = window.location.origin;\n\n if (typeof window === 'undefined') {\n return signInUrl;\n }\n\n const url = new URL(signInUrl, baseUrl);\n\n if (!currentPath.includes(signInPathParam) && !currentPath.includes(signUpPathParam)) {\n url.searchParams.set('redirect', currentPath);\n }\n\n return url.toString();\n};\n\n/**\n * Stores the current path before signing out\n */\nexport const storePreviousPath = (path: string): void => {\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('previousPath', path);\n }\n};\n\n/**\n * Gets the stored previous path\n */\nexport const getPreviousPath = (): string | null => {\n if (typeof window !== 'undefined') {\n return sessionStorage.getItem('previousPath');\n }\n return null;\n};\n\n/**\n * Gets a validated redirect URL ensuring it's from the same origin\n * @param redirectUrl - The URL to validate\n * @param searchParams - The search parameters to check for redirect\n * @returns A validated redirect URL\n */\nexport const getValidRedirectUrl = (\n searchParams: URLSearchParams,\n configuredRedirect?: string,\n): string => {\n // Check URL search param first (highest priority)\n const urlRedirect = searchParams.get('redirect');\n if (urlRedirect) {\n return validateUrl(urlRedirect);\n }\n\n // Then check configured redirect (for first visits)\n if (configuredRedirect) {\n return validateUrl(configuredRedirect);\n }\n\n // Default fallback\n return '/';\n};\n\n/**\n * Validates and sanitizes URLs\n */\nconst validateUrl = (url: string): string => {\n try {\n // For absolute URLs\n if (url.startsWith('http')) {\n const urlObj = new URL(url);\n if (typeof window !== 'undefined' && urlObj.origin !== window.location.origin) {\n return '/';\n }\n }\n\n // For relative URLs\n return '/';\n } catch {\n return '/';\n }\n};\n\nexport function toURL(url: string | URL): URL {\n return new URL(url.toString(), window.location.origin);\n}\n"],"mappings":"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","names":["params"]}
@@ -0,0 +1,9 @@
1
+ const SEPARATOR = "/";
2
+ const MULTIPLE_SEPARATOR_REGEX = new RegExp(SEPARATOR + "{1,}", "g");
3
+ function joinPaths(a, b) {
4
+ return [a, b].filter((p) => p).join(SEPARATOR).replace(MULTIPLE_SEPARATOR_REGEX, SEPARATOR);
5
+ }
6
+ export {
7
+ joinPaths
8
+ };
9
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/path.ts"],"sourcesContent":["const SEPARATOR = '/';\nconst MULTIPLE_SEPARATOR_REGEX = new RegExp(SEPARATOR + '{1,}', 'g');\n\ntype PathString = string | null | undefined;\n\nexport function joinPaths(a: PathString, b: PathString): string {\n return [a, b]\n .filter(p => p)\n .join(SEPARATOR)\n .replace(MULTIPLE_SEPARATOR_REGEX, SEPARATOR);\n}\n"],"mappings":"AAAA,MAAM,YAAY;AAClB,MAAM,2BAA2B,IAAI,OAAO,YAAY,QAAQ,GAAG;AAI5D,SAAS,UAAU,GAAe,GAAuB;AAC9D,SAAO,CAAC,GAAG,CAAC,EACT,OAAO,OAAK,CAAC,EACb,KAAK,SAAS,EACd,QAAQ,0BAA0B,SAAS;AAChD;","names":[]}
@@ -1,6 +1,7 @@
1
1
  import type { InstanceType, ListenerCallback, SignedInSession, SignInRedirectOptions, SignInResource, SignInResponseTree, SignOut, SignUpRedirectOptions, SignUpResource, TernSecureAuth as TernSecureAuthInterface, TernSecureAuthOptions, TernSecureSDK, TernSecureUser, UnsubscribeCallback } from '@tern-secure/types';
2
2
  import type { Auth as TernAuth } from 'firebase/auth';
3
3
  import { AuthCookieManager } from '../resources/internal';
4
+ import { type ApiClient } from './c_coreApiClient';
4
5
  export declare function inBrowser(): boolean;
5
6
  export { TernAuth };
6
7
  /**
@@ -30,10 +31,10 @@ export declare class TernSecureAuth implements TernSecureAuthInterface {
30
31
  get sdkMetadata(): TernSecureSDK;
31
32
  get requiresVerification(): boolean;
32
33
  get apiUrl(): string;
33
- getApiUrl: () => string;
34
34
  get domain(): string;
35
35
  get instanceType(): InstanceType | undefined;
36
36
  constructor(options?: TernSecureAuthOptions);
37
+ getApiClient: () => ApiClient;
37
38
  setLoading(isLoading: boolean): void;
38
39
  authCookieManager(): AuthCookieManager | undefined;
39
40
  static getorCreateInstance(options?: TernSecureAuthOptions): TernSecureAuth;
@@ -1 +1 @@
1
- {"version":3,"file":"TernAuth.d.ts","sourceRoot":"","sources":["../../../src/instance/TernAuth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TernAuth.d.ts","sourceRoot":"","sources":["../../../src/instance/TernAuth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { InstanceType, TernSecureApiErrorJSON } from '@tern-secure/types';
2
+ export type HTTPMethod = 'CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE';
3
+ export type ApiRequestInit = RequestInit & {
4
+ path?: string;
5
+ search?: ConstructorParameters<typeof URLSearchParams>[0];
6
+ sessionId?: string;
7
+ url?: URL;
8
+ };
9
+ export interface ApiResponseJSON<T> {
10
+ response: T;
11
+ errors?: TernSecureApiErrorJSON[];
12
+ }
13
+ export type ApiResponse<T> = Response & {
14
+ payload: ApiResponseJSON<T> | null;
15
+ };
16
+ export type ApiRequestCallback<T> = (request: ApiRequestInit, response?: ApiResponse<T>) => unknown;
17
+ export interface ApiRequestOptions {
18
+ timeoutMs?: number;
19
+ maxTries?: number;
20
+ initialDelay?: number;
21
+ factor?: number;
22
+ maxDelay?: number;
23
+ failureThreshold?: number;
24
+ recoveryTimeoutMs?: number;
25
+ }
26
+ export interface ApiClientOptions {
27
+ domain?: string;
28
+ apiUrl?: string;
29
+ frontendApi?: string;
30
+ instanceType?: InstanceType;
31
+ apiBasePath?: string;
32
+ }
33
+ export interface ApiClient {
34
+ onBeforeRequest: (hook: BeforeRequestHook) => void;
35
+ onAfterResponse: (hook: AfterResponseHook) => void;
36
+ request: <T>(init: ApiRequestInit, opts?: ApiRequestOptions) => Promise<ApiResponse<T>>;
37
+ }
38
+ export type BeforeRequestHook = () => boolean | Promise<boolean>;
39
+ export type AfterResponseHook = (response: ApiResponse<any>) => boolean | Promise<boolean>;
40
+ export declare class NetworkError extends Error {
41
+ url: string;
42
+ original: Error;
43
+ constructor(url: string, original: Error);
44
+ }
45
+ export declare class TimeoutError extends Error {
46
+ constructor();
47
+ }
48
+ export declare class CircuitOpenError extends Error {
49
+ constructor();
50
+ }
51
+ export declare class HTTPError extends Error {
52
+ status: number;
53
+ url: string;
54
+ body?: any | undefined;
55
+ constructor(status: number, url: string, body?: any | undefined);
56
+ }
57
+ export declare function createCoreApiClient(clientOptions: ApiClientOptions): ApiClient;
58
+ //# sourceMappingURL=c_coreApiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c_coreApiClient.d.ts","sourceRoot":"","sources":["../../../src/instance/c_coreApiClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAI/E,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,KAAK,GACL,MAAM,GACN,SAAS,GACT,OAAO,GACP,MAAM,GACN,KAAK,GACL,OAAO,CAAC;AAEZ,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,qBAAqB,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,GAAG,CAAC;CACX,CAAC;AAEF,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC;IACZ,MAAM,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACnC;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,QAAQ,GAAG;IAAE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC;AAEpG,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,eAAe,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,eAAe,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CACzF;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AACjE,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAG3F,qBAAa,YAAa,SAAQ,KAAK;IAE5B,GAAG,EAAE,MAAM;IACX,QAAQ,EAAE,KAAK;gBADf,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,KAAK;CAKzB;AAED,qBAAa,YAAa,SAAQ,KAAK;;CAKtC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;;CAK1C;AAED,qBAAa,SAAU,SAAQ,KAAK;IAEzB,MAAM,EAAE,MAAM;IACd,GAAG,EAAE,MAAM;IACX,IAAI,CAAC,EAAE,GAAG;gBAFV,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,GAAG,YAAA;CAKpB;AA4ID,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,gBAAgB,GAAG,SAAS,CAiJ9E"}
@@ -9,7 +9,7 @@ export type PostMutateParams = {
9
9
  };
10
10
  export declare abstract class TernSecureBase {
11
11
  static ternsecure: TernSecureAuth;
12
- static get apiUrl(): string;
12
+ static get apiClient(): import("../instance/c_coreApiClient").ApiClient;
13
13
  static get authCookieManager(): AuthCookieManager | undefined;
14
14
  protected get authCookieManager(): AuthCookieManager | undefined;
15
15
  /**