@augmenting-integrations/auth 5.0.1 → 8.0.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.
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var tenant_exports = {};
31
+ __export(tenant_exports, {
32
+ TENANT_GLOBAL_KEY: () => import_tenant_types2.TENANT_GLOBAL_KEY,
33
+ TenantProvider: () => TenantProvider,
34
+ useTenant: () => useTenant
35
+ });
36
+ module.exports = __toCommonJS(tenant_exports);
37
+ var React = __toESM(require("react"));
38
+ var import_tenant_types = require("../tenant-types.js");
39
+ var import_tenant_types2 = require("../tenant-types.js");
40
+ const TenantContext = React.createContext(null);
41
+ function TenantProvider({
42
+ tenant,
43
+ children
44
+ }) {
45
+ return React.createElement(TenantContext.Provider, { value: tenant }, children);
46
+ }
47
+ function useTenant() {
48
+ const ctx = React.useContext(TenantContext);
49
+ if (ctx) return ctx;
50
+ if (typeof window !== "undefined") {
51
+ const fromGlobal = window[import_tenant_types.TENANT_GLOBAL_KEY];
52
+ if (fromGlobal) return fromGlobal;
53
+ }
54
+ throw new Error(
55
+ "useTenant() called outside <TenantProvider> and before <TenantBootScript /> ran. Mount both in the root layout."
56
+ );
57
+ }
58
+ // Annotate the CommonJS export names for ESM import in node:
59
+ 0 && (module.exports = {
60
+ TENANT_GLOBAL_KEY,
61
+ TenantProvider,
62
+ useTenant
63
+ });
64
+ //# sourceMappingURL=tenant.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/tenant.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { TENANT_GLOBAL_KEY, type TenantPublicConfig } from \"../tenant-types.js\";\n\n// =============================================================================\n// <TenantProvider> + useTenant()\n//\n// Single source of tenant truth on the client. Rendered server-side as part\n// of the root layout; reads the same TenantPublicConfig passed to\n// <TenantBootScript />. The Context value flows through SSR, so server\n// components rendered as children + every client component can call\n// useTenant() without worrying about hydration order.\n//\n// We also accept window.__TENANT__ as a fallback for non-React widgets and\n// for the rare case of a client component rendered outside the Provider\n// tree (a defensive read).\n// =============================================================================\n\nconst TenantContext = React.createContext<TenantPublicConfig | null>(null);\n\nexport function TenantProvider({\n tenant,\n children,\n}: {\n tenant: TenantPublicConfig;\n children: React.ReactNode;\n}) {\n return React.createElement(TenantContext.Provider, { value: tenant }, children);\n}\n\nexport function useTenant(): TenantPublicConfig {\n const ctx = React.useContext(TenantContext);\n if (ctx) return ctx;\n // Defensive fallback: a non-Provider client widget. Only works after\n // <TenantBootScript /> has run.\n if (typeof window !== \"undefined\") {\n const fromGlobal = window[TENANT_GLOBAL_KEY];\n if (fromGlobal) return fromGlobal;\n }\n throw new Error(\n \"useTenant() called outside <TenantProvider> and before <TenantBootScript /> ran. Mount both in the root layout.\",\n );\n}\n\nexport {\n TENANT_GLOBAL_KEY,\n type TenantPublicConfig,\n type TenantRole,\n} from \"../tenant-types.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,YAAuB;AACvB,0BAA2D;AA0C3D,IAAAA,uBAIO;AA9BP,MAAM,gBAAgB,MAAM,cAAyC,IAAI;AAElE,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AACF,GAGG;AACD,SAAO,MAAM,cAAc,cAAc,UAAU,EAAE,OAAO,OAAO,GAAG,QAAQ;AAChF;AAEO,SAAS,YAAgC;AAC9C,QAAM,MAAM,MAAM,WAAW,aAAa;AAC1C,MAAI,IAAK,QAAO;AAGhB,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,aAAa,OAAO,qCAAiB;AAC3C,QAAI,WAAY,QAAO;AAAA,EACzB;AACA,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;","names":["import_tenant_types"]}
@@ -0,0 +1,9 @@
1
+ import * as React from "react";
2
+ import { type TenantPublicConfig } from "../tenant-types.js";
3
+ export declare function TenantProvider({ tenant, children, }: {
4
+ tenant: TenantPublicConfig;
5
+ children: React.ReactNode;
6
+ }): React.FunctionComponentElement<React.ProviderProps<TenantPublicConfig | null>>;
7
+ export declare function useTenant(): TenantPublicConfig;
8
+ export { TENANT_GLOBAL_KEY, type TenantPublicConfig, type TenantRole, } from "../tenant-types.js";
9
+ //# sourceMappingURL=tenant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/client/tenant.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAkBhF,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,kFAEA;AAED,wBAAgB,SAAS,IAAI,kBAAkB,CAY9C;AAED,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { TENANT_GLOBAL_KEY } from "../tenant-types.js";
4
+ const TenantContext = React.createContext(null);
5
+ function TenantProvider({
6
+ tenant,
7
+ children
8
+ }) {
9
+ return React.createElement(TenantContext.Provider, { value: tenant }, children);
10
+ }
11
+ function useTenant() {
12
+ const ctx = React.useContext(TenantContext);
13
+ if (ctx) return ctx;
14
+ if (typeof window !== "undefined") {
15
+ const fromGlobal = window[TENANT_GLOBAL_KEY];
16
+ if (fromGlobal) return fromGlobal;
17
+ }
18
+ throw new Error(
19
+ "useTenant() called outside <TenantProvider> and before <TenantBootScript /> ran. Mount both in the root layout."
20
+ );
21
+ }
22
+ import {
23
+ TENANT_GLOBAL_KEY as TENANT_GLOBAL_KEY2
24
+ } from "../tenant-types.js";
25
+ export {
26
+ TENANT_GLOBAL_KEY2 as TENANT_GLOBAL_KEY,
27
+ TenantProvider,
28
+ useTenant
29
+ };
30
+ //# sourceMappingURL=tenant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/tenant.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { TENANT_GLOBAL_KEY, type TenantPublicConfig } from \"../tenant-types.js\";\n\n// =============================================================================\n// <TenantProvider> + useTenant()\n//\n// Single source of tenant truth on the client. Rendered server-side as part\n// of the root layout; reads the same TenantPublicConfig passed to\n// <TenantBootScript />. The Context value flows through SSR, so server\n// components rendered as children + every client component can call\n// useTenant() without worrying about hydration order.\n//\n// We also accept window.__TENANT__ as a fallback for non-React widgets and\n// for the rare case of a client component rendered outside the Provider\n// tree (a defensive read).\n// =============================================================================\n\nconst TenantContext = React.createContext<TenantPublicConfig | null>(null);\n\nexport function TenantProvider({\n tenant,\n children,\n}: {\n tenant: TenantPublicConfig;\n children: React.ReactNode;\n}) {\n return React.createElement(TenantContext.Provider, { value: tenant }, children);\n}\n\nexport function useTenant(): TenantPublicConfig {\n const ctx = React.useContext(TenantContext);\n if (ctx) return ctx;\n // Defensive fallback: a non-Provider client widget. Only works after\n // <TenantBootScript /> has run.\n if (typeof window !== \"undefined\") {\n const fromGlobal = window[TENANT_GLOBAL_KEY];\n if (fromGlobal) return fromGlobal;\n }\n throw new Error(\n \"useTenant() called outside <TenantProvider> and before <TenantBootScript /> ran. Mount both in the root layout.\",\n );\n}\n\nexport {\n TENANT_GLOBAL_KEY,\n type TenantPublicConfig,\n type TenantRole,\n} from \"../tenant-types.js\";\n"],"mappings":";AAEA,YAAY,WAAW;AACvB,SAAS,yBAAkD;AAgB3D,MAAM,gBAAgB,MAAM,cAAyC,IAAI;AAElE,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AACF,GAGG;AACD,SAAO,MAAM,cAAc,cAAc,UAAU,EAAE,OAAO,OAAO,GAAG,QAAQ;AAChF;AAEO,SAAS,YAAgC;AAC9C,QAAM,MAAM,MAAM,WAAW,aAAa;AAC1C,MAAI,IAAK,QAAO;AAGhB,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,aAAa,OAAO,iBAAiB;AAC3C,QAAI,WAAY,QAAO;AAAA,EACzB;AACA,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAEA;AAAA,EACE,qBAAAA;AAAA,OAGK;","names":["TENANT_GLOBAL_KEY"]}
package/dist/client.cjs CHANGED
@@ -21,11 +21,14 @@ __export(client_exports, {
21
21
  AppUserProvider: () => import_AppUserProvider.AppUserProvider,
22
22
  ImpersonationBanner: () => import_ImpersonationBanner.ImpersonationBanner,
23
23
  SignOutButton: () => import_SignOutButton.SignOutButton,
24
+ TENANT_GLOBAL_KEY: () => import_tenant.TENANT_GLOBAL_KEY,
25
+ TenantProvider: () => import_tenant.TenantProvider,
24
26
  UserMenu: () => import_UserMenu.UserMenu,
25
27
  useAppUser: () => import_AppUserProvider.useAppUser,
26
28
  useDbAppUser: () => import_AppUserProvider.useDbAppUser,
27
29
  useImpersonation: () => import_use_impersonation.useImpersonation,
28
- useRole: () => import_AppUserProvider.useRole
30
+ useRole: () => import_AppUserProvider.useRole,
31
+ useTenant: () => import_tenant.useTenant
29
32
  });
30
33
  module.exports = __toCommonJS(client_exports);
31
34
  var import_AppUserProvider = require("./client/AppUserProvider.js");
@@ -33,15 +36,19 @@ var import_UserMenu = require("./client/UserMenu.js");
33
36
  var import_SignOutButton = require("./client/SignOutButton.js");
34
37
  var import_ImpersonationBanner = require("./client/ImpersonationBanner.js");
35
38
  var import_use_impersonation = require("./client/use-impersonation.js");
39
+ var import_tenant = require("./client/tenant.js");
36
40
  // Annotate the CommonJS export names for ESM import in node:
37
41
  0 && (module.exports = {
38
42
  AppUserProvider,
39
43
  ImpersonationBanner,
40
44
  SignOutButton,
45
+ TENANT_GLOBAL_KEY,
46
+ TenantProvider,
41
47
  UserMenu,
42
48
  useAppUser,
43
49
  useDbAppUser,
44
50
  useImpersonation,
45
- useRole
51
+ useRole,
52
+ useTenant
46
53
  });
47
54
  //# sourceMappingURL=client.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["export {\n AppUserProvider,\n useAppUser,\n useDbAppUser,\n useRole,\n type AppUserState,\n type DbAppUser,\n type SessionAppUser,\n} from \"./client/AppUserProvider.js\";\nexport { UserMenu } from \"./client/UserMenu.js\";\nexport { SignOutButton } from \"./client/SignOutButton.js\";\nexport { ImpersonationBanner } from \"./client/ImpersonationBanner.js\";\nexport {\n useImpersonation,\n type EffectiveUser,\n type ImpersonatedBy,\n type MeResponse,\n} from \"./client/use-impersonation.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAQO;AACP,sBAAyB;AACzB,2BAA8B;AAC9B,iCAAoC;AACpC,+BAKO;","names":[]}
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["export {\n AppUserProvider,\n useAppUser,\n useDbAppUser,\n useRole,\n type AppUserState,\n type DbAppUser,\n type SessionAppUser,\n} from \"./client/AppUserProvider.js\";\nexport { UserMenu } from \"./client/UserMenu.js\";\nexport { SignOutButton } from \"./client/SignOutButton.js\";\nexport { ImpersonationBanner } from \"./client/ImpersonationBanner.js\";\nexport {\n useImpersonation,\n type EffectiveUser,\n type ImpersonatedBy,\n type MeResponse,\n} from \"./client/use-impersonation.js\";\nexport {\n TenantProvider,\n useTenant,\n TENANT_GLOBAL_KEY,\n type TenantPublicConfig,\n type TenantRole,\n} from \"./client/tenant.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAQO;AACP,sBAAyB;AACzB,2BAA8B;AAC9B,iCAAoC;AACpC,+BAKO;AACP,oBAMO;","names":[]}
package/dist/client.d.ts CHANGED
@@ -3,4 +3,5 @@ export { UserMenu } from "./client/UserMenu.js";
3
3
  export { SignOutButton } from "./client/SignOutButton.js";
4
4
  export { ImpersonationBanner } from "./client/ImpersonationBanner.js";
5
5
  export { useImpersonation, type EffectiveUser, type ImpersonatedBy, type MeResponse, } from "./client/use-impersonation.js";
6
+ export { TenantProvider, useTenant, TENANT_GLOBAL_KEY, type TenantPublicConfig, type TenantRole, } from "./client/tenant.js";
6
7
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,OAAO,EACP,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EACL,gBAAgB,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,UAAU,GAChB,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,OAAO,EACP,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EACL,gBAAgB,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,UAAU,GAChB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,cAAc,EACd,SAAS,EACT,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC"}
package/dist/client.js CHANGED
@@ -10,14 +10,22 @@ import { ImpersonationBanner } from "./client/ImpersonationBanner.js";
10
10
  import {
11
11
  useImpersonation
12
12
  } from "./client/use-impersonation.js";
13
+ import {
14
+ TenantProvider,
15
+ useTenant,
16
+ TENANT_GLOBAL_KEY
17
+ } from "./client/tenant.js";
13
18
  export {
14
19
  AppUserProvider,
15
20
  ImpersonationBanner,
16
21
  SignOutButton,
22
+ TENANT_GLOBAL_KEY,
23
+ TenantProvider,
17
24
  UserMenu,
18
25
  useAppUser,
19
26
  useDbAppUser,
20
27
  useImpersonation,
21
- useRole
28
+ useRole,
29
+ useTenant
22
30
  };
23
31
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["export {\n AppUserProvider,\n useAppUser,\n useDbAppUser,\n useRole,\n type AppUserState,\n type DbAppUser,\n type SessionAppUser,\n} from \"./client/AppUserProvider.js\";\nexport { UserMenu } from \"./client/UserMenu.js\";\nexport { SignOutButton } from \"./client/SignOutButton.js\";\nexport { ImpersonationBanner } from \"./client/ImpersonationBanner.js\";\nexport {\n useImpersonation,\n type EffectiveUser,\n type ImpersonatedBy,\n type MeResponse,\n} from \"./client/use-impersonation.js\";\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,OAIK;","names":[]}
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["export {\n AppUserProvider,\n useAppUser,\n useDbAppUser,\n useRole,\n type AppUserState,\n type DbAppUser,\n type SessionAppUser,\n} from \"./client/AppUserProvider.js\";\nexport { UserMenu } from \"./client/UserMenu.js\";\nexport { SignOutButton } from \"./client/SignOutButton.js\";\nexport { ImpersonationBanner } from \"./client/ImpersonationBanner.js\";\nexport {\n useImpersonation,\n type EffectiveUser,\n type ImpersonatedBy,\n type MeResponse,\n} from \"./client/use-impersonation.js\";\nexport {\n TenantProvider,\n useTenant,\n TENANT_GLOBAL_KEY,\n type TenantPublicConfig,\n type TenantRole,\n} from \"./client/tenant.js\";\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,OAIK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;","names":[]}
@@ -1,58 +1,43 @@
1
1
  import { type DefaultSession, type Session } from "next-auth";
2
+ import type { TenantServerConfig } from "../tenant-types.js";
2
3
  declare module "next-auth" {
3
4
  interface Session {
4
5
  user: {
5
6
  groups: string[];
6
- role: string;
7
7
  } & DefaultSession["user"];
8
8
  }
9
9
  interface User {
10
- role?: string;
11
10
  groups?: string[];
12
11
  }
13
12
  }
14
13
  export type CreateAuthOptions = {
15
- /** Path prefixes that require an authenticated session. */
16
- authedRoutePrefixes: string[];
17
14
  /**
18
- * Page to redirect to when an unauthed user hits a gated route.
19
- * If omitted, derived automatically from appDomain + allowedParentDomain:
20
- * apex app gets `/login`; subdomain apps get `https://<apex>/login`.
15
+ * Full tenant configuration. Provides apex/cookieDomain/parentDomain/
16
+ * appDomain/role + cognito client id + issuer + allowed admin emails.
17
+ * Load via `loadTenantConfig()` from `@augmenting-integrations/tenant/server`.
21
18
  */
22
- signInPage?: string;
19
+ tenant: TenantServerConfig;
20
+ /** Path prefixes that require an authenticated session. */
21
+ authedRoutePrefixes: string[];
23
22
  /**
24
- * Cookie Domain attribute. In subdomain ecosystems, set to the parent
25
- * (e.g. `.agency.aillc.link`). Default: process.env.AUTH_COOKIE_DOMAIN.
26
- * In dev (NODE_ENV !== "production") this is ignored — cookies stay
27
- * host-only so per-port localhost apps don't collide.
23
+ * JWT signing secret. Caller fetches from Secrets Manager via
24
+ * `getSecret(tenant.authSecretArn)` and passes the resolved value here.
25
+ * The library doesn't bundle AWS SDK reads itself.
28
26
  */
29
- cookieDomain?: string;
27
+ authSecret: string;
30
28
  /**
31
- * The parent domain that all subdomain apps share (e.g.
32
- * `.agency.aillc.link`). The redirect callback uses this to allow
33
- * post-login redirects back to any subdomain of the parent (apex or
34
- * `<sub>.agency.aillc.link`). Default: process.env.AUTH_ALLOWED_PARENT_DOMAIN.
29
+ * Cognito OAuth client secret. Apex apps only -- spokes never run the
30
+ * OAuth dance. Caller fetches from Secrets Manager via
31
+ * `getSecret(tenant.authCognitoSecretArn)`.
35
32
  */
36
- allowedParentDomain?: string;
33
+ cognitoClientSecret?: string;
37
34
  /**
38
- * This app's full FQDN (e.g. `agency.aillc.link` for the apex app, or
39
- * `leads.agency.aillc.link` for a subdomain app). Used to derive the
40
- * default signInPage. Default: process.env.APP_DOMAIN.
35
+ * Override the auto-derived sign-in page (rarely needed). Default:
36
+ * apex apps get `/login`; spoke apps get `https://<apex>/login`.
41
37
  */
42
- appDomain?: string;
38
+ signInPage?: string;
43
39
  /** Override prod/dev detection. Default reads NODE_ENV. */
44
40
  isProd?: boolean;
45
- /**
46
- * The JWT signing secret. Default: process.env.AUTH_SECRET.
47
- * In prod, pass this from a runtime fetch (Secrets Manager) to keep the
48
- * secret out of Lambda env vars and to support rotation without redeploy.
49
- */
50
- secret?: string;
51
- cognito?: {
52
- clientId?: string;
53
- clientSecret?: string;
54
- issuer?: string;
55
- };
56
41
  };
57
42
  export declare class AuthError extends Error {
58
43
  code: "unauthenticated" | "forbidden";
@@ -1 +1 @@
1
- {"version":3,"file":"createAuth.d.ts","sourceRoot":"","sources":["../../src/server/createAuth.ts"],"names":[],"mappings":"AAkBA,OAAiB,EACf,KAAK,cAAc,EAEnB,KAAK,OAAO,EACb,MAAM,WAAW,CAAC;AAInB,OAAO,QAAQ,WAAW,CAAC;IACzB,UAAU,OAAO;QACf,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM,EAAE,CAAC;YACjB,IAAI,EAAE,MAAM,CAAC;SACd,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;KAC5B;IACD,UAAU,IAAI;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB;CACF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2DAA2D;IAC3D,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH,CAAC;AAIF,qBAAa,SAAU,SAAQ,KAAK;IACf,IAAI,EAAE,iBAAiB,GAAG,WAAW;gBAArC,IAAI,EAAE,iBAAiB,GAAG,WAAW;CAIzD;AAID,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAE3E;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAInF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,EACnC,GAAG,KAAK,EAAE,MAAM,EAAE,GACjB,IAAI,CAKN;AAyFD,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,sCAgJjD;AAED,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"createAuth.d.ts","sourceRoot":"","sources":["../../src/server/createAuth.ts"],"names":[],"mappings":"AAkBA,OAAiB,EACf,KAAK,cAAc,EAEnB,KAAK,OAAO,EACb,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAM7D,OAAO,QAAQ,WAAW,CAAC;IACzB,UAAU,OAAO;QACf,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM,EAAE,CAAC;SAClB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;KAC5B;IACD,UAAU,IAAI;QACZ,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB;CACF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,MAAM,EAAE,kBAAkB,CAAC;IAC3B,2DAA2D;IAC3D,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAIF,qBAAa,SAAU,SAAQ,KAAK;IACf,IAAI,EAAE,iBAAiB,GAAG,WAAW;gBAArC,IAAI,EAAE,iBAAiB,GAAG,WAAW;CAIzD;AAID,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAE3E;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAInF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,EACnC,GAAG,KAAK,EAAE,MAAM,EAAE,GACjB,IAAI,CAKN;AA+BD,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,sCAmIjD;AAED,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,26 @@
1
+ import "server-only";
2
+ import * as React from "react";
3
+ import { type TenantPublicConfig, type TenantRole, type TenantServerConfig } from "../tenant-types.js";
4
+ export type LoadOptions = {
5
+ role: TenantRole;
6
+ /**
7
+ * Override env reads with explicit values (useful for tests).
8
+ */
9
+ overrides?: Partial<TenantServerConfig>;
10
+ };
11
+ /**
12
+ * Read tenant configuration from process.env with optional overrides.
13
+ * Throws a single Error listing every missing required field.
14
+ */
15
+ export declare function loadTenantConfig(opts: LoadOptions): TenantServerConfig;
16
+ /**
17
+ * Reduce a TenantServerConfig to the public-safe subset. Strips every
18
+ * secret-arn so the result is safe to ship to the browser via
19
+ * <TenantBootScript />.
20
+ */
21
+ export declare function publicSubset(config: TenantServerConfig): TenantPublicConfig;
22
+ export declare function TenantBootScript({ config }: {
23
+ config: TenantPublicConfig;
24
+ }): React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
25
+ export { TENANT_GLOBAL_KEY, type TenantPublicConfig, type TenantServerConfig, type TenantRole, } from "../tenant-types.js";
26
+ //# sourceMappingURL=tenant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/server/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AACrB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAoB5B,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,kBAAkB,CAwDtE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,kBAAkB,CAU3E;AAeD,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,kBAAkB,CAAA;CAAE,wEAM1E;AAED,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC"}
package/dist/server.cjs CHANGED
@@ -33,11 +33,15 @@ __export(server_exports, {
33
33
  AuthError: () => AuthError,
34
34
  IMPERSONATE_COOKIE_NAME: () => IMPERSONATE_COOKIE_NAME,
35
35
  IMPERSONATE_TTL_SECONDS: () => IMPERSONATE_TTL_SECONDS,
36
+ TENANT_GLOBAL_KEY: () => TENANT_GLOBAL_KEY,
37
+ TenantBootScript: () => TenantBootScript,
36
38
  createAuth: () => createAuth,
37
39
  createGetOrCreateAppUser: () => createGetOrCreateAppUser,
38
40
  getUserGroups: () => getUserGroups,
39
41
  hasGroup: () => hasGroup,
42
+ loadTenantConfig: () => loadTenantConfig,
40
43
  mintImpersonationToken: () => mintImpersonationToken,
44
+ publicSubset: () => publicSubset,
41
45
  requireGroup: () => requireGroup,
42
46
  verifyImpersonationToken: () => verifyImpersonationToken
43
47
  });
@@ -69,37 +73,11 @@ function requireGroup(session, ...names) {
69
73
  const ok = names.some((n) => hasGroup(session, n));
70
74
  if (!ok) throw new AuthError("forbidden");
71
75
  }
72
- function validateProdEnv(args) {
73
- if (!args.isProd) return;
74
- if (process.env.NEXT_PHASE === "phase-production-build") return;
75
- if (!process.env.AWS_LAMBDA_FUNCTION_NAME) return;
76
- const missing = [];
77
- if (!args.secret) missing.push("AUTH_SECRET");
78
- if (!args.cognitoClientId) missing.push("AUTH_COGNITO_ID");
79
- if (!args.cognitoClientSecret) missing.push("AUTH_COGNITO_SECRET");
80
- if (!args.cognitoIssuer) missing.push("AUTH_COGNITO_ISSUER");
81
- const hasAny = !!(args.cookieDomain || args.allowedParentDomain || args.appDomain);
82
- if (hasAny) {
83
- if (!args.cookieDomain) missing.push("AUTH_COOKIE_DOMAIN");
84
- if (!args.allowedParentDomain) missing.push("AUTH_ALLOWED_PARENT_DOMAIN");
85
- if (!args.appDomain) missing.push("APP_DOMAIN");
86
- }
87
- if (missing.length > 0) {
88
- throw new Error(
89
- `[@augmenting-integrations/auth] Missing required prod env vars: ${missing.join(
90
- ", "
91
- )}. Provide via createAuth() opts or process.env.`
92
- );
93
- }
94
- }
95
- function buildRedirectCallback(allowedParentDomain) {
76
+ function buildRedirectCallback(parentDomain) {
96
77
  return ({ url, baseUrl }) => {
97
78
  try {
98
79
  const target = new URL(url, baseUrl);
99
- if (!allowedParentDomain) {
100
- return target.origin === new URL(baseUrl).origin ? target.toString() : baseUrl;
101
- }
102
- const apex = allowedParentDomain.replace(/^\./, "").toLowerCase();
80
+ const apex = parentDomain.replace(/^\./, "").toLowerCase();
103
81
  const host = target.hostname.toLowerCase();
104
82
  const ok = host === apex || host.endsWith(`.${apex}`);
105
83
  return ok ? target.toString() : baseUrl;
@@ -110,44 +88,31 @@ function buildRedirectCallback(allowedParentDomain) {
110
88
  }
111
89
  function deriveSignInPage(args) {
112
90
  if (args.signInPage) return args.signInPage;
113
- if (args.appDomain && args.allowedParentDomain) {
114
- const apex = args.allowedParentDomain.replace(/^\./, "");
115
- return args.appDomain === apex ? "/login" : `https://${apex}/login`;
116
- }
117
- return "/login";
118
- }
119
- function roleFromGroups(groups) {
120
- if (Array.isArray(groups) && groups.length > 0) {
121
- return String(groups[0]).toLowerCase();
122
- }
123
- return "visitor";
91
+ return args.appDomain === args.apex ? "/login" : `https://${args.apex}/login`;
124
92
  }
125
93
  function createAuth(opts) {
94
+ const { tenant, authSecret, cognitoClientSecret } = opts;
126
95
  const isProd = opts.isProd ?? process.env.NODE_ENV === "production";
127
- const cookieDomain = isProd ? opts.cookieDomain ?? process.env.AUTH_COOKIE_DOMAIN : void 0;
128
- const allowedParentDomain = opts.allowedParentDomain ?? process.env.AUTH_ALLOWED_PARENT_DOMAIN;
129
- const appDomain = opts.appDomain ?? process.env.APP_DOMAIN;
130
- const SECRET = opts.secret ?? process.env.AUTH_SECRET ?? (isProd ? void 0 : "dev-only-fallback-not-for-prod");
131
- const cognitoClientId = opts.cognito?.clientId ?? process.env.AUTH_COGNITO_ID;
132
- const cognitoClientSecret = opts.cognito?.clientSecret ?? process.env.AUTH_COGNITO_SECRET;
133
- const cognitoIssuer = opts.cognito?.issuer ?? process.env.AUTH_COGNITO_ISSUER;
134
- validateProdEnv({
135
- isProd,
136
- cookieDomain,
137
- allowedParentDomain,
138
- appDomain,
139
- secret: SECRET,
140
- cognitoClientId,
141
- cognitoClientSecret,
142
- cognitoIssuer
143
- });
96
+ const cookieDomain = isProd ? tenant.cookieDomain : void 0;
97
+ if (tenant.role === "apex") {
98
+ if (!tenant.cognitoClientId || !tenant.cognitoIssuer) {
99
+ throw new Error(
100
+ "createAuth: tenant.role='apex' requires cognitoClientId + cognitoIssuer. Check loadTenantConfig() inputs."
101
+ );
102
+ }
103
+ if (isProd && !cognitoClientSecret) {
104
+ throw new Error(
105
+ "createAuth: tenant.role='apex' in production requires cognitoClientSecret. Fetch via getSecret(tenant.authCognitoSecretArn) and pass it in."
106
+ );
107
+ }
108
+ }
144
109
  const signInPage = deriveSignInPage({
145
110
  signInPage: opts.signInPage,
146
- appDomain,
147
- allowedParentDomain
111
+ appDomain: tenant.appDomain,
112
+ apex: tenant.apex
148
113
  });
149
114
  const config = {
150
- secret: SECRET,
115
+ secret: authSecret,
151
116
  cookies: cookieDomain ? {
152
117
  sessionToken: {
153
118
  name: "authjs.session-token",
@@ -162,9 +127,9 @@ function createAuth(opts) {
162
127
  } : void 0,
163
128
  providers: isProd ? [
164
129
  (0, import_cognito.default)({
165
- clientId: cognitoClientId,
130
+ clientId: tenant.cognitoClientId,
166
131
  clientSecret: cognitoClientSecret,
167
- issuer: cognitoIssuer
132
+ issuer: tenant.cognitoIssuer
168
133
  })
169
134
  ] : [
170
135
  (0, import_credentials.default)({
@@ -215,7 +180,6 @@ function createAuth(opts) {
215
180
  session: ({ session, token }) => {
216
181
  const groups = token["cognito:groups"] ?? [];
217
182
  session.user.groups = groups;
218
- session.user.role = roleFromGroups(groups);
219
183
  return session;
220
184
  },
221
185
  authorized: ({ auth: session, request: { nextUrl } }) => {
@@ -233,7 +197,7 @@ function createAuth(opts) {
233
197
  }
234
198
  return true;
235
199
  },
236
- redirect: buildRedirectCallback(allowedParentDomain)
200
+ redirect: buildRedirectCallback(tenant.parentDomain)
237
201
  },
238
202
  pages: { signIn: signInPage },
239
203
  trustHost: true
@@ -376,16 +340,99 @@ function createGetOrCreateAppUser(opts) {
376
340
  });
377
341
  };
378
342
  }
343
+
344
+ // src/server/tenant.ts
345
+ var import_server_only3 = require("server-only");
346
+ var React = __toESM(require("react"));
347
+
348
+ // src/tenant-types.ts
349
+ var TENANT_GLOBAL_KEY = "__TENANT__";
350
+
351
+ // src/server/tenant.ts
352
+ function loadTenantConfig(opts) {
353
+ const env = process.env;
354
+ const o = opts.overrides ?? {};
355
+ const draft = {
356
+ role: opts.role,
357
+ apex: o.apex ?? env.APEX_DOMAIN,
358
+ cookieDomain: o.cookieDomain ?? env.AUTH_COOKIE_DOMAIN,
359
+ parentDomain: o.parentDomain ?? env.AUTH_ALLOWED_PARENT_DOMAIN,
360
+ region: o.region ?? env.AWS_REGION ?? "us-east-1",
361
+ appSlug: o.appSlug ?? env.APP_SLUG,
362
+ appDomain: o.appDomain ?? env.APP_DOMAIN,
363
+ authSecretArn: o.authSecretArn ?? env.AUTH_SECRET_ARN,
364
+ registryTable: o.registryTable ?? env.REGISTRY_TABLE,
365
+ authCognitoSecretArn: o.authCognitoSecretArn ?? env.AUTH_COGNITO_SECRET_ARN,
366
+ cognitoIssuer: o.cognitoIssuer ?? env.AUTH_COGNITO_ISSUER,
367
+ cognitoClientId: o.cognitoClientId ?? env.AUTH_COGNITO_CLIENT_ID,
368
+ adminEmails: o.adminEmails ?? env.ADMIN_EMAILS,
369
+ dbSecretArn: o.dbSecretArn ?? env.DB_SECRET_ARN,
370
+ dbHost: o.dbHost ?? env.DB_HOST,
371
+ dbName: o.dbName ?? env.DB_NAME,
372
+ stripeSecretArn: o.stripeSecretArn ?? env.STRIPE_SECRET_ARN,
373
+ stripeWebhookSecretArn: o.stripeWebhookSecretArn ?? env.STRIPE_WEBHOOK_SECRET_ARN
374
+ };
375
+ if (opts.role === "apex" && !draft.appDomain) {
376
+ draft.appDomain = draft.apex;
377
+ }
378
+ const required = [
379
+ { key: "apex", env: "APEX_DOMAIN" },
380
+ { key: "cookieDomain", env: "AUTH_COOKIE_DOMAIN" },
381
+ { key: "parentDomain", env: "AUTH_ALLOWED_PARENT_DOMAIN" },
382
+ { key: "authSecretArn", env: "AUTH_SECRET_ARN" },
383
+ { key: "registryTable", env: "REGISTRY_TABLE" },
384
+ { key: "appDomain", env: "APP_DOMAIN" }
385
+ ];
386
+ if (opts.role === "apex") {
387
+ required.push(
388
+ { key: "authCognitoSecretArn", env: "AUTH_COGNITO_SECRET_ARN" },
389
+ { key: "cognitoIssuer", env: "AUTH_COGNITO_ISSUER" },
390
+ { key: "cognitoClientId", env: "AUTH_COGNITO_CLIENT_ID" }
391
+ );
392
+ } else {
393
+ required.push({ key: "appSlug", env: "APP_SLUG" });
394
+ }
395
+ const missing = required.filter((r) => !draft[r.key]).map((r) => r.env);
396
+ if (missing.length > 0) {
397
+ throw new Error(
398
+ `loadTenantConfig(${opts.role}): missing required env vars: ${missing.join(", ")}`
399
+ );
400
+ }
401
+ return draft;
402
+ }
403
+ function publicSubset(config) {
404
+ return {
405
+ apex: config.apex,
406
+ cookieDomain: config.cookieDomain,
407
+ parentDomain: config.parentDomain,
408
+ region: config.region,
409
+ appSlug: config.appSlug,
410
+ appDomain: config.appDomain,
411
+ role: config.role
412
+ };
413
+ }
414
+ var INNER_HTML_PROP = "dangerouslySetInnerHTML";
415
+ function TenantBootScript({ config }) {
416
+ const payload = JSON.stringify(config).replace(/</g, "\\u003c");
417
+ const body = `window.${TENANT_GLOBAL_KEY}=${payload};`;
418
+ const props = {};
419
+ props[INNER_HTML_PROP] = { __html: body };
420
+ return React.createElement("script", props);
421
+ }
379
422
  // Annotate the CommonJS export names for ESM import in node:
380
423
  0 && (module.exports = {
381
424
  AuthError,
382
425
  IMPERSONATE_COOKIE_NAME,
383
426
  IMPERSONATE_TTL_SECONDS,
427
+ TENANT_GLOBAL_KEY,
428
+ TenantBootScript,
384
429
  createAuth,
385
430
  createGetOrCreateAppUser,
386
431
  getUserGroups,
387
432
  hasGroup,
433
+ loadTenantConfig,
388
434
  mintImpersonationToken,
435
+ publicSubset,
389
436
  requireGroup,
390
437
  verifyImpersonationToken
391
438
  });