@xylex-group/athena 3.0.3 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +1 -1
  2. package/dist/admin.cjs +55 -1
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.d.cts +32 -8
  5. package/dist/admin.d.ts +32 -8
  6. package/dist/admin.js +54 -2
  7. package/dist/admin.js.map +1 -1
  8. package/dist/athena-auth-url-C1FbVmN6.d.cts +200 -0
  9. package/dist/athena-auth-url-C1FbVmN6.d.ts +200 -0
  10. package/dist/{athena-request-headers-C7Jy-c_D.d.ts → athena-request-headers-DzimbvOA.d.ts} +48 -200
  11. package/dist/{athena-request-headers-DujFFyMU.d.cts → athena-request-headers-Lr_m8xCV.d.cts} +48 -200
  12. package/dist/billing.cjs +1 -1
  13. package/dist/billing.cjs.map +1 -1
  14. package/dist/billing.js +1 -1
  15. package/dist/billing.js.map +1 -1
  16. package/dist/browser.cjs +912 -5
  17. package/dist/browser.cjs.map +1 -1
  18. package/dist/browser.d.cts +8 -7
  19. package/dist/browser.d.ts +8 -7
  20. package/dist/browser.js +881 -6
  21. package/dist/browser.js.map +1 -1
  22. package/dist/cli/index.cjs +7909 -7061
  23. package/dist/cli/index.cjs.map +1 -1
  24. package/dist/cli/index.d.cts +17 -10
  25. package/dist/cli/index.d.ts +17 -10
  26. package/dist/cli/index.js +7911 -7063
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/env.cjs +130 -0
  29. package/dist/env.cjs.map +1 -0
  30. package/dist/env.d.cts +70 -0
  31. package/dist/env.d.ts +70 -0
  32. package/dist/env.js +122 -0
  33. package/dist/env.js.map +1 -0
  34. package/dist/index.cjs +1570 -98
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +31 -8
  37. package/dist/index.d.ts +31 -8
  38. package/dist/index.js +1532 -100
  39. package/dist/index.js.map +1 -1
  40. package/dist/model-form-3Gr8rkdT.d.cts +281 -0
  41. package/dist/model-form-CotpEL7z.d.ts +281 -0
  42. package/dist/{module-CPG3ULxQ.d.cts → module-CQmOaDzP.d.cts} +4 -4
  43. package/dist/{module-BruTcxe0.d.ts → module-CWkUTcUc.d.ts} +4 -4
  44. package/dist/next/client.cjs +123 -7
  45. package/dist/next/client.cjs.map +1 -1
  46. package/dist/next/client.d.cts +4 -3
  47. package/dist/next/client.d.ts +4 -3
  48. package/dist/next/client.js +123 -7
  49. package/dist/next/client.js.map +1 -1
  50. package/dist/next/server.cjs +1130 -364
  51. package/dist/next/server.cjs.map +1 -1
  52. package/dist/next/server.d.cts +121 -8
  53. package/dist/next/server.d.ts +121 -8
  54. package/dist/next/server.js +1120 -365
  55. package/dist/next/server.js.map +1 -1
  56. package/dist/pipeline-BnRKO_Pd.d.cts +93 -0
  57. package/dist/pipeline-sWCmlFqu.d.ts +93 -0
  58. package/dist/{proxy-request-headers-m4D2Tduy.d.ts → proxy-request-headers-CttlcuRb.d.ts} +1 -1
  59. package/dist/{proxy-request-headers-DGxdoyA0.d.cts → proxy-request-headers-pIBSn1Fw.d.cts} +1 -1
  60. package/dist/react.cjs +672 -16
  61. package/dist/react.cjs.map +1 -1
  62. package/dist/react.d.cts +123 -8
  63. package/dist/react.d.ts +123 -8
  64. package/dist/react.js +671 -17
  65. package/dist/react.js.map +1 -1
  66. package/dist/schema-handlers-BtT_IQFi.d.cts +138 -0
  67. package/dist/schema-handlers-VjFDhIMw.d.ts +138 -0
  68. package/dist/social-providers.d.cts +1 -1
  69. package/dist/social-providers.d.ts +1 -1
  70. package/dist/{types-D6tZ9aoq.d.ts → types-BDX8zS7w.d.ts} +40 -1
  71. package/dist/{types-AOY-GLu8.d.cts → types-BVKpQmfY.d.cts} +11 -0
  72. package/dist/{types-AOY-GLu8.d.ts → types-BVKpQmfY.d.ts} +11 -0
  73. package/dist/{types-DFr2cL1N.d.cts → types-D-Am7YSd.d.cts} +40 -1
  74. package/dist/utils.cjs +30 -0
  75. package/dist/utils.cjs.map +1 -1
  76. package/dist/utils.d.cts +3 -2
  77. package/dist/utils.d.ts +3 -2
  78. package/dist/utils.js +30 -1
  79. package/dist/utils.js.map +1 -1
  80. package/dist/{v3-client-CWfZHcKL.d.cts → v3-client-G1SLeHRa.d.cts} +23 -1
  81. package/dist/{v3-client-DZp2NEhK.d.ts → v3-client-ao8BWQ8v.d.ts} +23 -1
  82. package/package.json +16 -2
  83. package/dist/model-form-Dh0sisdL.d.ts +0 -97
  84. package/dist/model-form-oOAJUVd4.d.cts +0 -97
  85. package/dist/pipeline-CIzV9f7b.d.cts +0 -8
  86. package/dist/pipeline-DNlc8Ayn.d.ts +0 -8
@@ -1801,7 +1801,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
1801
1801
 
1802
1802
  // package.json
1803
1803
  var package_default = {
1804
- version: "3.0.3"
1804
+ version: "3.3.0"
1805
1805
  };
1806
1806
 
1807
1807
  // src/sdk-version.ts
@@ -3903,6 +3903,14 @@ function createAuthModule(config = {}, runtimeOptions = {}) {
3903
3903
  changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
3904
3904
  deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
3905
3905
  changePassword: (input, options) => postGeneric("/change-password", input, options),
3906
+ // Better Auth UI flat method aliases (also nested under session/account/social/user).
3907
+ listSessions: (input, options) => getGeneric("/list-sessions", input, options),
3908
+ revokeSession: sessionRevokeBinding,
3909
+ revokeOtherSessions,
3910
+ listAccounts: (input, options) => getGeneric("/list-accounts", input, options),
3911
+ unlinkAccount: (input, options) => postGeneric("/unlink-account", input, options),
3912
+ linkSocial: (input, options) => postGeneric("/link-social", input, options),
3913
+ updateUser: (input, options) => postGeneric("/update-user", input, options),
3906
3914
  user: {
3907
3915
  update: (input, options) => postGeneric("/update-user", input, options),
3908
3916
  delete: (input, options) => postGeneric("/delete-user", input, options),
@@ -9552,6 +9560,82 @@ var AthenaConfigurationError = class extends Error {
9552
9560
  }
9553
9561
  };
9554
9562
 
9563
+ // src/diagnostics.ts
9564
+ function readProcessEnv2() {
9565
+ try {
9566
+ return globalThis.process?.env ?? {};
9567
+ } catch {
9568
+ return {};
9569
+ }
9570
+ }
9571
+ function isTruthyEnv(value) {
9572
+ if (!value) return false;
9573
+ const normalized = value.trim().toLowerCase();
9574
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
9575
+ }
9576
+ function isQuietAthenaDiagnosticsEnvironment(env = readProcessEnv2()) {
9577
+ const nodeEnv = env.NODE_ENV?.trim().toLowerCase();
9578
+ if (nodeEnv === "production") {
9579
+ return true;
9580
+ }
9581
+ if (isTruthyEnv(env.OPENNEXT_BUILD)) {
9582
+ return true;
9583
+ }
9584
+ const nextPhase = env.NEXT_PHASE?.trim();
9585
+ if (nextPhase === "phase-production-build") {
9586
+ return true;
9587
+ }
9588
+ if (isTruthyEnv(env.CI) && nodeEnv !== "test") {
9589
+ if (nodeEnv === "production" || isTruthyEnv(env.OPENNEXT_BUILD)) {
9590
+ return true;
9591
+ }
9592
+ }
9593
+ return false;
9594
+ }
9595
+ function resolveBooleanFlag(explicit, mode, quiet) {
9596
+ if (typeof explicit === "boolean") {
9597
+ return explicit;
9598
+ }
9599
+ if (mode === true) {
9600
+ return true;
9601
+ }
9602
+ if (mode === false) {
9603
+ return false;
9604
+ }
9605
+ if (mode === "auto") {
9606
+ return false;
9607
+ }
9608
+ return false;
9609
+ }
9610
+ function resolveAthenaClientDiagnostics(input) {
9611
+ const env = input.env ?? readProcessEnv2();
9612
+ const quiet = isQuietAthenaDiagnosticsEnvironment(env);
9613
+ const mode = input.diagnostics;
9614
+ const effectiveMode = mode === "auto" && quiet ? false : mode;
9615
+ const debugAst = resolveBooleanFlag(input.debugAst, effectiveMode);
9616
+ const findManyAst = resolveBooleanFlag(input.findManyAst, effectiveMode);
9617
+ let traceQueries;
9618
+ if (input.traceQueries !== void 0) {
9619
+ if (typeof input.traceQueries === "boolean") {
9620
+ traceQueries = input.traceQueries;
9621
+ } else if (effectiveMode === false || mode === "auto" && quiet) {
9622
+ const enabled = input.traceQueries.enabled;
9623
+ traceQueries = typeof enabled === "boolean" ? enabled ? input.traceQueries : false : false;
9624
+ } else {
9625
+ traceQueries = input.traceQueries;
9626
+ }
9627
+ } else if (effectiveMode === true) {
9628
+ traceQueries = true;
9629
+ } else {
9630
+ traceQueries = false;
9631
+ }
9632
+ return {
9633
+ debugAst,
9634
+ findManyAst,
9635
+ traceQueries
9636
+ };
9637
+ }
9638
+
9555
9639
  // src/v3-client.ts
9556
9640
  var ENV_URL_KEYS = ["ATHENA_URL", "NEXT_PUBLIC_ATHENA_URL"];
9557
9641
  var ENV_DB_URL_KEYS = ["ATHENA_DB_URL", "ATHENA_GATEWAY_URL", "NEXT_PUBLIC_ATHENA_DB_API_URL"];
@@ -9560,7 +9644,13 @@ var ENV_CHAT_URL_KEYS = ["ATHENA_CHAT_URL", "NEXT_PUBLIC_ATHENA_CHAT_URL"];
9560
9644
  var ENV_CHAT_WS_URL_KEYS = ["ATHENA_CHAT_WS_URL", "NEXT_PUBLIC_ATHENA_CHAT_WS_URL"];
9561
9645
  var ENV_STORAGE_URL_KEYS = ["ATHENA_STORAGE_URL", "NEXT_PUBLIC_ATHENA_STORAGE_URL"];
9562
9646
  var ENV_KEY_KEYS = ["ATHENA_API_KEY", "NEXT_PUBLIC_ATHENA_API_KEY", "ATHENA_GATEWAY_API_KEY", "X_API_KEY"];
9563
- var ENV_CLIENT_KEYS = ["ATHENA_CLIENT", "NEXT_PUBLIC_ATHENA_CLIENT"];
9647
+ var ENV_CLIENT_KEYS = [
9648
+ "ATHENA_CLIENT",
9649
+ "ATHENA_GATEWAY_CLIENT",
9650
+ "ATHENA_GENERATOR_CLIENT",
9651
+ "NEXT_PUBLIC_ATHENA_CLIENT",
9652
+ "NEXT_PUBLIC_ATHENA_GATEWAY_CLIENT"
9653
+ ];
9564
9654
  var MISSING_DB_SENTINEL = "https://athena.invalid/db";
9565
9655
  function readFirstEnv(env, keys) {
9566
9656
  for (const key of keys) {
@@ -9635,6 +9725,13 @@ function createInternalConfig(core) {
9635
9725
  const { config, urls } = core;
9636
9726
  const { url: _authUrl, ...authOptions } = config.auth ?? {};
9637
9727
  const { url: _storageUrl, directUpload, ...storageOptions } = config.storage ?? {};
9728
+ const diagnostics = resolveAthenaClientDiagnostics({
9729
+ diagnostics: config.diagnostics,
9730
+ debugAst: config.debugAst,
9731
+ findManyAst: config.findManyAst,
9732
+ traceQueries: config.traceQueries,
9733
+ env: config.env
9734
+ });
9638
9735
  return {
9639
9736
  baseUrl: urls.db ?? MISSING_DB_SENTINEL,
9640
9737
  apiKey: core.key,
@@ -9651,9 +9748,9 @@ function createInternalConfig(core) {
9651
9748
  models: config.models,
9652
9749
  behavior: {
9653
9750
  retryReads: config.retryReads,
9654
- traceQueries: config.traceQueries,
9655
- debugAst: config.debugAst,
9656
- findManyAst: config.findManyAst
9751
+ traceQueries: diagnostics.traceQueries,
9752
+ debugAst: diagnostics.debugAst,
9753
+ findManyAst: diagnostics.findManyAst
9657
9754
  },
9658
9755
  storage: {
9659
9756
  ...storageOptions,
@@ -9727,11 +9824,30 @@ function createClientView(core, viewContext) {
9727
9824
  return resolved.verifyConnection(options);
9728
9825
  },
9729
9826
  withContext(context) {
9827
+ warnIfEmptyRequestContext(context);
9730
9828
  return createClientView(core, mergeAthenaRequestContexts(viewContext, context));
9731
9829
  }
9732
9830
  };
9733
9831
  return Object.freeze(client);
9734
9832
  }
9833
+ function isEmptyAthenaRequestContext(context) {
9834
+ if (!context) return true;
9835
+ const hasHeaders = context.headers != null && Object.keys(context.headers).length > 0;
9836
+ return context.userId == null && context.organizationId == null && !normalizeOptionalContextString(context.cookie) && !normalizeOptionalContextString(context.bearerToken) && !normalizeOptionalContextString(context.sessionToken) && !context.forceNoCache && !hasHeaders;
9837
+ }
9838
+ function normalizeOptionalContextString(value) {
9839
+ const trimmed = value?.trim();
9840
+ return trimmed || void 0;
9841
+ }
9842
+ function warnIfEmptyRequestContext(context) {
9843
+ if (!isEmptyAthenaRequestContext(context)) return;
9844
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
9845
+ return;
9846
+ }
9847
+ console.warn(
9848
+ "[athena] withContext({}) has no userId, organizationId, cookie, bearerToken, sessionToken, headers, or forceNoCache. Gateway scope headers will not change. Pass identity fields, or use createAthenaServerClient({ session, scope })."
9849
+ );
9850
+ }
9735
9851
  function createClient(config) {
9736
9852
  return createClientView(resolveCore(config));
9737
9853
  }
@@ -9801,303 +9917,139 @@ async function resolveNextRequestContext(options = {}) {
9801
9917
  };
9802
9918
  }
9803
9919
 
9804
- // src/next/session-bridge/constants.ts
9805
- var ATHENA_AUTH_SESSION_BRIDGE_ROUTE = "/api/athena-auth/session";
9806
- var ATHENA_AUTH_SESSION_COOKIE_NAME = "athena-auth.session-token";
9807
- var ATHENA_AUTH_SESSION_COOKIE_NAMES = [
9808
- ATHENA_AUTH_SESSION_COOKIE_NAME,
9809
- "athena-auth.session_token"
9810
- ];
9811
-
9812
- // src/next/session-bridge/client.ts
9813
- var JSON_CONTENT_TYPE = "application/json";
9814
- function isBrowserRuntime() {
9815
- return typeof globalThis !== "undefined" && "window" in globalThis;
9816
- }
9817
- async function persistAthenaAuthSessionOnAppHost(payload, options) {
9818
- if (!(payload && isBrowserRuntime())) {
9819
- return;
9920
+ // src/organization/ensure-active-organization.ts
9921
+ function normalizeOrganizationId(value) {
9922
+ if (typeof value !== "string") {
9923
+ return null;
9820
9924
  }
9821
- const route = options?.route ?? ATHENA_AUTH_SESSION_BRIDGE_ROUTE;
9822
- const fetchImpl = options?.fetch ?? fetch;
9823
- const response = await fetchImpl(route, {
9824
- body: JSON.stringify(payload),
9825
- credentials: "same-origin",
9826
- headers: {
9827
- "Content-Type": JSON_CONTENT_TYPE
9828
- },
9829
- method: "POST"
9830
- });
9831
- if (!response.ok) {
9832
- throw new Error("Failed to persist the Athena Auth session on the app host");
9925
+ const normalized = value.trim();
9926
+ return normalized.length > 0 ? normalized : null;
9927
+ }
9928
+ function defaultSelectOrganizationId(organizations) {
9929
+ for (const organization of organizations) {
9930
+ const id = normalizeOrganizationId(organization.id);
9931
+ if (id) {
9932
+ return id;
9933
+ }
9833
9934
  }
9935
+ return null;
9834
9936
  }
9835
- async function clearAthenaAuthSessionOnAppHost(options) {
9836
- if (!isBrowserRuntime()) {
9837
- return;
9937
+ async function ensureActiveOrganization(options) {
9938
+ const currentActiveOrganizationId = normalizeOrganizationId(
9939
+ options.session?.session?.activeOrganizationId
9940
+ );
9941
+ if (currentActiveOrganizationId) {
9942
+ return {
9943
+ activeOrganizationId: currentActiveOrganizationId,
9944
+ didSetActiveOrganization: false
9945
+ };
9838
9946
  }
9839
- const route = options?.route ?? ATHENA_AUTH_SESSION_BRIDGE_ROUTE;
9840
- const fetchImpl = options?.fetch ?? fetch;
9841
- const response = await fetchImpl(route, {
9842
- credentials: "same-origin",
9843
- method: "DELETE"
9844
- });
9845
- if (!response.ok) {
9846
- throw new Error("Failed to clear the Athena Auth session on the app host");
9947
+ let organizations;
9948
+ try {
9949
+ organizations = await options.listOrganizations();
9950
+ } catch (error) {
9951
+ options.onError?.(error);
9952
+ return {
9953
+ activeOrganizationId: null,
9954
+ didSetActiveOrganization: false
9955
+ };
9956
+ }
9957
+ if (organizations.length === 0) {
9958
+ return {
9959
+ activeOrganizationId: null,
9960
+ didSetActiveOrganization: false
9961
+ };
9962
+ }
9963
+ const selectedOrganizationId = normalizeOrganizationId(
9964
+ (options.selectOrganizationId ?? defaultSelectOrganizationId)(organizations)
9965
+ );
9966
+ if (!selectedOrganizationId) {
9967
+ return {
9968
+ activeOrganizationId: null,
9969
+ didSetActiveOrganization: false
9970
+ };
9971
+ }
9972
+ try {
9973
+ await options.setActiveOrganization(selectedOrganizationId);
9974
+ return {
9975
+ activeOrganizationId: selectedOrganizationId,
9976
+ didSetActiveOrganization: true
9977
+ };
9978
+ } catch (error) {
9979
+ options.onError?.(error);
9980
+ return {
9981
+ activeOrganizationId: null,
9982
+ didSetActiveOrganization: false
9983
+ };
9847
9984
  }
9848
9985
  }
9849
9986
 
9850
- // src/next/session-bridge/payload.ts
9851
- function resolveSessionBridgePayload(payload) {
9852
- const token = payload?.session?.token ?? payload?.token;
9853
- if (typeof token !== "string") {
9854
- return null;
9987
+ // src/utils/athena-auth-url.ts
9988
+ var ATHENA_AUTH_PATH = "/api/auth";
9989
+ var LOCAL_DEV_ORIGIN = "http://localhost:3000";
9990
+ var DEFAULT_ATHENA_AUTH_ORIGIN = "https://auth.athena-auth.com";
9991
+ var DEFAULT_ATHENA_AUTH_UPSTREAM_URL = DEFAULT_ATHENA_AUTH_ORIGIN;
9992
+ var ATHENA_AUTH_UPSTREAM_ENV_KEYS = [
9993
+ "ATHENA_AUTH_UPSTREAM_URL",
9994
+ "ATHENA_AUTH_URL",
9995
+ "NEXT_PUBLIC_ATHENA_AUTH_UPSTREAM_URL",
9996
+ "NEXT_PUBLIC_ATHENA_AUTH_URL"
9997
+ ];
9998
+ var ATHENA_AUTH_UPSTREAM_URL_ENV_NAMES = ATHENA_AUTH_UPSTREAM_ENV_KEYS;
9999
+ var LEADING_SLASHES_REGEX = /^\/+/;
10000
+ function stripTrailingSlashes(value) {
10001
+ return value.replace(/\/+$/g, "");
10002
+ }
10003
+ function ensureLeadingSlash(value) {
10004
+ return value.startsWith("/") ? value : `/${value}`;
10005
+ }
10006
+ function ensureAthenaAuthPath(pathname) {
10007
+ const normalizedPath = stripTrailingSlashes(
10008
+ ensureLeadingSlash(pathname.trim())
10009
+ );
10010
+ if (!normalizedPath || normalizedPath === "/") {
10011
+ return ATHENA_AUTH_PATH;
9855
10012
  }
9856
- const normalizedToken = token.trim();
9857
- if (!normalizedToken) {
9858
- return null;
10013
+ if (normalizedPath.endsWith(ATHENA_AUTH_PATH)) {
10014
+ return normalizedPath;
9859
10015
  }
9860
- return {
9861
- token: normalizedToken,
9862
- expiresAt: typeof payload?.session?.expiresAt === "string" ? payload.session.expiresAt : void 0
9863
- };
10016
+ return `${normalizedPath}${ATHENA_AUTH_PATH}`;
9864
10017
  }
9865
-
9866
- // src/next/session-bridge/cookie.ts
9867
- var EXPIRED_AT = /* @__PURE__ */ new Date(0);
9868
- function resolveRequestIsSecure(request2) {
9869
- const forwardedProto = request2.headers.get("x-forwarded-proto")?.trim();
9870
- if (forwardedProto) {
9871
- const first = forwardedProto.split(",")[0]?.trim().toLowerCase();
9872
- if (first === "https") return true;
9873
- if (first === "http") return false;
10018
+ function stripAthenaAuthPath(pathname) {
10019
+ const normalizedPath = stripTrailingSlashes(
10020
+ ensureLeadingSlash(pathname.trim())
10021
+ );
10022
+ if (!normalizedPath || normalizedPath === "/") {
10023
+ return "/";
9874
10024
  }
9875
- return new URL(request2.url).protocol === "https:";
10025
+ if (normalizedPath === ATHENA_AUTH_PATH) {
10026
+ return "/";
10027
+ }
10028
+ if (normalizedPath.endsWith(ATHENA_AUTH_PATH)) {
10029
+ const withoutAuthPath = normalizedPath.slice(0, -ATHENA_AUTH_PATH.length);
10030
+ return withoutAuthPath ? ensureLeadingSlash(withoutAuthPath) : "/";
10031
+ }
10032
+ return normalizedPath;
9876
10033
  }
9877
- function resolveSessionCookieExpiresAt(value) {
9878
- if (typeof value !== "string") {
10034
+ function readProcessEnv3() {
10035
+ try {
10036
+ const maybeProcess = globalThis.process;
10037
+ return maybeProcess?.env;
10038
+ } catch {
9879
10039
  return void 0;
9880
10040
  }
9881
- const expiresAt = new Date(value);
9882
- return Number.isNaN(expiresAt.getTime()) ? void 0 : expiresAt;
9883
10041
  }
9884
- function serializeCookie(name, value, options) {
9885
- const parts = [
9886
- `${encodeURIComponent(name)}=${encodeURIComponent(value)}`,
9887
- `Path=${options.path}`,
9888
- "HttpOnly",
9889
- `SameSite=${options.sameSite === "none" ? "None" : options.sameSite === "strict" ? "Strict" : "Lax"}`
9890
- ];
9891
- if (options.secure) {
9892
- parts.push("Secure");
9893
- }
9894
- if (options.expires) {
9895
- parts.push(`Expires=${options.expires.toUTCString()}`);
10042
+ function getBrowserOrigin() {
10043
+ try {
10044
+ const origin = globalThis.window?.location?.origin;
10045
+ return typeof origin === "string" && origin.length > 0 ? origin : void 0;
10046
+ } catch {
10047
+ return void 0;
9896
10048
  }
9897
- return parts.join("; ");
9898
10049
  }
9899
- function resolveBridgeCookieConfig(options) {
9900
- return {
9901
- cookieName: options?.cookieName ?? ATHENA_AUTH_SESSION_COOKIE_NAME,
9902
- cookieNames: options?.cookieNames ?? ATHENA_AUTH_SESSION_COOKIE_NAMES,
9903
- cookiePath: options?.cookiePath ?? "/",
9904
- sameSite: options?.sameSite ?? "lax"
9905
- };
9906
- }
9907
- function appendSessionCookie(headers, request2, token, expiresAt, options) {
9908
- const config = resolveBridgeCookieConfig(options);
9909
- const secure = options?.secure ?? resolveRequestIsSecure(request2);
9910
- headers.append(
9911
- "set-cookie",
9912
- serializeCookie(config.cookieName, token, {
9913
- path: config.cookiePath,
9914
- sameSite: config.sameSite,
9915
- secure,
9916
- expires: expiresAt
9917
- })
9918
- );
9919
- }
9920
- function appendClearSessionCookies(headers, request2, options) {
9921
- const config = resolveBridgeCookieConfig(options);
9922
- const secure = options?.secure ?? resolveRequestIsSecure(request2);
9923
- const names = /* @__PURE__ */ new Set([config.cookieName, ...config.cookieNames]);
9924
- for (const name of names) {
9925
- headers.append(
9926
- "set-cookie",
9927
- serializeCookie(name, "", {
9928
- path: config.cookiePath,
9929
- sameSite: config.sameSite,
9930
- secure,
9931
- expires: EXPIRED_AT
9932
- })
9933
- );
9934
- }
9935
- }
9936
-
9937
- // src/next/session-bridge/handlers.ts
9938
- function json(body, init) {
9939
- const headers = init?.headers ?? new Headers();
9940
- if (!headers.has("content-type")) {
9941
- headers.set("content-type", "application/json; charset=utf-8");
9942
- }
9943
- return new Response(JSON.stringify(body), {
9944
- status: init?.status ?? 200,
9945
- headers
9946
- });
9947
- }
9948
- function resolveRoute(options) {
9949
- return options?.route ?? ATHENA_AUTH_SESSION_BRIDGE_ROUTE;
9950
- }
9951
- async function handleAthenaAuthSessionBridgePost(request2, options) {
9952
- const payload = await request2.json().catch(() => null);
9953
- const token = typeof payload?.token === "string" ? payload.token.trim() : "";
9954
- if (!token) {
9955
- return json(
9956
- {
9957
- error: "Missing Athena Auth session token"
9958
- },
9959
- { status: 400 }
9960
- );
9961
- }
9962
- const headers = new Headers();
9963
- appendSessionCookie(
9964
- headers,
9965
- request2,
9966
- token,
9967
- resolveSessionCookieExpiresAt(payload?.expiresAt),
9968
- options
9969
- );
9970
- return json(
9971
- {
9972
- ok: true,
9973
- route: resolveRoute(options)
9974
- },
9975
- { headers }
9976
- );
9977
- }
9978
- function handleAthenaAuthSessionBridgeDelete(request2, options) {
9979
- const headers = new Headers();
9980
- appendClearSessionCookies(headers, request2, options);
9981
- return json(
9982
- {
9983
- ok: true,
9984
- route: resolveRoute(options)
9985
- },
9986
- { headers }
9987
- );
9988
- }
9989
- function createAthenaAuthSessionBridgeHandlers(options) {
9990
- return {
9991
- POST: (request2) => handleAthenaAuthSessionBridgePost(request2, options),
9992
- DELETE: (request2) => handleAthenaAuthSessionBridgeDelete(request2, options)
9993
- };
9994
- }
9995
- function normalizePathname(pathname) {
9996
- if (pathname.length > 1 && pathname.endsWith("/")) {
9997
- return pathname.slice(0, -1);
9998
- }
9999
- return pathname || "/";
10000
- }
10001
- function isAthenaAuthSessionBridgePath(request2, options) {
10002
- const pathname = normalizePathname(new URL(request2.url).pathname);
10003
- const route = normalizePathname(resolveRoute(options));
10004
- if (pathname === route) {
10005
- return true;
10006
- }
10007
- const matchPaths = options?.matchPaths ?? ["session"];
10008
- const segments = pathname.split("/").filter(Boolean);
10009
- const tail = segments[segments.length - 1];
10010
- return typeof tail === "string" && matchPaths.includes(tail);
10011
- }
10012
- function createAthenaAuthSessionBridgePathHandlers(options) {
10013
- const notFound = () => json(
10014
- {
10015
- error: "Not found"
10016
- },
10017
- { status: 404 }
10018
- );
10019
- return {
10020
- POST: async (request2) => {
10021
- if (!isAthenaAuthSessionBridgePath(request2, options)) {
10022
- return notFound();
10023
- }
10024
- return handleAthenaAuthSessionBridgePost(request2, options);
10025
- },
10026
- DELETE: (request2) => {
10027
- if (!isAthenaAuthSessionBridgePath(request2, options)) {
10028
- return notFound();
10029
- }
10030
- return handleAthenaAuthSessionBridgeDelete(request2, options);
10031
- }
10032
- };
10033
- }
10034
-
10035
- // src/utils/athena-auth-url.ts
10036
- var ATHENA_AUTH_PATH = "/api/auth";
10037
- var LOCAL_DEV_ORIGIN = "http://localhost:3000";
10038
- var DEFAULT_ATHENA_AUTH_ORIGIN = "https://auth.athena-auth.com";
10039
- var DEFAULT_ATHENA_AUTH_UPSTREAM_URL = DEFAULT_ATHENA_AUTH_ORIGIN;
10040
- var ATHENA_AUTH_UPSTREAM_ENV_KEYS = [
10041
- "ATHENA_AUTH_UPSTREAM_URL",
10042
- "ATHENA_AUTH_URL",
10043
- "NEXT_PUBLIC_ATHENA_AUTH_UPSTREAM_URL",
10044
- "NEXT_PUBLIC_ATHENA_AUTH_URL"
10045
- ];
10046
- var ATHENA_AUTH_UPSTREAM_URL_ENV_NAMES = ATHENA_AUTH_UPSTREAM_ENV_KEYS;
10047
- var LEADING_SLASHES_REGEX = /^\/+/;
10048
- function stripTrailingSlashes(value) {
10049
- return value.replace(/\/+$/g, "");
10050
- }
10051
- function ensureLeadingSlash(value) {
10052
- return value.startsWith("/") ? value : `/${value}`;
10053
- }
10054
- function ensureAthenaAuthPath(pathname) {
10055
- const normalizedPath = stripTrailingSlashes(
10056
- ensureLeadingSlash(pathname.trim())
10057
- );
10058
- if (!normalizedPath || normalizedPath === "/") {
10059
- return ATHENA_AUTH_PATH;
10060
- }
10061
- if (normalizedPath.endsWith(ATHENA_AUTH_PATH)) {
10062
- return normalizedPath;
10063
- }
10064
- return `${normalizedPath}${ATHENA_AUTH_PATH}`;
10065
- }
10066
- function stripAthenaAuthPath(pathname) {
10067
- const normalizedPath = stripTrailingSlashes(
10068
- ensureLeadingSlash(pathname.trim())
10069
- );
10070
- if (!normalizedPath || normalizedPath === "/") {
10071
- return "/";
10072
- }
10073
- if (normalizedPath === ATHENA_AUTH_PATH) {
10074
- return "/";
10075
- }
10076
- if (normalizedPath.endsWith(ATHENA_AUTH_PATH)) {
10077
- const withoutAuthPath = normalizedPath.slice(0, -ATHENA_AUTH_PATH.length);
10078
- return withoutAuthPath ? ensureLeadingSlash(withoutAuthPath) : "/";
10079
- }
10080
- return normalizedPath;
10081
- }
10082
- function readProcessEnv2() {
10083
- try {
10084
- const maybeProcess = globalThis.process;
10085
- return maybeProcess?.env;
10086
- } catch {
10087
- return void 0;
10088
- }
10089
- }
10090
- function getBrowserOrigin() {
10091
- try {
10092
- const origin = globalThis.window?.location?.origin;
10093
- return typeof origin === "string" && origin.length > 0 ? origin : void 0;
10094
- } catch {
10095
- return void 0;
10096
- }
10097
- }
10098
- function isAbsoluteUrl(value) {
10099
- const trimmed = value.trim();
10100
- return trimmed.startsWith("http://") || trimmed.startsWith("https://");
10050
+ function isAbsoluteUrl(value) {
10051
+ const trimmed = value.trim();
10052
+ return trimmed.startsWith("http://") || trimmed.startsWith("https://");
10101
10053
  }
10102
10054
  function readAthenaAuthUpstreamUrlFromEnv(env) {
10103
10055
  for (const key of ATHENA_AUTH_UPSTREAM_ENV_KEYS) {
@@ -10116,7 +10068,7 @@ function resolveConfiguredAthenaAuthUpstreamUrl(rawUpstreamUrl) {
10116
10068
  if (rawUpstreamUrl) {
10117
10069
  return readAthenaAuthUpstreamUrlFromEnv(rawUpstreamUrl);
10118
10070
  }
10119
- const processEnv = readProcessEnv2();
10071
+ const processEnv = readProcessEnv3();
10120
10072
  return processEnv ? readAthenaAuthUpstreamUrlFromEnv(processEnv) : void 0;
10121
10073
  }
10122
10074
  function normalizeAthenaAuthBaseUrl(urlOrPath) {
@@ -10203,31 +10155,442 @@ function resolveAthenaAuthClientBaseUrl(configuredAuthBaseUrl, rawUpstreamUrl, o
10203
10155
  new URL(normalizedConfiguredBaseUrl, LOCAL_DEV_ORIGIN).toString()
10204
10156
  );
10205
10157
  }
10206
- function resolveAthenaAuthRequestUrl(path, rawBaseUrl) {
10207
- const normalizedPath = path.replace(LEADING_SLASHES_REGEX, "");
10208
- const base = resolveAthenaAuthClientBaseUrl(rawBaseUrl);
10209
- return new URL(normalizedPath, `${base}/`).toString();
10158
+ function resolveAthenaAuthRequestUrl(path, rawBaseUrl) {
10159
+ const normalizedPath = path.replace(LEADING_SLASHES_REGEX, "");
10160
+ const base = resolveAthenaAuthClientBaseUrl(rawBaseUrl);
10161
+ return new URL(normalizedPath, `${base}/`).toString();
10162
+ }
10163
+ var ATHENA_AUTH_VERIFY_EMAIL_PATH = "verify-email";
10164
+ var ATHENA_AUTH_GET_SESSION_PATH = "get-session";
10165
+ var ATHENA_AUTH_GET_SESSION_ABSOLUTE_PATH = `${ATHENA_AUTH_PATH}/get-session`;
10166
+ var AUTH_SESSION_PATH = ATHENA_AUTH_GET_SESSION_ABSOLUTE_PATH;
10167
+ var ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_PARAM = "disableCookieCache";
10168
+ var DISABLE_COOKIE_CACHE_QUERY_PARAM = ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_PARAM;
10169
+ var ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_VALUE = "true";
10170
+ var DISABLE_COOKIE_CACHE_QUERY_VALUE = ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_VALUE;
10171
+ var ATHENA_SESSION_DATA_HEADER = "x-session-data";
10172
+ var SESSION_DATA_HEADER = ATHENA_SESSION_DATA_HEADER;
10173
+ function resolveEmailVerificationCallbackUrl(rawBaseUrl) {
10174
+ return resolveAthenaAuthRequestUrl(ATHENA_AUTH_VERIFY_EMAIL_PATH, rawBaseUrl);
10175
+ }
10176
+ function createFreshSessionLookupUrl(baseUrl) {
10177
+ const url = new URL(ATHENA_AUTH_GET_SESSION_ABSOLUTE_PATH, baseUrl);
10178
+ url.searchParams.set(
10179
+ ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_PARAM,
10180
+ ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_VALUE
10181
+ );
10182
+ return url;
10183
+ }
10184
+
10185
+ // src/next/get-server-session.ts
10186
+ function normalizeId(value) {
10187
+ if (typeof value !== "string") return null;
10188
+ const trimmed = value.trim();
10189
+ return trimmed.length > 0 ? trimmed : null;
10190
+ }
10191
+ function readHeader2(headers, target) {
10192
+ if (!headers) return void 0;
10193
+ if (typeof headers.get === "function") {
10194
+ const value = headers.get(target);
10195
+ return value?.trim() || void 0;
10196
+ }
10197
+ const normalizedTarget = target.toLowerCase();
10198
+ for (const [key, value] of Object.entries(headers)) {
10199
+ if (key.toLowerCase() === normalizedTarget) {
10200
+ const normalized = value?.trim();
10201
+ return normalized || void 0;
10202
+ }
10203
+ }
10204
+ return void 0;
10205
+ }
10206
+ function parseAthenaSessionDataHeader(raw) {
10207
+ if (!raw?.trim()) return null;
10208
+ try {
10209
+ const parsed = JSON.parse(raw);
10210
+ return coerceSessionResponse(parsed);
10211
+ } catch {
10212
+ return null;
10213
+ }
10214
+ }
10215
+ function coerceSessionResponse(value) {
10216
+ if (!value || typeof value !== "object") return null;
10217
+ const record = value;
10218
+ const payload = record.session && record.user ? record : record.data && typeof record.data === "object" ? record.data : null;
10219
+ if (!payload) return null;
10220
+ const user = payload.user;
10221
+ const session = payload.session;
10222
+ if (!user || typeof user !== "object" || !session || typeof session !== "object") {
10223
+ return null;
10224
+ }
10225
+ const userRecord = user;
10226
+ const sessionRecord = session;
10227
+ const userId = normalizeId(
10228
+ typeof userRecord.id === "string" ? userRecord.id : void 0
10229
+ );
10230
+ const sessionId = normalizeId(
10231
+ typeof sessionRecord.id === "string" ? sessionRecord.id : void 0
10232
+ );
10233
+ if (!userId || !sessionId) return null;
10234
+ return {
10235
+ user: {
10236
+ id: userId,
10237
+ email: typeof userRecord.email === "string" ? userRecord.email : "",
10238
+ name: typeof userRecord.name === "string" ? userRecord.name : null,
10239
+ image: typeof userRecord.image === "string" ? userRecord.image : null,
10240
+ emailVerified: typeof userRecord.emailVerified === "boolean" ? userRecord.emailVerified : void 0,
10241
+ role: typeof userRecord.role === "string" ? userRecord.role : null,
10242
+ username: typeof userRecord.username === "string" ? userRecord.username : null
10243
+ },
10244
+ session: {
10245
+ id: sessionId,
10246
+ userId: typeof sessionRecord.userId === "string" ? sessionRecord.userId : userId,
10247
+ token: typeof sessionRecord.token === "string" ? sessionRecord.token : void 0,
10248
+ expiresAt: typeof sessionRecord.expiresAt === "string" ? sessionRecord.expiresAt : void 0,
10249
+ activeOrganizationId: normalizeId(
10250
+ typeof sessionRecord.activeOrganizationId === "string" ? sessionRecord.activeOrganizationId : null
10251
+ )
10252
+ }
10253
+ };
10254
+ }
10255
+ async function fetchSessionFromAuth(options) {
10256
+ const headers = {
10257
+ accept: "application/json"
10258
+ };
10259
+ if (options.cookie) headers.cookie = options.cookie;
10260
+ if (options.bearerToken) headers.authorization = `Bearer ${options.bearerToken}`;
10261
+ try {
10262
+ const response = await options.fetchImpl(options.url, {
10263
+ method: "GET",
10264
+ headers,
10265
+ cache: "no-store"
10266
+ });
10267
+ if (!response.ok) return null;
10268
+ const json3 = await response.json();
10269
+ return coerceSessionResponse(json3);
10270
+ } catch {
10271
+ return null;
10272
+ }
10273
+ }
10274
+ function resolveSessionLookupUrl(options) {
10275
+ if (options.authSessionUrl) {
10276
+ return String(options.authSessionUrl);
10277
+ }
10278
+ if (options.appOrigin) {
10279
+ return createFreshSessionLookupUrl(options.appOrigin).toString();
10280
+ }
10281
+ return null;
10282
+ }
10283
+ async function getServerSession(options = {}) {
10284
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
10285
+ const skipWithoutCredentials = options.skipFetchWithoutCredentials !== false;
10286
+ const hasExplicitRequestInputs = options.requestHeaders !== void 0 || options.requestCookies !== void 0 || options.sessionDataHeader !== void 0;
10287
+ const requestHeaders = options.requestHeaders ?? (hasExplicitRequestInputs ? {} : void 0);
10288
+ const requestCookies = options.requestCookies ?? (hasExplicitRequestInputs ? "" : void 0);
10289
+ const request2 = await resolveNextRequestContext({
10290
+ requestHeaders,
10291
+ requestCookies,
10292
+ forceNoCache: options.forceNoCache,
10293
+ headers: options.headers
10294
+ });
10295
+ const headerRaw = options.sessionDataHeader !== void 0 ? options.sessionDataHeader : readHeader2(requestHeaders, ATHENA_SESSION_DATA_HEADER) ?? readHeader2(requestHeaders, "x-session-data");
10296
+ let fromSessionDataHeader = false;
10297
+ let session = parseAthenaSessionDataHeader(headerRaw);
10298
+ if (session) {
10299
+ fromSessionDataHeader = true;
10300
+ } else {
10301
+ const hasCredentials = Boolean(request2.cookie || request2.bearerToken);
10302
+ if (!skipWithoutCredentials || hasCredentials) {
10303
+ const lookupUrl = resolveSessionLookupUrl(options);
10304
+ if (lookupUrl) {
10305
+ session = await fetchSessionFromAuth({
10306
+ url: lookupUrl,
10307
+ cookie: request2.cookie,
10308
+ bearerToken: request2.bearerToken,
10309
+ fetchImpl
10310
+ });
10311
+ }
10312
+ }
10313
+ }
10314
+ if (!session) {
10315
+ return {
10316
+ session: null,
10317
+ userId: null,
10318
+ rawActiveOrganizationId: null,
10319
+ organizationId: null,
10320
+ didEnsureActiveOrganization: false,
10321
+ fromSessionDataHeader: false
10322
+ };
10323
+ }
10324
+ const userId = normalizeId(session.user?.id);
10325
+ const rawActiveOrganizationId = normalizeId(session.session?.activeOrganizationId);
10326
+ let organizationId = rawActiveOrganizationId;
10327
+ if (userId && options.resolveActiveOrganizationId) {
10328
+ organizationId = normalizeId(
10329
+ await options.resolveActiveOrganizationId({
10330
+ userId,
10331
+ rawActiveOrganizationId,
10332
+ session
10333
+ })
10334
+ );
10335
+ }
10336
+ let didEnsureActiveOrganization = false;
10337
+ if (options.ensureActiveOrganization && userId) {
10338
+ const sessionForEnsure = {
10339
+ session: {
10340
+ activeOrganizationId: organizationId
10341
+ }
10342
+ };
10343
+ const ensured = await ensureActiveOrganization({
10344
+ session: sessionForEnsure,
10345
+ listOrganizations: options.ensureActiveOrganization.listOrganizations,
10346
+ setActiveOrganization: options.ensureActiveOrganization.setActiveOrganization,
10347
+ selectOrganizationId: options.ensureActiveOrganization.selectOrganizationId,
10348
+ onError: options.ensureActiveOrganization.onError
10349
+ });
10350
+ didEnsureActiveOrganization = ensured.didSetActiveOrganization;
10351
+ if (ensured.activeOrganizationId) {
10352
+ organizationId = ensured.activeOrganizationId;
10353
+ }
10354
+ }
10355
+ return {
10356
+ session,
10357
+ userId,
10358
+ rawActiveOrganizationId,
10359
+ organizationId,
10360
+ didEnsureActiveOrganization,
10361
+ fromSessionDataHeader
10362
+ };
10363
+ }
10364
+
10365
+ // src/next/session-bridge/constants.ts
10366
+ var ATHENA_AUTH_SESSION_BRIDGE_ROUTE = "/api/athena-auth/session";
10367
+ var ATHENA_AUTH_SESSION_COOKIE_NAME = "athena-auth.session-token";
10368
+ var ATHENA_AUTH_SESSION_COOKIE_NAMES = [
10369
+ ATHENA_AUTH_SESSION_COOKIE_NAME,
10370
+ "athena-auth.session_token"
10371
+ ];
10372
+
10373
+ // src/next/session-bridge/client.ts
10374
+ var JSON_CONTENT_TYPE = "application/json";
10375
+ function isBrowserRuntime() {
10376
+ return typeof globalThis !== "undefined" && "window" in globalThis;
10377
+ }
10378
+ async function persistAthenaAuthSessionOnAppHost(payload, options) {
10379
+ if (!(payload && isBrowserRuntime())) {
10380
+ return;
10381
+ }
10382
+ const route = options?.route ?? ATHENA_AUTH_SESSION_BRIDGE_ROUTE;
10383
+ const fetchImpl = options?.fetch ?? fetch;
10384
+ const response = await fetchImpl(route, {
10385
+ body: JSON.stringify(payload),
10386
+ credentials: "same-origin",
10387
+ headers: {
10388
+ "Content-Type": JSON_CONTENT_TYPE
10389
+ },
10390
+ method: "POST"
10391
+ });
10392
+ if (!response.ok) {
10393
+ throw new Error("Failed to persist the Athena Auth session on the app host");
10394
+ }
10395
+ }
10396
+ async function clearAthenaAuthSessionOnAppHost(options) {
10397
+ if (!isBrowserRuntime()) {
10398
+ return;
10399
+ }
10400
+ const route = options?.route ?? ATHENA_AUTH_SESSION_BRIDGE_ROUTE;
10401
+ const fetchImpl = options?.fetch ?? fetch;
10402
+ const response = await fetchImpl(route, {
10403
+ credentials: "same-origin",
10404
+ method: "DELETE"
10405
+ });
10406
+ if (!response.ok) {
10407
+ throw new Error("Failed to clear the Athena Auth session on the app host");
10408
+ }
10409
+ }
10410
+
10411
+ // src/next/session-bridge/payload.ts
10412
+ function resolveSessionBridgePayload(payload) {
10413
+ const token = payload?.session?.token ?? payload?.token;
10414
+ if (typeof token !== "string") {
10415
+ return null;
10416
+ }
10417
+ const normalizedToken = token.trim();
10418
+ if (!normalizedToken) {
10419
+ return null;
10420
+ }
10421
+ return {
10422
+ token: normalizedToken,
10423
+ expiresAt: typeof payload?.session?.expiresAt === "string" ? payload.session.expiresAt : void 0
10424
+ };
10425
+ }
10426
+
10427
+ // src/next/session-bridge/cookie.ts
10428
+ var EXPIRED_AT = /* @__PURE__ */ new Date(0);
10429
+ function resolveRequestIsSecure(request2) {
10430
+ const forwardedProto = request2.headers.get("x-forwarded-proto")?.trim();
10431
+ if (forwardedProto) {
10432
+ const first = forwardedProto.split(",")[0]?.trim().toLowerCase();
10433
+ if (first === "https") return true;
10434
+ if (first === "http") return false;
10435
+ }
10436
+ return new URL(request2.url).protocol === "https:";
10437
+ }
10438
+ function resolveSessionCookieExpiresAt(value) {
10439
+ if (typeof value !== "string") {
10440
+ return void 0;
10441
+ }
10442
+ const expiresAt = new Date(value);
10443
+ return Number.isNaN(expiresAt.getTime()) ? void 0 : expiresAt;
10444
+ }
10445
+ function serializeCookie(name, value, options) {
10446
+ const parts = [
10447
+ `${encodeURIComponent(name)}=${encodeURIComponent(value)}`,
10448
+ `Path=${options.path}`,
10449
+ "HttpOnly",
10450
+ `SameSite=${options.sameSite === "none" ? "None" : options.sameSite === "strict" ? "Strict" : "Lax"}`
10451
+ ];
10452
+ if (options.secure) {
10453
+ parts.push("Secure");
10454
+ }
10455
+ if (options.expires) {
10456
+ parts.push(`Expires=${options.expires.toUTCString()}`);
10457
+ }
10458
+ return parts.join("; ");
10459
+ }
10460
+ function resolveBridgeCookieConfig(options) {
10461
+ return {
10462
+ cookieName: options?.cookieName ?? ATHENA_AUTH_SESSION_COOKIE_NAME,
10463
+ cookieNames: options?.cookieNames ?? ATHENA_AUTH_SESSION_COOKIE_NAMES,
10464
+ cookiePath: options?.cookiePath ?? "/",
10465
+ sameSite: options?.sameSite ?? "lax"
10466
+ };
10467
+ }
10468
+ function appendSessionCookie(headers, request2, token, expiresAt, options) {
10469
+ const config = resolveBridgeCookieConfig(options);
10470
+ const secure = options?.secure ?? resolveRequestIsSecure(request2);
10471
+ headers.append(
10472
+ "set-cookie",
10473
+ serializeCookie(config.cookieName, token, {
10474
+ path: config.cookiePath,
10475
+ sameSite: config.sameSite,
10476
+ secure,
10477
+ expires: expiresAt
10478
+ })
10479
+ );
10480
+ }
10481
+ function appendClearSessionCookies(headers, request2, options) {
10482
+ const config = resolveBridgeCookieConfig(options);
10483
+ const secure = options?.secure ?? resolveRequestIsSecure(request2);
10484
+ const names = /* @__PURE__ */ new Set([config.cookieName, ...config.cookieNames]);
10485
+ for (const name of names) {
10486
+ headers.append(
10487
+ "set-cookie",
10488
+ serializeCookie(name, "", {
10489
+ path: config.cookiePath,
10490
+ sameSite: config.sameSite,
10491
+ secure,
10492
+ expires: EXPIRED_AT
10493
+ })
10494
+ );
10495
+ }
10496
+ }
10497
+
10498
+ // src/next/session-bridge/handlers.ts
10499
+ function json(body, init) {
10500
+ const headers = init?.headers ?? new Headers();
10501
+ if (!headers.has("content-type")) {
10502
+ headers.set("content-type", "application/json; charset=utf-8");
10503
+ }
10504
+ return new Response(JSON.stringify(body), {
10505
+ status: init?.status ?? 200,
10506
+ headers
10507
+ });
10508
+ }
10509
+ function resolveRoute(options) {
10510
+ return options?.route ?? ATHENA_AUTH_SESSION_BRIDGE_ROUTE;
10511
+ }
10512
+ async function handleAthenaAuthSessionBridgePost(request2, options) {
10513
+ const payload = await request2.json().catch(() => null);
10514
+ const token = typeof payload?.token === "string" ? payload.token.trim() : "";
10515
+ if (!token) {
10516
+ return json(
10517
+ {
10518
+ error: "Missing Athena Auth session token"
10519
+ },
10520
+ { status: 400 }
10521
+ );
10522
+ }
10523
+ const headers = new Headers();
10524
+ appendSessionCookie(
10525
+ headers,
10526
+ request2,
10527
+ token,
10528
+ resolveSessionCookieExpiresAt(payload?.expiresAt),
10529
+ options
10530
+ );
10531
+ return json(
10532
+ {
10533
+ ok: true,
10534
+ route: resolveRoute(options)
10535
+ },
10536
+ { headers }
10537
+ );
10538
+ }
10539
+ function handleAthenaAuthSessionBridgeDelete(request2, options) {
10540
+ const headers = new Headers();
10541
+ appendClearSessionCookies(headers, request2, options);
10542
+ return json(
10543
+ {
10544
+ ok: true,
10545
+ route: resolveRoute(options)
10546
+ },
10547
+ { headers }
10548
+ );
10210
10549
  }
10211
- var ATHENA_AUTH_VERIFY_EMAIL_PATH = "verify-email";
10212
- var ATHENA_AUTH_GET_SESSION_PATH = "get-session";
10213
- var ATHENA_AUTH_GET_SESSION_ABSOLUTE_PATH = `${ATHENA_AUTH_PATH}/get-session`;
10214
- var AUTH_SESSION_PATH = ATHENA_AUTH_GET_SESSION_ABSOLUTE_PATH;
10215
- var ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_PARAM = "disableCookieCache";
10216
- var DISABLE_COOKIE_CACHE_QUERY_PARAM = ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_PARAM;
10217
- var ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_VALUE = "true";
10218
- var DISABLE_COOKIE_CACHE_QUERY_VALUE = ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_VALUE;
10219
- var ATHENA_SESSION_DATA_HEADER = "x-session-data";
10220
- var SESSION_DATA_HEADER = ATHENA_SESSION_DATA_HEADER;
10221
- function resolveEmailVerificationCallbackUrl(rawBaseUrl) {
10222
- return resolveAthenaAuthRequestUrl(ATHENA_AUTH_VERIFY_EMAIL_PATH, rawBaseUrl);
10550
+ function createAthenaAuthSessionBridgeHandlers(options) {
10551
+ return {
10552
+ POST: (request2) => handleAthenaAuthSessionBridgePost(request2, options),
10553
+ DELETE: (request2) => handleAthenaAuthSessionBridgeDelete(request2, options)
10554
+ };
10223
10555
  }
10224
- function createFreshSessionLookupUrl(baseUrl) {
10225
- const url = new URL(ATHENA_AUTH_GET_SESSION_ABSOLUTE_PATH, baseUrl);
10226
- url.searchParams.set(
10227
- ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_PARAM,
10228
- ATHENA_AUTH_DISABLE_COOKIE_CACHE_QUERY_VALUE
10556
+ function normalizePathname(pathname) {
10557
+ if (pathname.length > 1 && pathname.endsWith("/")) {
10558
+ return pathname.slice(0, -1);
10559
+ }
10560
+ return pathname || "/";
10561
+ }
10562
+ function isAthenaAuthSessionBridgePath(request2, options) {
10563
+ const pathname = normalizePathname(new URL(request2.url).pathname);
10564
+ const route = normalizePathname(resolveRoute(options));
10565
+ if (pathname === route) {
10566
+ return true;
10567
+ }
10568
+ const matchPaths = options?.matchPaths ?? ["session"];
10569
+ const segments = pathname.split("/").filter(Boolean);
10570
+ const tail = segments[segments.length - 1];
10571
+ return typeof tail === "string" && matchPaths.includes(tail);
10572
+ }
10573
+ function createAthenaAuthSessionBridgePathHandlers(options) {
10574
+ const notFound = () => json(
10575
+ {
10576
+ error: "Not found"
10577
+ },
10578
+ { status: 404 }
10229
10579
  );
10230
- return url;
10580
+ return {
10581
+ POST: async (request2) => {
10582
+ if (!isAthenaAuthSessionBridgePath(request2, options)) {
10583
+ return notFound();
10584
+ }
10585
+ return handleAthenaAuthSessionBridgePost(request2, options);
10586
+ },
10587
+ DELETE: (request2) => {
10588
+ if (!isAthenaAuthSessionBridgePath(request2, options)) {
10589
+ return notFound();
10590
+ }
10591
+ return handleAthenaAuthSessionBridgeDelete(request2, options);
10592
+ }
10593
+ };
10231
10594
  }
10232
10595
 
10233
10596
  // src/utils/auth-routes.ts
@@ -10464,7 +10827,7 @@ function requireEnv(names, env) {
10464
10827
  "requireEnv() requires at least one environment variable name."
10465
10828
  );
10466
10829
  }
10467
- const source = env ?? readProcessEnv3();
10830
+ const source = env ?? readProcessEnv4();
10468
10831
  for (const name of names) {
10469
10832
  const value = source[name]?.trim();
10470
10833
  if (value) {
@@ -10479,7 +10842,7 @@ function readEnv(names, env) {
10479
10842
  if (!names.length) {
10480
10843
  return void 0;
10481
10844
  }
10482
- const source = env ?? readProcessEnv3();
10845
+ const source = env ?? readProcessEnv4();
10483
10846
  for (const name of names) {
10484
10847
  const value = source[name]?.trim();
10485
10848
  if (value) {
@@ -10488,7 +10851,7 @@ function readEnv(names, env) {
10488
10851
  }
10489
10852
  return void 0;
10490
10853
  }
10491
- function readProcessEnv3() {
10854
+ function readProcessEnv4() {
10492
10855
  try {
10493
10856
  const processEnv = globalThis.process?.env;
10494
10857
  return processEnv ?? {};
@@ -10515,79 +10878,469 @@ function proxyRequestHeaders(request2) {
10515
10878
  return headers;
10516
10879
  }
10517
10880
 
10518
- // src/organization/ensure-active-organization.ts
10519
- function normalizeOrganizationId(value) {
10520
- if (typeof value !== "string") {
10521
- return null;
10881
+ // src/tables/catalog.ts
10882
+ var POSTGRES_CATALOG_SQL = {
10883
+ columns: `
10884
+ SELECT
10885
+ n.nspname AS schema_name,
10886
+ c.relname AS table_name,
10887
+ a.attname AS column_name,
10888
+ format_type(a.atttypid, a.atttypmod) AS data_type,
10889
+ NOT a.attnotnull AS is_nullable
10890
+ FROM pg_attribute a
10891
+ JOIN pg_class c ON c.oid = a.attrelid
10892
+ JOIN pg_namespace n ON n.oid = c.relnamespace
10893
+ WHERE c.relkind IN ('r', 'p')
10894
+ AND a.attnum > 0
10895
+ AND NOT a.attisdropped
10896
+ AND n.nspname = ANY($1::text[])
10897
+ ORDER BY n.nspname, c.relname, a.attnum;
10898
+ `,
10899
+ foreignKeys: `
10900
+ SELECT
10901
+ sn.nspname AS source_schema,
10902
+ sc.relname AS source_table,
10903
+ con.conname AS constraint_name,
10904
+ ARRAY_AGG(sa.attname ORDER BY cols.ordinality) AS source_columns,
10905
+ tn.nspname AS target_schema,
10906
+ tc.relname AS target_table,
10907
+ ARRAY_AGG(ta.attname ORDER BY cols.ordinality) AS target_columns,
10908
+ EXISTS (
10909
+ SELECT 1
10910
+ FROM pg_constraint uq
10911
+ WHERE uq.conrelid = con.conrelid
10912
+ AND uq.contype IN ('p', 'u')
10913
+ AND uq.conkey = con.conkey
10914
+ ) AS source_is_unique
10915
+ FROM pg_constraint con
10916
+ JOIN pg_class sc ON sc.oid = con.conrelid
10917
+ JOIN pg_namespace sn ON sn.oid = sc.relnamespace
10918
+ JOIN pg_class tc ON tc.oid = con.confrelid
10919
+ JOIN pg_namespace tn ON tn.oid = tc.relnamespace
10920
+ JOIN unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(source_attnum, target_attnum, ordinality) ON TRUE
10921
+ JOIN pg_attribute sa ON sa.attrelid = con.conrelid AND sa.attnum = cols.source_attnum
10922
+ JOIN pg_attribute ta ON ta.attrelid = con.confrelid AND ta.attnum = cols.target_attnum
10923
+ WHERE con.contype = 'f'
10924
+ AND sn.nspname = ANY($1::text[])
10925
+ AND tn.nspname = ANY($1::text[])
10926
+ GROUP BY
10927
+ sn.nspname,
10928
+ sc.relname,
10929
+ con.conname,
10930
+ tn.nspname,
10931
+ tc.relname,
10932
+ con.conkey,
10933
+ con.conrelid
10934
+ ORDER BY sn.nspname, sc.relname, con.conname;
10935
+ `,
10936
+ primaryKeys: `
10937
+ SELECT
10938
+ n.nspname AS schema_name,
10939
+ c.relname AS table_name,
10940
+ ARRAY_AGG(a.attname ORDER BY ck.ordinality) AS columns
10941
+ FROM pg_constraint con
10942
+ JOIN pg_class c ON c.oid = con.conrelid
10943
+ JOIN pg_namespace n ON n.oid = c.relnamespace
10944
+ JOIN unnest(con.conkey) WITH ORDINALITY AS ck(attnum, ordinality) ON TRUE
10945
+ JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ck.attnum
10946
+ WHERE con.contype = 'p'
10947
+ AND n.nspname = ANY($1::text[])
10948
+ GROUP BY n.nspname, c.relname
10949
+ ORDER BY n.nspname, c.relname;
10950
+ `
10951
+ };
10952
+ function parseAthenaTableSchemaScope(value) {
10953
+ return value.split(",").map((entry) => entry.trim()).filter(
10954
+ (entry, index, values) => entry.length > 0 && values.indexOf(entry) === index
10955
+ );
10956
+ }
10957
+ function escapeSqlLiteral(value) {
10958
+ return value.replace(/'/g, "''");
10959
+ }
10960
+ function buildSchemaArrayLiteral(schemas) {
10961
+ const literals = schemas.map((schema) => `'${escapeSqlLiteral(schema)}'`).join(", ");
10962
+ return `ARRAY[${literals}]`;
10963
+ }
10964
+ function inlineSchemaLiteral(sql, schemas) {
10965
+ return sql.replace(
10966
+ /\$1::text\[\]/g,
10967
+ `${buildSchemaArrayLiteral(schemas)}::text[]`
10968
+ );
10969
+ }
10970
+ function buildAthenaTableCatalogQueries(schemas) {
10971
+ return {
10972
+ columns: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.columns, schemas),
10973
+ foreignKeys: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.foreignKeys, schemas),
10974
+ primaryKeys: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.primaryKeys, schemas)
10975
+ };
10976
+ }
10977
+ function tableKey(schema, table) {
10978
+ return `${schema}.${table}`;
10979
+ }
10980
+ function relationKey(...parts) {
10981
+ const base = parts.join("_").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
10982
+ return base.length > 0 ? base : "relation";
10983
+ }
10984
+ function parsePostgresArrayLiteral(text) {
10985
+ const body = text.slice(1, -1).trim();
10986
+ if (!body) {
10987
+ return [];
10522
10988
  }
10523
- const normalized = value.trim();
10524
- return normalized.length > 0 ? normalized : null;
10989
+ const values = [];
10990
+ let current = "";
10991
+ let inQuotes = false;
10992
+ let escaped = false;
10993
+ for (const char of body) {
10994
+ if (escaped) {
10995
+ current += char;
10996
+ escaped = false;
10997
+ continue;
10998
+ }
10999
+ if (char === "\\") {
11000
+ escaped = true;
11001
+ continue;
11002
+ }
11003
+ if (char === '"') {
11004
+ inQuotes = !inQuotes;
11005
+ continue;
11006
+ }
11007
+ if (char === "," && !inQuotes) {
11008
+ values.push(current);
11009
+ current = "";
11010
+ continue;
11011
+ }
11012
+ current += char;
11013
+ }
11014
+ values.push(current);
11015
+ return values.map((value) => value.trim()).filter((value) => value.length > 0);
10525
11016
  }
10526
- function defaultSelectOrganizationId(organizations) {
10527
- for (const organization of organizations) {
10528
- const id = normalizeOrganizationId(organization.id);
10529
- if (id) {
10530
- return id;
11017
+ function coerceStringArray(value) {
11018
+ if (value == null) {
11019
+ return [];
11020
+ }
11021
+ if (Array.isArray(value)) {
11022
+ return value.map((entry) => entry.trim()).filter(Boolean);
11023
+ }
11024
+ if (typeof value !== "string") {
11025
+ return [];
11026
+ }
11027
+ const trimmedValue = value.trim();
11028
+ if (!trimmedValue) {
11029
+ return [];
11030
+ }
11031
+ if (trimmedValue.startsWith("{") && trimmedValue.endsWith("}")) {
11032
+ return parsePostgresArrayLiteral(trimmedValue);
11033
+ }
11034
+ return trimmedValue.split(",").map((entry) => entry.trim()).filter(Boolean);
11035
+ }
11036
+ function createTableCatalog() {
11037
+ const tables = /* @__PURE__ */ new Map();
11038
+ const ensureTable = (schema, name) => {
11039
+ const id = tableKey(schema, name);
11040
+ const existingTable = tables.get(id);
11041
+ if (existingTable) {
11042
+ return existingTable;
11043
+ }
11044
+ const nextTable = {
11045
+ columns: [],
11046
+ id,
11047
+ name,
11048
+ primaryKey: [],
11049
+ relationMap: /* @__PURE__ */ new Map(),
11050
+ schema
11051
+ };
11052
+ tables.set(id, nextTable);
11053
+ return nextTable;
11054
+ };
11055
+ const upsertRelation = (table, key, relation) => {
11056
+ table.relationMap.set(key, relation);
11057
+ };
11058
+ return {
11059
+ addColumnRows(columnRows) {
11060
+ for (const row of columnRows) {
11061
+ const table = ensureTable(row.schema_name, row.table_name);
11062
+ table.columns.push({
11063
+ dataType: row.data_type,
11064
+ isNullable: row.is_nullable,
11065
+ isPrimaryKey: false,
11066
+ name: row.column_name
11067
+ });
11068
+ }
11069
+ },
11070
+ addForeignKeyRows(foreignKeyRows) {
11071
+ for (const row of foreignKeyRows) {
11072
+ const sourceTable = ensureTable(row.source_schema, row.source_table);
11073
+ const targetTable = ensureTable(row.target_schema, row.target_table);
11074
+ upsertRelation(
11075
+ sourceTable,
11076
+ relationKey(row.constraint_name, row.target_table),
11077
+ {
11078
+ name: row.constraint_name,
11079
+ targetSchema: row.target_schema,
11080
+ targetTable: row.target_table
11081
+ }
11082
+ );
11083
+ upsertRelation(targetTable, relationKey(row.source_table), {
11084
+ name: relationKey(row.source_table, row.constraint_name),
11085
+ targetSchema: row.source_schema,
11086
+ targetTable: row.source_table
11087
+ });
11088
+ }
11089
+ },
11090
+ addManyToManyRows(foreignKeyRows) {
11091
+ const foreignKeysBySourceTable = /* @__PURE__ */ new Map();
11092
+ for (const foreignKey of foreignKeyRows) {
11093
+ const key = tableKey(foreignKey.source_schema, foreignKey.source_table);
11094
+ const current = foreignKeysBySourceTable.get(key) ?? {
11095
+ foreignKeys: [],
11096
+ schema: foreignKey.source_schema,
11097
+ table: foreignKey.source_table
11098
+ };
11099
+ current.foreignKeys.push(foreignKey);
11100
+ foreignKeysBySourceTable.set(key, current);
11101
+ }
11102
+ for (const candidate of foreignKeysBySourceTable.values()) {
11103
+ const bridgeTable = tables.get(
11104
+ tableKey(candidate.schema, candidate.table)
11105
+ );
11106
+ if (!bridgeTable || candidate.foreignKeys.length !== 2) {
11107
+ continue;
11108
+ }
11109
+ const combinedForeignColumns = Array.from(
11110
+ new Set(
11111
+ candidate.foreignKeys.flatMap(
11112
+ (foreignKey) => coerceStringArray(foreignKey.source_columns)
11113
+ )
11114
+ )
11115
+ );
11116
+ if (bridgeTable.primaryKey.length === 0 || combinedForeignColumns.length !== bridgeTable.primaryKey.length || !bridgeTable.primaryKey.every(
11117
+ (column) => combinedForeignColumns.includes(column)
11118
+ )) {
11119
+ continue;
11120
+ }
11121
+ const [firstForeignKey, secondForeignKey] = candidate.foreignKeys;
11122
+ const firstTarget = tables.get(
11123
+ tableKey(firstForeignKey.target_schema, firstForeignKey.target_table)
11124
+ );
11125
+ const secondTarget = tables.get(
11126
+ tableKey(
11127
+ secondForeignKey.target_schema,
11128
+ secondForeignKey.target_table
11129
+ )
11130
+ );
11131
+ if (!(firstTarget && secondTarget)) {
11132
+ continue;
11133
+ }
11134
+ upsertRelation(
11135
+ firstTarget,
11136
+ relationKey(candidate.table, secondForeignKey.target_table),
11137
+ {
11138
+ name: relationKey(
11139
+ candidate.table,
11140
+ secondForeignKey.constraint_name
11141
+ ),
11142
+ targetSchema: secondForeignKey.target_schema,
11143
+ targetTable: secondForeignKey.target_table
11144
+ }
11145
+ );
11146
+ upsertRelation(
11147
+ secondTarget,
11148
+ relationKey(candidate.table, firstForeignKey.target_table),
11149
+ {
11150
+ name: relationKey(candidate.table, firstForeignKey.constraint_name),
11151
+ targetSchema: firstForeignKey.target_schema,
11152
+ targetTable: firstForeignKey.target_table
11153
+ }
11154
+ );
11155
+ }
11156
+ },
11157
+ addPrimaryKeyRows(primaryKeyRows) {
11158
+ for (const row of primaryKeyRows) {
11159
+ const table = ensureTable(row.schema_name, row.table_name);
11160
+ const primaryKey = coerceStringArray(row.columns);
11161
+ table.primaryKey = primaryKey;
11162
+ for (const columnName of primaryKey) {
11163
+ const column = table.columns.find(
11164
+ (candidate) => candidate.name === columnName
11165
+ );
11166
+ if (column) {
11167
+ column.isPrimaryKey = true;
11168
+ }
11169
+ }
11170
+ }
11171
+ },
11172
+ toResponse(database) {
11173
+ return {
11174
+ database,
11175
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11176
+ tables: [...tables.values()].map((table) => ({
11177
+ columns: [...table.columns].sort(
11178
+ (left, right) => left.name.localeCompare(right.name)
11179
+ ),
11180
+ id: table.id,
11181
+ name: table.name,
11182
+ primaryKey: [...table.primaryKey],
11183
+ relations: [...table.relationMap.values()].map((relation) => ({
11184
+ columns: tables.get(
11185
+ tableKey(relation.targetSchema, relation.targetTable)
11186
+ )?.columns ?? [],
11187
+ name: relation.name,
11188
+ targetSchema: relation.targetSchema,
11189
+ targetTable: relation.targetTable
11190
+ })).sort(
11191
+ (left, right) => left.name.localeCompare(right.name)
11192
+ ),
11193
+ schema: table.schema
11194
+ })).sort(
11195
+ (left, right) => left.id.localeCompare(right.id)
11196
+ )
11197
+ };
10531
11198
  }
11199
+ };
11200
+ }
11201
+ async function queryRows(client, query) {
11202
+ const result = await client.query(query);
11203
+ if (result.error || result.status < 200 || result.status >= 300) {
11204
+ const errorMessage = typeof result.error === "string" ? result.error : result.error && typeof result.error === "object" && "message" in result.error && typeof result.error.message === "string" ? result.error.message : `Athena gateway query failed with status ${result.status}.`;
11205
+ throw new Error(errorMessage);
10532
11206
  }
10533
- return null;
11207
+ return Array.isArray(result.data) ? result.data : [];
10534
11208
  }
10535
- async function ensureActiveOrganization(options) {
10536
- const currentActiveOrganizationId = normalizeOrganizationId(
10537
- options.session?.session?.activeOrganizationId
10538
- );
10539
- if (currentActiveOrganizationId) {
11209
+ function isAthenaTableSchemaConfig(value) {
11210
+ if (typeof value !== "object" || value === null) {
11211
+ return false;
11212
+ }
11213
+ const config = value;
11214
+ return typeof config.gatewayUrl === "string" && typeof config.gatewayKey === "string" && typeof config.gatewayDatabase === "string" && typeof config.schemaScope === "string" && typeof config.clientName === "string";
11215
+ }
11216
+ function hasAthenaTableSchemaCredentials(config) {
11217
+ return config.gatewayUrl.trim().length > 0 && config.gatewayKey.trim().length > 0 && config.gatewayDatabase.trim().length > 0;
11218
+ }
11219
+ async function fetchAthenaTableCatalog(config, options = {}) {
11220
+ const schemas = parseAthenaTableSchemaScope(config.schemaScope);
11221
+ if (schemas.length === 0) {
10540
11222
  return {
10541
- activeOrganizationId: currentActiveOrganizationId,
10542
- didSetActiveOrganization: false
11223
+ database: config.gatewayDatabase,
11224
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11225
+ tables: []
10543
11226
  };
10544
11227
  }
10545
- let organizations;
11228
+ const queries = buildAthenaTableCatalogQueries(schemas);
11229
+ const client = options.client ?? createClient({
11230
+ url: config.gatewayUrl.trim(),
11231
+ key: config.gatewayKey.trim(),
11232
+ client: config.clientName.trim() || void 0
11233
+ });
11234
+ const [columnRows, primaryKeyRows, foreignKeyRows] = await Promise.all([
11235
+ queryRows(client, queries.columns),
11236
+ queryRows(client, queries.primaryKeys),
11237
+ queryRows(client, queries.foreignKeys)
11238
+ ]);
11239
+ const catalog = createTableCatalog();
11240
+ catalog.addColumnRows(columnRows);
11241
+ catalog.addPrimaryKeyRows(primaryKeyRows);
11242
+ catalog.addForeignKeyRows(foreignKeyRows);
11243
+ catalog.addManyToManyRows(foreignKeyRows);
11244
+ return catalog.toResponse(config.gatewayDatabase);
11245
+ }
11246
+ var fetchTableCatalog = fetchAthenaTableCatalog;
11247
+
11248
+ // src/tables/schema-handlers.ts
11249
+ var ATHENA_TABLE_SCHEMA_ROUTE = "/api/tables/schema";
11250
+ function json2(body, init) {
11251
+ const headers = new Headers(init?.headers);
11252
+ if (!headers.has("content-type")) {
11253
+ headers.set("content-type", "application/json; charset=utf-8");
11254
+ }
11255
+ return new Response(JSON.stringify(body), {
11256
+ status: init?.status ?? 200,
11257
+ headers
11258
+ });
11259
+ }
11260
+ async function handleAthenaTableSchemaPost(request2, options) {
11261
+ const payload = await request2.json().catch(() => null);
11262
+ let config = isAthenaTableSchemaConfig(
11263
+ payload?.config
11264
+ ) ? payload.config : null;
11265
+ if (config && options?.resolveConfig) {
11266
+ config = await options.resolveConfig(config, request2);
11267
+ }
11268
+ if (!config || !isAthenaTableSchemaConfig(config)) {
11269
+ return json2(
11270
+ {
11271
+ error: "The Athena tables showcase config is invalid."
11272
+ },
11273
+ { status: 400 }
11274
+ );
11275
+ }
11276
+ if (!hasAthenaTableSchemaCredentials(config)) {
11277
+ return json2(
11278
+ {
11279
+ error: "Gateway URL, API key, and database are required for schema introspection."
11280
+ },
11281
+ { status: 400 }
11282
+ );
11283
+ }
10546
11284
  try {
10547
- organizations = await options.listOrganizations();
11285
+ const response = await fetchAthenaTableCatalog(
11286
+ config,
11287
+ {
11288
+ client: options?.client
11289
+ }
11290
+ );
11291
+ return json2(response);
10548
11292
  } catch (error) {
10549
- options.onError?.(error);
10550
- return {
10551
- activeOrganizationId: null,
10552
- didSetActiveOrganization: false
10553
- };
11293
+ return json2(
11294
+ {
11295
+ error: error instanceof Error ? error.message : "Athena schema introspection failed."
11296
+ },
11297
+ { status: 500 }
11298
+ );
10554
11299
  }
10555
- if (organizations.length === 0) {
10556
- return {
10557
- activeOrganizationId: null,
10558
- didSetActiveOrganization: false
10559
- };
11300
+ }
11301
+ function createAthenaTableSchemaHandlers(options) {
11302
+ return {
11303
+ POST: (request2) => handleAthenaTableSchemaPost(request2, options)
11304
+ };
11305
+ }
11306
+
11307
+ // src/next/server.ts
11308
+ function warnEmptyServerScope() {
11309
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
11310
+ return;
10560
11311
  }
10561
- const selectedOrganizationId = normalizeOrganizationId(
10562
- (options.selectOrganizationId ?? defaultSelectOrganizationId)(organizations)
11312
+ console.warn(
11313
+ "[athena] createAthenaServerClient/resolveAthenaServerContext: `scope` was provided without userId or organizationId. Gateway identity headers will not be set from scope. Pass at least one field, or omit scope."
10563
11314
  );
10564
- if (!selectedOrganizationId) {
11315
+ }
11316
+ function resolveServerIdentity(options) {
11317
+ const session = options.session ?? null;
11318
+ const sessionUserId = session?.user?.id ?? null;
11319
+ const sessionOrganizationId = session?.session?.activeOrganizationId ?? null;
11320
+ const scope = options.scope;
11321
+ if (scope === void 0) {
10565
11322
  return {
10566
- activeOrganizationId: null,
10567
- didSetActiveOrganization: false
11323
+ userId: sessionUserId,
11324
+ organizationId: sessionOrganizationId
10568
11325
  };
10569
11326
  }
10570
- try {
10571
- await options.setActiveOrganization(selectedOrganizationId);
10572
- return {
10573
- activeOrganizationId: selectedOrganizationId,
10574
- didSetActiveOrganization: true
10575
- };
10576
- } catch (error) {
10577
- options.onError?.(error);
10578
- return {
10579
- activeOrganizationId: null,
10580
- didSetActiveOrganization: false
10581
- };
11327
+ const scopeHasUserId = Object.hasOwn(scope, "userId");
11328
+ const scopeHasOrganizationId = Object.hasOwn(scope, "organizationId");
11329
+ if (!scopeHasUserId && !scopeHasOrganizationId) {
11330
+ warnEmptyServerScope();
10582
11331
  }
11332
+ return {
11333
+ userId: scopeHasUserId ? scope.userId ?? null : sessionUserId,
11334
+ organizationId: scopeHasOrganizationId ? scope.organizationId ?? null : sessionOrganizationId
11335
+ };
10583
11336
  }
10584
-
10585
- // src/next/server.ts
10586
11337
  async function resolveAthenaServerContext(options = {}) {
10587
11338
  const request2 = await resolveNextRequestContext(options);
10588
11339
  const session = options.session ?? null;
10589
- const userId = session?.user?.id ?? null;
10590
- const organizationId = session?.session?.activeOrganizationId ?? null;
11340
+ const { userId, organizationId } = resolveServerIdentity({
11341
+ session,
11342
+ scope: options.scope
11343
+ });
10591
11344
  return {
10592
11345
  request: {
10593
11346
  ...request2,
@@ -10605,6 +11358,7 @@ async function createAthenaServerClient(options) {
10605
11358
  requestCookies,
10606
11359
  forceNoCache,
10607
11360
  session,
11361
+ scope,
10608
11362
  headers: requestScopedHeaders,
10609
11363
  ...clientConfig
10610
11364
  } = options;
@@ -10613,7 +11367,8 @@ async function createAthenaServerClient(options) {
10613
11367
  requestCookies,
10614
11368
  forceNoCache,
10615
11369
  headers: requestScopedHeaders,
10616
- session
11370
+ session,
11371
+ scope
10617
11372
  });
10618
11373
  const configuredContext = clientConfig.context;
10619
11374
  return createClient({
@@ -10638,6 +11393,7 @@ exports.ATHENA_AUTH_UPSTREAM_ENV_KEYS = ATHENA_AUTH_UPSTREAM_ENV_KEYS;
10638
11393
  exports.ATHENA_AUTH_UPSTREAM_URL_ENV_NAMES = ATHENA_AUTH_UPSTREAM_URL_ENV_NAMES;
10639
11394
  exports.ATHENA_AUTH_VERIFY_EMAIL_PATH = ATHENA_AUTH_VERIFY_EMAIL_PATH;
10640
11395
  exports.ATHENA_SESSION_DATA_HEADER = ATHENA_SESSION_DATA_HEADER;
11396
+ exports.ATHENA_TABLE_SCHEMA_ROUTE = ATHENA_TABLE_SCHEMA_ROUTE;
10641
11397
  exports.AUTHENTICATED_REDIRECT_MODE_SET = AUTHENTICATED_REDIRECT_MODE_SET;
10642
11398
  exports.AUTHENTICATED_REDIRECT_VIEW_SET = AUTHENTICATED_REDIRECT_VIEW_SET;
10643
11399
  exports.AUTH_DEFAULT_VIEW = AUTH_DEFAULT_VIEW;
@@ -10661,26 +11417,36 @@ exports.asNonEmptyString = asNonEmptyString;
10661
11417
  exports.asString = asString;
10662
11418
  exports.buildAthenaGatewayHeaders = buildAthenaGatewayHeaders;
10663
11419
  exports.buildAthenaRequestHeaders = buildAthenaRequestHeaders;
11420
+ exports.buildAthenaTableCatalogQueries = buildAthenaTableCatalogQueries;
10664
11421
  exports.buildServiceRequestHeaders = buildServiceRequestHeaders;
10665
11422
  exports.clearAthenaAuthSessionOnAppHost = clearAthenaAuthSessionOnAppHost;
10666
11423
  exports.clearAuthCookies = clearAuthCookies;
10667
11424
  exports.createAthenaAuthSessionBridgeHandlers = createAthenaAuthSessionBridgeHandlers;
10668
11425
  exports.createAthenaAuthSessionBridgePathHandlers = createAthenaAuthSessionBridgePathHandlers;
10669
11426
  exports.createAthenaServerClient = createAthenaServerClient;
11427
+ exports.createAthenaTableSchemaHandlers = createAthenaTableSchemaHandlers;
10670
11428
  exports.createAuthModeRedirects = createAuthModeRedirects;
10671
11429
  exports.createAuthRoutes = createAuthRoutes;
10672
11430
  exports.createFreshSessionLookupUrl = createFreshSessionLookupUrl;
10673
11431
  exports.ensureActiveOrganization = ensureActiveOrganization;
11432
+ exports.fetchAthenaTableCatalog = fetchAthenaTableCatalog;
11433
+ exports.fetchTableCatalog = fetchTableCatalog;
10674
11434
  exports.getOriginFromHeaders = getOriginFromHeaders;
11435
+ exports.getServerSession = getServerSession;
10675
11436
  exports.handleAthenaAuthSessionBridgeDelete = handleAthenaAuthSessionBridgeDelete;
10676
11437
  exports.handleAthenaAuthSessionBridgePost = handleAthenaAuthSessionBridgePost;
11438
+ exports.handleAthenaTableSchemaPost = handleAthenaTableSchemaPost;
11439
+ exports.hasAthenaTableSchemaCredentials = hasAthenaTableSchemaCredentials;
10677
11440
  exports.hasAuthSessionCookie = hasAuthSessionCookie;
10678
11441
  exports.hasHeaderIgnoreCase = hasHeaderIgnoreCase;
10679
11442
  exports.isAbsoluteUrl = isAbsoluteUrl;
10680
11443
  exports.isAthenaAuthSessionBridgePath = isAthenaAuthSessionBridgePath;
11444
+ exports.isAthenaTableSchemaConfig = isAthenaTableSchemaConfig;
10681
11445
  exports.isAuthMode = isAuthMode;
10682
11446
  exports.isDynamicServerUsageError = isDynamicServerUsageError;
10683
11447
  exports.normalizeAthenaAuthBaseUrl = normalizeAthenaAuthBaseUrl;
11448
+ exports.parseAthenaSessionDataHeader = parseAthenaSessionDataHeader;
11449
+ exports.parseAthenaTableSchemaScope = parseAthenaTableSchemaScope;
10684
11450
  exports.persistAthenaAuthSessionOnAppHost = persistAthenaAuthSessionOnAppHost;
10685
11451
  exports.proxyRequestHeaders = proxyRequestHeaders;
10686
11452
  exports.readAthenaAuthUpstreamUrlFromEnv = readAthenaAuthUpstreamUrlFromEnv;