@tern-secure/backend 1.1.6 → 1.1.8

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 (159) hide show
  1. package/admin/package.json +5 -0
  2. package/dist/adapters/PostgresAdapter.d.ts +8 -0
  3. package/dist/adapters/PostgresAdapter.d.ts.map +1 -0
  4. package/dist/adapters/RedisAdapter.d.ts +10 -0
  5. package/dist/adapters/RedisAdapter.d.ts.map +1 -0
  6. package/dist/adapters/index.d.ts +13 -0
  7. package/dist/adapters/index.d.ts.map +1 -0
  8. package/dist/adapters/types.d.ts +30 -0
  9. package/dist/adapters/types.d.ts.map +1 -0
  10. package/dist/admin/gemini_sessionTernSecure.d.ts +10 -0
  11. package/dist/admin/gemini_sessionTernSecure.d.ts.map +1 -0
  12. package/dist/admin/index.d.ts +8 -0
  13. package/dist/admin/index.d.ts.map +1 -0
  14. package/dist/admin/index.js +705 -0
  15. package/dist/admin/index.js.map +1 -0
  16. package/dist/admin/index.mjs +512 -0
  17. package/dist/admin/index.mjs.map +1 -0
  18. package/dist/admin/nextSessionTernSecure.d.ts +28 -0
  19. package/dist/admin/nextSessionTernSecure.d.ts.map +1 -0
  20. package/dist/admin/sessionTernSecure.d.ts +6 -0
  21. package/dist/admin/sessionTernSecure.d.ts.map +1 -0
  22. package/dist/admin/tenant.d.ts.map +1 -0
  23. package/dist/api/createBackendApi.d.ts +8 -0
  24. package/dist/api/createBackendApi.d.ts.map +1 -0
  25. package/dist/api/endpoints/SessionApi.d.ts +12 -0
  26. package/dist/api/endpoints/SessionApi.d.ts.map +1 -0
  27. package/dist/api/endpoints/index.d.ts +2 -0
  28. package/dist/api/endpoints/index.d.ts.map +1 -0
  29. package/dist/api/index.d.ts +2 -0
  30. package/dist/api/index.d.ts.map +1 -0
  31. package/dist/api/request.d.ts +36 -0
  32. package/dist/api/request.d.ts.map +1 -0
  33. package/dist/chunk-JFOTE3Y5.mjs +157 -0
  34. package/dist/chunk-JFOTE3Y5.mjs.map +1 -0
  35. package/dist/chunk-WZYVAHZ3.mjs +318 -0
  36. package/dist/chunk-WZYVAHZ3.mjs.map +1 -0
  37. package/dist/constants.d.ts +63 -0
  38. package/dist/constants.d.ts.map +1 -0
  39. package/dist/index.d.ts +14 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +1307 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/index.mjs +839 -0
  44. package/dist/index.mjs.map +1 -0
  45. package/dist/instance/backendFireInstance.d.ts +7 -0
  46. package/dist/instance/backendFireInstance.d.ts.map +1 -0
  47. package/dist/instance/backendInstance.d.ts +20 -0
  48. package/dist/instance/backendInstance.d.ts.map +1 -0
  49. package/dist/instance/backendInstanceEdge.d.ts +13 -0
  50. package/dist/instance/backendInstanceEdge.d.ts.map +1 -0
  51. package/dist/jwt/algorithms.d.ts +3 -0
  52. package/dist/jwt/algorithms.d.ts.map +1 -0
  53. package/dist/jwt/cryptoKeys.d.ts +3 -0
  54. package/dist/jwt/cryptoKeys.d.ts.map +1 -0
  55. package/dist/jwt/guardReturn.d.ts +3 -0
  56. package/dist/jwt/guardReturn.d.ts.map +1 -0
  57. package/dist/jwt/index.d.ts +4 -0
  58. package/dist/jwt/index.d.ts.map +1 -0
  59. package/dist/jwt/index.js +332 -0
  60. package/dist/jwt/index.js.map +1 -0
  61. package/dist/jwt/index.mjs +139 -0
  62. package/dist/jwt/index.mjs.map +1 -0
  63. package/dist/jwt/jwt.d.ts +4 -0
  64. package/dist/jwt/jwt.d.ts.map +1 -0
  65. package/dist/jwt/signJwt.d.ts +5 -0
  66. package/dist/jwt/signJwt.d.ts.map +1 -0
  67. package/dist/jwt/types.d.ts +8 -0
  68. package/dist/jwt/types.d.ts.map +1 -0
  69. package/dist/jwt/verifyContent.d.ts +7 -0
  70. package/dist/jwt/verifyContent.d.ts.map +1 -0
  71. package/dist/jwt/verifyJwt.d.ts +12 -0
  72. package/dist/jwt/verifyJwt.d.ts.map +1 -0
  73. package/dist/runtime/browser/crypto.mjs +1 -0
  74. package/dist/runtime/node/crypto.js +1 -0
  75. package/dist/runtime/node/crypto.mjs +1 -0
  76. package/dist/runtime.d.ts +26 -0
  77. package/dist/runtime.d.ts.map +1 -0
  78. package/dist/ternsecureauth.d.ts.map +1 -0
  79. package/dist/tokens/authstate.d.ts +61 -0
  80. package/dist/tokens/authstate.d.ts.map +1 -0
  81. package/dist/tokens/keys.d.ts +16 -0
  82. package/dist/tokens/keys.d.ts.map +1 -0
  83. package/dist/tokens/request.d.ts +16 -0
  84. package/dist/tokens/request.d.ts.map +1 -0
  85. package/dist/tokens/requestFire.d.ts +17 -0
  86. package/dist/tokens/requestFire.d.ts.map +1 -0
  87. package/dist/tokens/sessionConfig.d.ts +14 -0
  88. package/dist/tokens/sessionConfig.d.ts.map +1 -0
  89. package/dist/tokens/ternSecureRequest.d.ts +20 -0
  90. package/dist/tokens/ternSecureRequest.d.ts.map +1 -0
  91. package/dist/tokens/ternUrl.d.ts +15 -0
  92. package/dist/tokens/ternUrl.d.ts.map +1 -0
  93. package/dist/tokens/types.d.ts +41 -0
  94. package/dist/tokens/types.d.ts.map +1 -0
  95. package/dist/tokens/verify.d.ts +11 -0
  96. package/dist/tokens/verify.d.ts.map +1 -0
  97. package/dist/utils/admin-init.d.ts +13 -0
  98. package/dist/utils/admin-init.d.ts.map +1 -0
  99. package/dist/{types/utils → utils}/config.d.ts +1 -1
  100. package/dist/utils/config.d.ts.map +1 -0
  101. package/dist/utils/enableDebugLogging.d.ts +5 -0
  102. package/dist/utils/enableDebugLogging.d.ts.map +1 -0
  103. package/dist/utils/errors.d.ts +29 -0
  104. package/dist/utils/errors.d.ts.map +1 -0
  105. package/dist/utils/gemini_admin-init.d.ts +10 -0
  106. package/dist/utils/gemini_admin-init.d.ts.map +1 -0
  107. package/dist/utils/logger.d.ts +28 -0
  108. package/dist/utils/logger.d.ts.map +1 -0
  109. package/dist/utils/mapDecode.d.ts +4 -0
  110. package/dist/utils/mapDecode.d.ts.map +1 -0
  111. package/dist/utils/options.d.ts +5 -0
  112. package/dist/utils/options.d.ts.map +1 -0
  113. package/dist/utils/path.d.ts +4 -0
  114. package/dist/utils/path.d.ts.map +1 -0
  115. package/dist/utils/redis.d.ts +10 -0
  116. package/dist/utils/redis.d.ts.map +1 -0
  117. package/dist/utils/rfc4648.d.ts +26 -0
  118. package/dist/utils/rfc4648.d.ts.map +1 -0
  119. package/jwt/package.json +5 -0
  120. package/package.json +59 -10
  121. package/dist/cjs/admin/sessionTernSecure.js +0 -256
  122. package/dist/cjs/admin/sessionTernSecure.js.map +0 -1
  123. package/dist/cjs/admin/tenant.js +0 -68
  124. package/dist/cjs/admin/tenant.js.map +0 -1
  125. package/dist/cjs/global.d.js +0 -2
  126. package/dist/cjs/global.d.js.map +0 -1
  127. package/dist/cjs/index.js +0 -48
  128. package/dist/cjs/index.js.map +0 -1
  129. package/dist/cjs/ternsecureauth.js +0 -40
  130. package/dist/cjs/ternsecureauth.js.map +0 -1
  131. package/dist/cjs/utils/admin-init.js +0 -60
  132. package/dist/cjs/utils/admin-init.js.map +0 -1
  133. package/dist/cjs/utils/config.js +0 -113
  134. package/dist/cjs/utils/config.js.map +0 -1
  135. package/dist/esm/admin/sessionTernSecure.js +0 -226
  136. package/dist/esm/admin/sessionTernSecure.js.map +0 -1
  137. package/dist/esm/admin/tenant.js +0 -43
  138. package/dist/esm/admin/tenant.js.map +0 -1
  139. package/dist/esm/global.d.js +0 -1
  140. package/dist/esm/global.d.js.map +0 -1
  141. package/dist/esm/index.js +0 -24
  142. package/dist/esm/index.js.map +0 -1
  143. package/dist/esm/ternsecureauth.js +0 -16
  144. package/dist/esm/ternsecureauth.js.map +0 -1
  145. package/dist/esm/utils/admin-init.js +0 -24
  146. package/dist/esm/utils/admin-init.js.map +0 -1
  147. package/dist/esm/utils/config.js +0 -84
  148. package/dist/esm/utils/config.js.map +0 -1
  149. package/dist/types/admin/sessionTernSecure.d.ts +0 -36
  150. package/dist/types/admin/sessionTernSecure.d.ts.map +0 -1
  151. package/dist/types/admin/tenant.d.ts.map +0 -1
  152. package/dist/types/index.d.ts +0 -5
  153. package/dist/types/index.d.ts.map +0 -1
  154. package/dist/types/ternsecureauth.d.ts.map +0 -1
  155. package/dist/types/utils/admin-init.d.ts +0 -5
  156. package/dist/types/utils/admin-init.d.ts.map +0 -1
  157. package/dist/types/utils/config.d.ts.map +0 -1
  158. /package/dist/{types/admin → admin}/tenant.d.ts +0 -0
  159. /package/dist/{types/ternsecureauth.d.ts → ternsecureauth.d.ts} +0 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,839 @@
1
+ import {
2
+ CACHE_CONTROL_REGEX,
3
+ DEFAULT_CACHE_DURATION,
4
+ MAX_CACHE_LAST_UPDATED_AT_SECONDS,
5
+ SESSION_COOKIE_PUBLIC_KEYS_URL,
6
+ constants,
7
+ createTernSecureRequest,
8
+ getSessionConfig
9
+ } from "./chunk-JFOTE3Y5.mjs";
10
+ import {
11
+ TokenVerificationError,
12
+ TokenVerificationErrorReason,
13
+ mapJwtPayloadToDecodedIdToken,
14
+ ternDecodeJwt,
15
+ verifyJwt
16
+ } from "./chunk-WZYVAHZ3.mjs";
17
+
18
+ // src/tokens/authstate.ts
19
+ var AuthStatus = {
20
+ SignedIn: "signed-in",
21
+ SignedOut: "signed-out"
22
+ };
23
+ var AuthErrorReason = {
24
+ SessionTokenAndUATMissing: "session-token-and-uat-missing",
25
+ SessionTokenMissing: "session-token-missing",
26
+ SessionTokenExpired: "session-token-expired",
27
+ SessionTokenIATBeforeClientUAT: "session-token-iat-before-client-uat",
28
+ SessionTokenNBF: "session-token-nbf",
29
+ SessionTokenIatInTheFuture: "session-token-iat-in-the-future",
30
+ ActiveOrganizationMismatch: "active-organization-mismatch",
31
+ UnexpectedError: "unexpected-error"
32
+ };
33
+ function createHasAuthorization(decodedIdToken) {
34
+ return (authorizationParams) => {
35
+ if (!authorizationParams || typeof authorizationParams !== "object" || Array.isArray(authorizationParams)) {
36
+ return false;
37
+ }
38
+ const claims = decodedIdToken;
39
+ return Object.entries(authorizationParams).every(([key, value]) => {
40
+ const claimValue = claims[key];
41
+ if (typeof claimValue === "undefined") {
42
+ return false;
43
+ }
44
+ if (Array.isArray(value)) {
45
+ if (Array.isArray(claimValue)) {
46
+ return value.some((v) => claimValue.includes(v));
47
+ }
48
+ return value.includes(claimValue);
49
+ }
50
+ if (Array.isArray(claimValue)) {
51
+ return claimValue.includes(value);
52
+ }
53
+ return claimValue === value;
54
+ });
55
+ };
56
+ }
57
+ function signedInAuthObject(sessionToken, sessionClaims) {
58
+ const decodedIdToken = mapJwtPayloadToDecodedIdToken(sessionClaims);
59
+ return {
60
+ sessionClaims: {
61
+ ...decodedIdToken
62
+ },
63
+ userId: decodedIdToken.uid,
64
+ token: sessionToken,
65
+ require: createHasAuthorization(decodedIdToken),
66
+ error: null
67
+ };
68
+ }
69
+ function signedOutAuthObject() {
70
+ return {
71
+ sessionClaims: null,
72
+ userId: null,
73
+ require: () => false,
74
+ error: "No active session"
75
+ };
76
+ }
77
+ function signedIn(sessionClaims, headers = new Headers(), token) {
78
+ const authObject = signedInAuthObject(token, sessionClaims);
79
+ return {
80
+ status: AuthStatus.SignedIn,
81
+ reason: null,
82
+ isSignedIn: true,
83
+ auth: () => authObject,
84
+ token,
85
+ headers
86
+ };
87
+ }
88
+ function signedOut(reason, headers = new Headers()) {
89
+ return decorateHeaders({
90
+ status: AuthStatus.SignedOut,
91
+ reason,
92
+ isSignedIn: false,
93
+ auth: () => signedOutAuthObject(),
94
+ token: null,
95
+ headers
96
+ });
97
+ }
98
+ var decorateHeaders = (requestState) => {
99
+ const headers = new Headers(requestState.headers || {});
100
+ if (requestState.reason) {
101
+ try {
102
+ headers.set(constants.Headers.AuthReason, requestState.reason);
103
+ } catch {
104
+ }
105
+ }
106
+ if (requestState.status) {
107
+ try {
108
+ headers.set(constants.Headers.AuthStatus, requestState.status);
109
+ } catch {
110
+ }
111
+ }
112
+ requestState.headers = headers;
113
+ return requestState;
114
+ };
115
+
116
+ // src/api/endpoints/SessionApi.ts
117
+ var rootPath = "/sessions";
118
+ var SessionApi = class {
119
+ constructor(request) {
120
+ this.request = request;
121
+ }
122
+ async createSession(params) {
123
+ return this.request({
124
+ method: "POST",
125
+ path: rootPath,
126
+ bodyParams: params
127
+ });
128
+ }
129
+ };
130
+
131
+ // src/runtime.ts
132
+ import { webcrypto as crypto } from "#crypto";
133
+ var globalFetch = fetch.bind(globalThis);
134
+ var runtime = {
135
+ crypto,
136
+ get fetch() {
137
+ return process.env.NODE_ENV === "test" ? fetch : globalFetch;
138
+ },
139
+ AbortController: globalThis.AbortController,
140
+ Blob: globalThis.Blob,
141
+ FormData: globalThis.FormData,
142
+ Headers: globalThis.Headers,
143
+ Request: globalThis.Request,
144
+ Response: globalThis.Response
145
+ };
146
+
147
+ // src/utils/path.ts
148
+ var SEPARATOR = "/";
149
+ var MULTIPLE_SEPARATOR_REGEX = new RegExp("(?<!:)" + SEPARATOR + "{1,}", "g");
150
+ function joinPaths(...args) {
151
+ return args.filter((p) => p).join(SEPARATOR).replace(MULTIPLE_SEPARATOR_REGEX, SEPARATOR);
152
+ }
153
+
154
+ // src/api/request.ts
155
+ function createRequest(options) {
156
+ const requestFn = async (requestOptions) => {
157
+ const { apiUrl, apiVersion } = options;
158
+ const { path, method, queryParams, headerParams, bodyParams, formData } = requestOptions;
159
+ const url = joinPaths(apiUrl, apiVersion, path);
160
+ const finalUrl = new URL(url);
161
+ if (queryParams) {
162
+ Object.entries(queryParams).forEach(([key, value]) => {
163
+ if (value) {
164
+ [value].flat().forEach((v) => finalUrl.searchParams.append(key, v));
165
+ }
166
+ });
167
+ }
168
+ const headers = {
169
+ ...headerParams
170
+ };
171
+ let res;
172
+ try {
173
+ if (formData) {
174
+ res = await runtime.fetch(finalUrl.href, {
175
+ method,
176
+ headers,
177
+ body: formData
178
+ });
179
+ } else {
180
+ headers["Content-Type"] = "application/json";
181
+ const hasBody = method !== "GET" && bodyParams && Object.keys(bodyParams).length > 0;
182
+ const body = hasBody ? { body: JSON.stringify(bodyParams) } : null;
183
+ res = await runtime.fetch(finalUrl.href, {
184
+ method,
185
+ headers,
186
+ ...body
187
+ });
188
+ }
189
+ const isJSONResponse = res?.headers && res.headers?.get(constants.Headers.ContentType) === constants.ContentTypes.Json;
190
+ const responseBody = await (isJSONResponse ? res.json() : res.text());
191
+ if (!res.ok) {
192
+ return {
193
+ data: null,
194
+ errors: parseErrors(responseBody),
195
+ status: res?.status,
196
+ statusText: res?.statusText
197
+ };
198
+ }
199
+ return {
200
+ data: responseBody,
201
+ errors: null
202
+ };
203
+ } catch (error) {
204
+ if (error instanceof Error) {
205
+ return {
206
+ data: null,
207
+ errors: [
208
+ {
209
+ code: "unexpected_error",
210
+ message: error.message || "An unexpected error occurred"
211
+ }
212
+ ]
213
+ };
214
+ }
215
+ return {
216
+ data: null,
217
+ errors: parseErrors(error),
218
+ status: res?.status,
219
+ statusText: res?.statusText
220
+ };
221
+ }
222
+ };
223
+ return requestFn;
224
+ }
225
+ function parseErrors(data) {
226
+ if (!!data && typeof data === "object" && "errors" in data) {
227
+ const errors = data.errors;
228
+ return errors.length > 0 ? errors.map(parseError) : [];
229
+ }
230
+ return [];
231
+ }
232
+ function parseError(error) {
233
+ return {
234
+ code: error.code,
235
+ message: error.message
236
+ };
237
+ }
238
+
239
+ // src/api/createBackendApi.ts
240
+ function createBackendApi(options) {
241
+ const request = createRequest(options);
242
+ return {
243
+ sessions: new SessionApi(request)
244
+ };
245
+ }
246
+
247
+ // src/utils/options.ts
248
+ var defaultOptions = {
249
+ apiUrl: void 0,
250
+ apiVersion: void 0
251
+ };
252
+ function mergePreDefinedOptions(userOptions = {}) {
253
+ return {
254
+ ...defaultOptions,
255
+ ...userOptions
256
+ };
257
+ }
258
+
259
+ // src/tokens/keys.ts
260
+ var cache = {};
261
+ var lastUpdatedAt = 0;
262
+ var googleExpiresAt = 0;
263
+ function getFromCache(kid) {
264
+ return cache[kid];
265
+ }
266
+ function getCacheValues() {
267
+ return Object.values(cache);
268
+ }
269
+ function setInCache(kid, certificate, shouldExpire = true) {
270
+ cache[kid] = certificate;
271
+ lastUpdatedAt = shouldExpire ? Date.now() : -1;
272
+ }
273
+ async function fetchPublicKeys(keyUrl) {
274
+ const url = new URL(keyUrl);
275
+ const response = await fetch(url);
276
+ if (!response.ok) {
277
+ throw new TokenVerificationError({
278
+ message: `Error loading public keys from ${url.href} with code=${response.status} `,
279
+ reason: TokenVerificationErrorReason.TokenInvalid
280
+ });
281
+ }
282
+ const data = await response.json();
283
+ const expiresAt = getExpiresAt(response);
284
+ return {
285
+ keys: data,
286
+ expiresAt
287
+ };
288
+ }
289
+ async function loadJWKFromRemote({
290
+ keyURL = SESSION_COOKIE_PUBLIC_KEYS_URL,
291
+ skipJwksCache,
292
+ kid
293
+ }) {
294
+ if (skipJwksCache || isCacheExpired() || !getFromCache(kid)) {
295
+ const { keys, expiresAt } = await fetchPublicKeys(keyURL);
296
+ if (!keys || Object.keys(keys).length === 0) {
297
+ throw new TokenVerificationError({
298
+ message: `The JWKS endpoint ${keyURL} returned no keys`,
299
+ reason: TokenVerificationErrorReason.RemoteJWKFailedToLoad
300
+ });
301
+ }
302
+ googleExpiresAt = expiresAt;
303
+ Object.entries(keys).forEach(([keyId, cert2]) => {
304
+ setInCache(keyId, cert2);
305
+ });
306
+ }
307
+ const cert = getFromCache(kid);
308
+ if (!cert) {
309
+ getCacheValues();
310
+ const availableKids = Object.keys(cache).sort().join(", ");
311
+ throw new TokenVerificationError({
312
+ message: `No public key found for kid "${kid}". Available kids: [${availableKids}]`,
313
+ reason: TokenVerificationErrorReason.TokenInvalid
314
+ });
315
+ }
316
+ return cert;
317
+ }
318
+ function isCacheExpired() {
319
+ const now = Date.now();
320
+ if (lastUpdatedAt === -1) {
321
+ return false;
322
+ }
323
+ const cacheAge = now - lastUpdatedAt;
324
+ const maxCacheAge = MAX_CACHE_LAST_UPDATED_AT_SECONDS * 1e3;
325
+ const localCacheExpired = cacheAge >= maxCacheAge;
326
+ const googleCacheExpired = now >= googleExpiresAt;
327
+ const isExpired = localCacheExpired || googleCacheExpired;
328
+ if (isExpired) {
329
+ cache = {};
330
+ }
331
+ return isExpired;
332
+ }
333
+ function getExpiresAt(res) {
334
+ const cacheControlHeader = res.headers.get("cache-control");
335
+ if (!cacheControlHeader) {
336
+ return Date.now() + DEFAULT_CACHE_DURATION;
337
+ }
338
+ const maxAgeMatch = cacheControlHeader.match(CACHE_CONTROL_REGEX);
339
+ const maxAge = maxAgeMatch ? parseInt(maxAgeMatch[1], 10) : DEFAULT_CACHE_DURATION / 1e3;
340
+ return Date.now() + maxAge * 1e3;
341
+ }
342
+
343
+ // src/tokens/verify.ts
344
+ async function verifyToken(token, options) {
345
+ const { data: decodedResult, errors } = ternDecodeJwt(token);
346
+ if (errors) {
347
+ return { errors };
348
+ }
349
+ const { header } = decodedResult;
350
+ const { kid } = header;
351
+ if (!kid) {
352
+ return {
353
+ errors: [
354
+ new TokenVerificationError({
355
+ reason: TokenVerificationErrorReason.TokenInvalid,
356
+ message: 'JWT "kid" header is missing.'
357
+ })
358
+ ]
359
+ };
360
+ }
361
+ try {
362
+ const key = options.jwtKey || await loadJWKFromRemote({ ...options, kid });
363
+ if (!key) {
364
+ return {
365
+ errors: [
366
+ new TokenVerificationError({
367
+ reason: TokenVerificationErrorReason.TokenInvalid,
368
+ message: `No public key found for kid "${kid}".`
369
+ })
370
+ ]
371
+ };
372
+ }
373
+ return await verifyJwt(token, { ...options, key });
374
+ } catch (error) {
375
+ if (error instanceof TokenVerificationError) {
376
+ return { errors: [error] };
377
+ }
378
+ return {
379
+ errors: [error]
380
+ };
381
+ }
382
+ }
383
+
384
+ // src/tokens/request.ts
385
+ var BEARER_PREFIX = "Bearer ";
386
+ var AUTH_COOKIE_NAME = "_session_cookie";
387
+ function extractTokenFromHeader(request) {
388
+ const authHeader = request.headers.get("Authorization");
389
+ if (!authHeader || !authHeader.startsWith(BEARER_PREFIX)) {
390
+ return null;
391
+ }
392
+ return authHeader.slice(BEARER_PREFIX.length);
393
+ }
394
+ function extractTokenFromCookie(request, opts) {
395
+ const cookieHeader = request.headers.get("Cookie") || void 0;
396
+ const sessionName = getSessionConfig(opts).COOKIE_NAME;
397
+ if (!cookieHeader) {
398
+ return null;
399
+ }
400
+ const cookies = cookieHeader.split(";").reduce(
401
+ (acc, cookie) => {
402
+ const [name, value] = cookie.trim().split("=");
403
+ acc[name] = value;
404
+ return acc;
405
+ },
406
+ {}
407
+ );
408
+ return cookies[AUTH_COOKIE_NAME] || null;
409
+ }
410
+ function hasAuthorizationHeader(request) {
411
+ return request.headers.has("Authorization");
412
+ }
413
+ async function authenticateRequest(request, options) {
414
+ async function authenticateRequestWithTokenInCookie() {
415
+ const token = extractTokenFromCookie(request, options);
416
+ if (!token) {
417
+ return signedOut(AuthErrorReason.SessionTokenMissing);
418
+ }
419
+ const { data, errors } = await verifyToken(token, options);
420
+ if (errors) {
421
+ throw errors[0];
422
+ }
423
+ const signedInRequestState = signedIn(data, void 0, token);
424
+ return signedInRequestState;
425
+ }
426
+ async function authenticateRequestWithTokenInHeader() {
427
+ const token = extractTokenFromHeader(request);
428
+ if (!token) {
429
+ return signedOut(AuthErrorReason.SessionTokenMissing);
430
+ }
431
+ const { data, errors } = await verifyToken(token, options);
432
+ if (errors) {
433
+ throw errors[0];
434
+ }
435
+ const signedInRequestState = signedIn(data, void 0, token);
436
+ return signedInRequestState;
437
+ }
438
+ if (hasAuthorizationHeader(request)) {
439
+ return authenticateRequestWithTokenInHeader();
440
+ }
441
+ return authenticateRequestWithTokenInCookie();
442
+ }
443
+ function createAuthenticateRequest(params) {
444
+ const buildTimeOptions = mergePreDefinedOptions(params.options);
445
+ const apiClient = params.apiClient;
446
+ const handleAuthenticateRequest = (request, options = {}) => {
447
+ const { apiUrl } = buildTimeOptions;
448
+ return authenticateRequest(request, { ...options, apiUrl, apiClient });
449
+ };
450
+ return {
451
+ authenticateRequest: handleAuthenticateRequest
452
+ };
453
+ }
454
+
455
+ // src/instance/backendInstanceEdge.ts
456
+ function createBackendInstanceClient(options) {
457
+ const opts = { ...options };
458
+ const apiClient = createBackendApi(opts);
459
+ const requestState = createAuthenticateRequest({ options: opts, apiClient });
460
+ return {
461
+ ...apiClient,
462
+ ...requestState
463
+ };
464
+ }
465
+
466
+ // src/tokens/requestFire.ts
467
+ var defaultFirebaseOptions = {
468
+ apiKey: "",
469
+ authDomain: "",
470
+ projectId: "",
471
+ tenantId: void 0
472
+ };
473
+ function mergePreDefinedOptions2(preDefinedOptions, options) {
474
+ return Object.keys(preDefinedOptions).reduce(
475
+ (obj, key) => {
476
+ return { ...obj, [key]: options[key] || obj[key] };
477
+ },
478
+ { ...preDefinedOptions }
479
+ );
480
+ }
481
+ var BEARER_PREFIX2 = "Bearer ";
482
+ var AUTH_COOKIE_NAME2 = "_session_cookie";
483
+ function extractTokenFromHeader2(request) {
484
+ const authHeader = request.headers.get("Authorization");
485
+ if (!authHeader || !authHeader.startsWith(BEARER_PREFIX2)) {
486
+ return null;
487
+ }
488
+ return authHeader.slice(BEARER_PREFIX2.length);
489
+ }
490
+ function extractTokenFromCookie2(request, opts) {
491
+ const cookieHeader = request.headers.get("Cookie") || void 0;
492
+ const sessionName = getSessionConfig(opts).COOKIE_NAME;
493
+ if (!cookieHeader) {
494
+ return null;
495
+ }
496
+ const cookies = cookieHeader.split(";").reduce(
497
+ (acc, cookie) => {
498
+ const [name, value] = cookie.trim().split("=");
499
+ acc[name] = value;
500
+ return acc;
501
+ },
502
+ {}
503
+ );
504
+ return cookies[AUTH_COOKIE_NAME2] || null;
505
+ }
506
+ function hasAuthorizationHeader2(request) {
507
+ return request.headers.has("Authorization");
508
+ }
509
+ async function authenticateRequest2(request, options) {
510
+ async function authenticateRequestWithTokenInCookie() {
511
+ const token = extractTokenFromCookie2(request, options);
512
+ if (!token) {
513
+ return signedOut(AuthErrorReason.SessionTokenMissing);
514
+ }
515
+ const { data, errors } = await verifyToken(token, options);
516
+ if (errors) {
517
+ throw errors[0];
518
+ }
519
+ const signedInRequestState = signedIn(data, void 0, token);
520
+ return signedInRequestState;
521
+ }
522
+ async function authenticateRequestWithTokenInHeader() {
523
+ const token = extractTokenFromHeader2(request);
524
+ if (!token) {
525
+ return signedOut(AuthErrorReason.SessionTokenMissing);
526
+ }
527
+ const { data, errors } = await verifyToken(token, options);
528
+ if (errors) {
529
+ throw errors[0];
530
+ }
531
+ const signedInRequestState = signedIn(data, void 0, token);
532
+ return signedInRequestState;
533
+ }
534
+ if (hasAuthorizationHeader2(request)) {
535
+ return authenticateRequestWithTokenInHeader();
536
+ }
537
+ return authenticateRequestWithTokenInCookie();
538
+ }
539
+ function createFireAuthenticateRequest(params) {
540
+ const buildTimeOptions = mergePreDefinedOptions2(defaultFirebaseOptions, params.options);
541
+ const handleAuthenticateRequest = (request, options = {}) => {
542
+ const runtimeOptions = { ...buildTimeOptions, ...options };
543
+ return authenticateRequest2(request, runtimeOptions);
544
+ };
545
+ return {
546
+ authenticateRequest: handleAuthenticateRequest
547
+ };
548
+ }
549
+
550
+ // src/instance/backendFireInstance.ts
551
+ function createFireClient(options) {
552
+ const opts = { ...options };
553
+ const apiClient = createBackendApi(opts);
554
+ const requestState = createFireAuthenticateRequest({ options: opts });
555
+ return {
556
+ ...apiClient,
557
+ ...requestState
558
+ };
559
+ }
560
+
561
+ // src/utils/logger.ts
562
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
563
+ LogLevel2[LogLevel2["ERROR"] = 0] = "ERROR";
564
+ LogLevel2[LogLevel2["WARN"] = 1] = "WARN";
565
+ LogLevel2[LogLevel2["INFO"] = 2] = "INFO";
566
+ LogLevel2[LogLevel2["DEBUG"] = 3] = "DEBUG";
567
+ return LogLevel2;
568
+ })(LogLevel || {});
569
+ var Logger = class {
570
+ options;
571
+ constructor(options = {}) {
572
+ this.options = {
573
+ enabled: false,
574
+ level: 2 /* INFO */,
575
+ prefix: "[TernSecure-Backend]",
576
+ ...options
577
+ };
578
+ }
579
+ enable() {
580
+ this.options.enabled = true;
581
+ }
582
+ disable() {
583
+ this.options.enabled = false;
584
+ }
585
+ setLevel(level) {
586
+ this.options.level = level;
587
+ }
588
+ setPrefix(prefix) {
589
+ this.options.prefix = prefix;
590
+ }
591
+ log(level, levelName, message, ...args) {
592
+ if (!this.options.enabled || level > this.options.level) {
593
+ return;
594
+ }
595
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
596
+ const formattedMessage = `${timestamp} ${this.options.prefix} [${levelName}] ${message}`;
597
+ switch (level) {
598
+ case 0 /* ERROR */:
599
+ console.error(formattedMessage, ...args);
600
+ break;
601
+ case 1 /* WARN */:
602
+ console.warn(formattedMessage, ...args);
603
+ break;
604
+ case 2 /* INFO */:
605
+ console.info(formattedMessage, ...args);
606
+ break;
607
+ case 3 /* DEBUG */:
608
+ console.debug(formattedMessage, ...args);
609
+ break;
610
+ }
611
+ }
612
+ error(message, ...args) {
613
+ this.log(0 /* ERROR */, "ERROR", message, ...args);
614
+ }
615
+ warn(message, ...args) {
616
+ this.log(1 /* WARN */, "WARN", message, ...args);
617
+ }
618
+ info(message, ...args) {
619
+ this.log(2 /* INFO */, "INFO", message, ...args);
620
+ }
621
+ debug(message, ...args) {
622
+ this.log(3 /* DEBUG */, "DEBUG", message, ...args);
623
+ }
624
+ };
625
+ var createLogger = (options) => {
626
+ return new Logger(options);
627
+ };
628
+ var redisLogger = createLogger({ prefix: "[TernSecure-Redis]" });
629
+ var authLogger = createLogger({ prefix: "[TernSecure-Auth]" });
630
+
631
+ // src/utils/enableDebugLogging.ts
632
+ function enableDebugLogging() {
633
+ authLogger.enable();
634
+ authLogger.setLevel(3 /* DEBUG */);
635
+ redisLogger.enable();
636
+ redisLogger.setLevel(3 /* DEBUG */);
637
+ }
638
+ function disableDebugLogging() {
639
+ authLogger.disable();
640
+ redisLogger.disable();
641
+ }
642
+ function setLogLevel(level) {
643
+ authLogger.setLevel(level);
644
+ redisLogger.setLevel(level);
645
+ }
646
+
647
+ // src/adapters/PostgresAdapter.ts
648
+ var PostgresAdapter = class {
649
+ config;
650
+ tableName;
651
+ constructor(config) {
652
+ this.config = config;
653
+ this.tableName = config.table || "disabled_users";
654
+ }
655
+ getDisabledUser = async (uid) => {
656
+ try {
657
+ const response = await fetch(this.config.url, {
658
+ method: "POST",
659
+ headers: {
660
+ "Content-Type": "application/json",
661
+ "Authorization": `Bearer ${this.config.token}`
662
+ },
663
+ body: JSON.stringify({
664
+ query: `SELECT uid, email, disabled_time as "disabledTime" FROM ${this.tableName} WHERE uid = $1`,
665
+ params: [uid]
666
+ })
667
+ });
668
+ if (!response.ok) {
669
+ throw new Error(`HTTP error! status: ${response.status}`);
670
+ }
671
+ const result = await response.json();
672
+ if (result.rows && result.rows.length > 0) {
673
+ const row = result.rows[0];
674
+ const disabledUser = {
675
+ uid: row.uid,
676
+ email: row.email,
677
+ disabledTime: row.disabledTime
678
+ };
679
+ authLogger.debug(`Found disabled user: ${uid}`);
680
+ return disabledUser;
681
+ }
682
+ authLogger.debug(`No disabled user found: ${uid}`);
683
+ return null;
684
+ } catch (error) {
685
+ authLogger.error("Failed to fetch disabled user from Postgres:", error);
686
+ return null;
687
+ }
688
+ };
689
+ };
690
+
691
+ // src/adapters/RedisAdapter.ts
692
+ import { Redis } from "@upstash/redis";
693
+ var TTLCache = class {
694
+ cache = /* @__PURE__ */ new Map();
695
+ defaultTTL;
696
+ constructor(defaultTTLMs = 6e4) {
697
+ this.defaultTTL = defaultTTLMs;
698
+ }
699
+ set(key, value, ttlMs) {
700
+ const expiresAt = Date.now() + (ttlMs ?? this.defaultTTL);
701
+ this.cache.set(key, { value, expiresAt });
702
+ console.log(`TTLCache.set: key=${key}, value=${JSON.stringify(value)}, expiresAt=${expiresAt}, cacheSize=${this.cache.size}`);
703
+ }
704
+ getEntry(key) {
705
+ const entry = this.cache.get(key);
706
+ if (!entry) return void 0;
707
+ const now = Date.now();
708
+ if (now > entry.expiresAt) {
709
+ console.log(`TTLCache: key=${key} expired (now=${now}, expiresAt=${entry.expiresAt})`);
710
+ this.cache.delete(key);
711
+ return void 0;
712
+ }
713
+ return entry;
714
+ }
715
+ get(key) {
716
+ const entry = this.getEntry(key);
717
+ const hasEntry = entry !== void 0;
718
+ const cacheHasKey = this.cache.has(key);
719
+ const rawEntry = this.cache.get(key);
720
+ console.log(`TTLCache.get: key=${key}, hasEntry=${hasEntry}, cacheHasKey=${cacheHasKey}`);
721
+ console.log(`TTLCache.get: rawEntry=${JSON.stringify(rawEntry)}, entry=${JSON.stringify(entry)}`);
722
+ if (!entry) {
723
+ console.log(`TTLCache.get: no entry found for key=${key}, returning undefined`);
724
+ return void 0;
725
+ }
726
+ console.log(`TTLCache.get: returning value=${JSON.stringify(entry.value)} for key=${key}`);
727
+ return entry.value;
728
+ }
729
+ delete(key) {
730
+ return this.cache.delete(key);
731
+ }
732
+ clear() {
733
+ this.cache.clear();
734
+ }
735
+ cleanup() {
736
+ const now = Date.now();
737
+ for (const [key, entry] of this.cache.entries()) {
738
+ if (now > entry.expiresAt) {
739
+ this.cache.delete(key);
740
+ }
741
+ }
742
+ }
743
+ };
744
+ var RedisAdapter = class {
745
+ redis;
746
+ cache;
747
+ keyPrefix;
748
+ constructor(config) {
749
+ this.redis = new Redis({
750
+ url: config.url,
751
+ token: config.token
752
+ });
753
+ this.keyPrefix = config.keyPrefix || "disabled_user:";
754
+ const cacheTTL = config.ttl || 3e4;
755
+ this.cache = new TTLCache(cacheTTL);
756
+ setInterval(() => this.cache.cleanup(), 5 * 60 * 1e3);
757
+ }
758
+ getDisabledUser = async (uid) => {
759
+ const cacheKey = `${this.keyPrefix}${uid}`;
760
+ authLogger.debug(`RedisAdapter: Checking cache for key: ${cacheKey}`);
761
+ const cachedResult = this.cache.get(cacheKey);
762
+ authLogger.debug(`RedisAdapter: Cache get result for ${cacheKey}:`, {
763
+ cachedResult: JSON.stringify(cachedResult),
764
+ isUndefined: cachedResult === void 0,
765
+ type: typeof cachedResult
766
+ });
767
+ if (cachedResult !== void 0) {
768
+ authLogger.debug(`Cache hit for disabled user: ${uid}`, {
769
+ cacheKey,
770
+ cachedResult: JSON.stringify(cachedResult)
771
+ });
772
+ return cachedResult;
773
+ }
774
+ authLogger.debug(
775
+ `Cache miss for disabled user: ${uid}, fetching from Redis with key: ${cacheKey}`
776
+ );
777
+ try {
778
+ const disabledUser = await this.redis.get(cacheKey);
779
+ authLogger.debug(`Redis returned for key ${cacheKey}:`, {
780
+ disabledUser: JSON.stringify(disabledUser),
781
+ type: typeof disabledUser
782
+ });
783
+ this.cache.set(cacheKey, disabledUser);
784
+ authLogger.debug(`Cached disabled user result for: ${uid}`, {
785
+ cacheKey,
786
+ isDisabled: !!disabledUser,
787
+ cachedValue: JSON.stringify(disabledUser)
788
+ });
789
+ return disabledUser;
790
+ } catch (error) {
791
+ authLogger.error("Failed to fetch disabled user from Redis:", error);
792
+ return null;
793
+ }
794
+ };
795
+ invalidateCache(uid) {
796
+ const cacheKey = `${this.keyPrefix}${uid}`;
797
+ this.cache.delete(cacheKey);
798
+ }
799
+ };
800
+
801
+ // src/adapters/index.ts
802
+ function createAdapter(config) {
803
+ switch (config.type) {
804
+ case "redis":
805
+ return new RedisAdapter(config.config);
806
+ case "postgres":
807
+ return new PostgresAdapter(config.config);
808
+ default:
809
+ throw new Error(`Unsupported adapter type: ${config.type}`);
810
+ }
811
+ }
812
+ function validateCheckRevokedOptions(options) {
813
+ if (options?.enabled && !options.adapter) {
814
+ return {
815
+ isValid: false,
816
+ error: "When checkRevoked.enabled is true, an adapter must be provided"
817
+ };
818
+ }
819
+ return { isValid: true };
820
+ }
821
+ export {
822
+ AuthStatus,
823
+ LogLevel,
824
+ PostgresAdapter,
825
+ RedisAdapter,
826
+ constants,
827
+ createAdapter,
828
+ createBackendInstanceClient,
829
+ createFireClient,
830
+ createTernSecureRequest,
831
+ disableDebugLogging,
832
+ enableDebugLogging,
833
+ setLogLevel,
834
+ signedIn,
835
+ signedInAuthObject,
836
+ signedOutAuthObject,
837
+ validateCheckRevokedOptions
838
+ };
839
+ //# sourceMappingURL=index.mjs.map