@every-app/sdk 0.1.1 → 0.1.3

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 (34) hide show
  1. package/README.md +0 -1
  2. package/dist/core/authenticatedFetch.d.ts.map +1 -1
  3. package/dist/core/authenticatedFetch.js +4 -0
  4. package/dist/core/localDemoSessionManager.d.ts +42 -0
  5. package/dist/core/localDemoSessionManager.d.ts.map +1 -0
  6. package/dist/core/localDemoSessionManager.js +52 -0
  7. package/dist/core/sessionManager.d.ts +1 -0
  8. package/dist/core/sessionManager.d.ts.map +1 -1
  9. package/dist/core/sessionManager.js +41 -9
  10. package/dist/shared/demoModeLocalOnly.d.ts +14 -0
  11. package/dist/shared/demoModeLocalOnly.d.ts.map +1 -0
  12. package/dist/shared/demoModeLocalOnly.js +30 -0
  13. package/dist/shared/localOnly.d.ts +14 -0
  14. package/dist/shared/localOnly.d.ts.map +1 -0
  15. package/dist/shared/localOnly.js +30 -0
  16. package/dist/tanstack/EmbeddedAppProvider.js +2 -2
  17. package/dist/tanstack/_internal/useEveryAppSession.d.ts +4 -1
  18. package/dist/tanstack/_internal/useEveryAppSession.d.ts.map +1 -1
  19. package/dist/tanstack/_internal/useEveryAppSession.js +9 -4
  20. package/dist/tanstack/server/authConfig.d.ts.map +1 -1
  21. package/dist/tanstack/server/authConfig.js +5 -1
  22. package/dist/tanstack/server/authenticateRequest.d.ts.map +1 -1
  23. package/dist/tanstack/server/authenticateRequest.js +9 -0
  24. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts.map +1 -1
  25. package/dist/tanstack/useSessionTokenClientMiddleware.js +8 -0
  26. package/package.json +1 -1
  27. package/src/core/authenticatedFetch.ts +9 -0
  28. package/src/core/sessionManager.ts +53 -8
  29. package/src/shared/demoModeLocalOnly.ts +36 -0
  30. package/src/tanstack/EmbeddedAppProvider.tsx +2 -2
  31. package/src/tanstack/_internal/useEveryAppSession.tsx +16 -9
  32. package/src/tanstack/server/authConfig.ts +7 -1
  33. package/src/tanstack/server/authenticateRequest.ts +17 -0
  34. package/src/tanstack/useSessionTokenClientMiddleware.ts +12 -0
package/README.md CHANGED
@@ -7,4 +7,3 @@ This SDK handles authentication and session management for apps running within t
7
7
  ## Documentation
8
8
 
9
9
  For full API reference and usage guides, see the [Embedded SDK documentation](https://everyapp.dev/docs/embedded-sdk/overview/).
10
-
@@ -1 +1 @@
1
- {"version":3,"file":"authenticatedFetch.d.ts","sourceRoot":"","sources":["../../src/core/authenticatedFetch.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAevD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,QAAQ,CAAC,CAUnB"}
1
+ {"version":3,"file":"authenticatedFetch.d.ts","sourceRoot":"","sources":["../../src/core/authenticatedFetch.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAmBvD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,QAAQ,CAAC,CAUnB"}
@@ -1,7 +1,11 @@
1
+ import { LOCAL_ONLY_TOKEN, isLocalOnlyClient, } from "../shared/demoModeLocalOnly";
1
2
  /**
2
3
  * Gets the current session token from the embedded session manager
3
4
  */
4
5
  export async function getSessionToken() {
6
+ if (isLocalOnlyClient()) {
7
+ return LOCAL_ONLY_TOKEN;
8
+ }
5
9
  const windowWithSession = window;
6
10
  const sessionManager = windowWithSession.__embeddedSessionManager;
7
11
  if (!sessionManager) {
@@ -0,0 +1,42 @@
1
+ export interface SessionManagerConfig {
2
+ appId: string;
3
+ }
4
+ /**
5
+ * A simplified session manager for local demo mode.
6
+ *
7
+ * This manager bypasses all real authentication and returns static demo credentials.
8
+ * It should only be used in development when LOCAL_DEMO_ONLY_MODE is enabled.
9
+ *
10
+ * SECURITY: This class is only instantiated when isLocalDemoModeClient() returns true,
11
+ * which includes a production safety check.
12
+ */
13
+ export declare class LocalDemoSessionManager {
14
+ readonly parentOrigin: string;
15
+ readonly appId: string;
16
+ readonly isInIframe: boolean;
17
+ constructor(config: SessionManagerConfig);
18
+ /**
19
+ * Returns the static demo token.
20
+ * No expiration logic needed since this is just for local development.
21
+ */
22
+ getToken(): Promise<string>;
23
+ /**
24
+ * Always returns VALID status with the demo token.
25
+ */
26
+ getTokenState(): {
27
+ status: "NO_TOKEN" | "VALID" | "EXPIRED" | "REFRESHING";
28
+ token: string | null;
29
+ };
30
+ /**
31
+ * Returns static demo user info.
32
+ */
33
+ getUser(): {
34
+ userId: string;
35
+ email: string;
36
+ };
37
+ /**
38
+ * No-op for demo mode - token never needs refreshing.
39
+ */
40
+ requestNewToken(): Promise<string>;
41
+ }
42
+ //# sourceMappingURL=localDemoSessionManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localDemoSessionManager.d.ts","sourceRoot":"","sources":["../../src/core/localDemoSessionManager.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,qBAAa,uBAAuB;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAQ;gBAExB,MAAM,EAAE,oBAAoB;IAcxC;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAIjC;;OAEG;IACH,aAAa,IAAI;QACf,MAAM,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;QACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB;IAID;;OAEG;IACH,OAAO,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAO5C;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;CAGzC"}
@@ -0,0 +1,52 @@
1
+ import { LOCAL_DEMO_TOKEN, LOCAL_DEMO_USER_ID, LOCAL_DEMO_EMAIL, } from "../shared/localOnly";
2
+ /**
3
+ * A simplified session manager for local demo mode.
4
+ *
5
+ * This manager bypasses all real authentication and returns static demo credentials.
6
+ * It should only be used in development when LOCAL_DEMO_ONLY_MODE is enabled.
7
+ *
8
+ * SECURITY: This class is only instantiated when isLocalDemoModeClient() returns true,
9
+ * which includes a production safety check.
10
+ */
11
+ export class LocalDemoSessionManager {
12
+ parentOrigin;
13
+ appId;
14
+ isInIframe = true;
15
+ constructor(config) {
16
+ if (!config.appId) {
17
+ throw new Error("[LocalDemoSessionManager] appId is required.");
18
+ }
19
+ this.appId = config.appId;
20
+ this.parentOrigin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
21
+ console.warn("[LocalDemoSessionManager] Running in LOCAL DEMO MODE. " +
22
+ "Authentication is bypassed. Do not use in production!");
23
+ }
24
+ /**
25
+ * Returns the static demo token.
26
+ * No expiration logic needed since this is just for local development.
27
+ */
28
+ async getToken() {
29
+ return LOCAL_DEMO_TOKEN;
30
+ }
31
+ /**
32
+ * Always returns VALID status with the demo token.
33
+ */
34
+ getTokenState() {
35
+ return { status: "VALID", token: LOCAL_DEMO_TOKEN };
36
+ }
37
+ /**
38
+ * Returns static demo user info.
39
+ */
40
+ getUser() {
41
+ return {
42
+ userId: LOCAL_DEMO_USER_ID,
43
+ email: LOCAL_DEMO_EMAIL,
44
+ };
45
+ }
46
+ /**
47
+ * No-op for demo mode - token never needs refreshing.
48
+ */
49
+ async requestNewToken() {
50
+ return LOCAL_DEMO_TOKEN;
51
+ }
52
+ }
@@ -10,6 +10,7 @@ export declare class SessionManager {
10
10
  readonly parentOrigin: string;
11
11
  readonly appId: string;
12
12
  readonly isInIframe: boolean;
13
+ readonly isDemoModeLocalOnly: boolean;
13
14
  private token;
14
15
  private refreshPromise;
15
16
  constructor(config: SessionManagerConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"sessionManager.d.ts","sourceRoot":"","sources":["../../src/core/sessionManager.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAQ3C;AAED,qBAAa,cAAc;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAE7B,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,cAAc,CAAgC;gBAE1C,MAAM,EAAE,oBAAoB;IAqBxC,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,uBAAuB;IAuCzB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IA8ClC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAOjC,aAAa,IAAI;QACf,MAAM,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;QACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB;IAgBD;;;OAGG;IACH,OAAO,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAwBpD"}
1
+ {"version":3,"file":"sessionManager.d.ts","sourceRoot":"","sources":["../../src/core/sessionManager.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAQ3C;AAED,qBAAa,cAAc;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAEtC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,cAAc,CAAgC;gBAE1C,MAAM,EAAE,oBAAoB;IAoCxC,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,uBAAuB;IAuCzB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAsDlC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAcjC,aAAa,IAAI;QACf,MAAM,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;QACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB;IAgBD;;;OAGG;IACH,OAAO,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CA+BpD"}
@@ -1,3 +1,4 @@
1
+ import { LOCAL_ONLY_EMAIL, LOCAL_ONLY_TOKEN, LOCAL_ONLY_USER_ID, isLocalOnlyClient, } from "../shared/demoModeLocalOnly";
1
2
  const MESSAGE_TIMEOUT_MS = 5000;
2
3
  const TOKEN_EXPIRY_BUFFER_MS = 10000;
3
4
  const DEFAULT_TOKEN_LIFETIME_MS = 60000;
@@ -19,25 +20,37 @@ export class SessionManager {
19
20
  parentOrigin;
20
21
  appId;
21
22
  isInIframe;
23
+ isDemoModeLocalOnly;
22
24
  token = null;
23
25
  refreshPromise = null;
24
26
  constructor(config) {
25
27
  if (!config.appId) {
26
28
  throw new Error("[SessionManager] appId is required.");
27
29
  }
30
+ this.isDemoModeLocalOnly = isLocalOnlyClient();
28
31
  const gatewayUrl = import.meta.env.VITE_GATEWAY_URL;
29
- if (!gatewayUrl) {
30
- throw new Error("[SessionManager] VITE_GATEWAY_URL env var is required.");
31
- }
32
- try {
33
- new URL(gatewayUrl);
34
- }
35
- catch {
36
- throw new Error(`[SessionManager] Invalid gateway URL: ${gatewayUrl}`);
32
+ if (!this.isDemoModeLocalOnly) {
33
+ if (!gatewayUrl) {
34
+ throw new Error("[SessionManager] VITE_GATEWAY_URL env var is required.");
35
+ }
36
+ try {
37
+ new URL(gatewayUrl);
38
+ }
39
+ catch {
40
+ throw new Error(`[SessionManager] Invalid gateway URL: ${gatewayUrl}`);
41
+ }
37
42
  }
38
43
  this.appId = config.appId;
39
- this.parentOrigin = gatewayUrl;
44
+ this.parentOrigin = this.isDemoModeLocalOnly
45
+ ? window.location.origin
46
+ : gatewayUrl;
40
47
  this.isInIframe = isRunningInIframe();
48
+ if (this.isDemoModeLocalOnly) {
49
+ this.token = {
50
+ token: LOCAL_ONLY_TOKEN,
51
+ expiresAt: Date.now() + DEFAULT_TOKEN_LIFETIME_MS,
52
+ };
53
+ }
41
54
  }
42
55
  isTokenExpiringSoon(bufferMs = TOKEN_EXPIRY_BUFFER_MS) {
43
56
  if (!this.token)
@@ -77,6 +90,13 @@ export class SessionManager {
77
90
  });
78
91
  }
79
92
  async requestNewToken() {
93
+ if (this.isDemoModeLocalOnly) {
94
+ this.token = {
95
+ token: LOCAL_ONLY_TOKEN,
96
+ expiresAt: Date.now() + DEFAULT_TOKEN_LIFETIME_MS,
97
+ };
98
+ return this.token.token;
99
+ }
80
100
  if (this.refreshPromise) {
81
101
  return this.refreshPromise;
82
102
  }
@@ -112,6 +132,12 @@ export class SessionManager {
112
132
  }
113
133
  }
114
134
  async getToken() {
135
+ if (this.isDemoModeLocalOnly) {
136
+ if (!this.token || this.isTokenExpiringSoon()) {
137
+ return this.requestNewToken();
138
+ }
139
+ return this.token.token;
140
+ }
115
141
  if (this.isTokenExpiringSoon()) {
116
142
  return this.requestNewToken();
117
143
  }
@@ -134,6 +160,12 @@ export class SessionManager {
134
160
  * Returns null if no valid token is available.
135
161
  */
136
162
  getUser() {
163
+ if (this.isDemoModeLocalOnly) {
164
+ return {
165
+ userId: LOCAL_ONLY_USER_ID,
166
+ email: LOCAL_ONLY_EMAIL,
167
+ };
168
+ }
137
169
  if (!this.token) {
138
170
  return null;
139
171
  }
@@ -0,0 +1,14 @@
1
+ export declare const LOCAL_ONLY_TOKEN = "DEMO_MODE_LOCAL_ONLY";
2
+ export declare const LOCAL_ONLY_USER_ID = "demo-local-user";
3
+ export declare const LOCAL_ONLY_EMAIL = "demo-local-user@local";
4
+ export declare function isLocalOnlyClient(): boolean;
5
+ export declare function isLocalOnlyServer(): boolean;
6
+ export declare function createLocalOnlySessionPayload(audience: string): {
7
+ sub: string;
8
+ email: string;
9
+ iss: string;
10
+ aud: string;
11
+ iat: number;
12
+ exp: number;
13
+ };
14
+ //# sourceMappingURL=demoModeLocalOnly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demoModeLocalOnly.d.ts","sourceRoot":"","sources":["../../src/shared/demoModeLocalOnly.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AACvD,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AACpD,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAExD,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAa3C;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM;;;;;;;EAY7D"}
@@ -0,0 +1,30 @@
1
+ export const LOCAL_ONLY_TOKEN = "DEMO_MODE_LOCAL_ONLY";
2
+ export const LOCAL_ONLY_USER_ID = "demo-local-user";
3
+ export const LOCAL_ONLY_EMAIL = "demo-local-user@local";
4
+ export function isLocalOnlyClient() {
5
+ return import.meta.env.VITE_LOCAL_ONLY === "true";
6
+ }
7
+ export function isLocalOnlyServer() {
8
+ const metaEnv = import.meta
9
+ .env;
10
+ const metaValue = metaEnv?.LOCAL_ONLY ?? metaEnv?.VITE_LOCAL_ONLY;
11
+ if (metaValue === "true") {
12
+ return true;
13
+ }
14
+ if (typeof process !== "undefined" && process.env?.LOCAL_ONLY === "true") {
15
+ return true;
16
+ }
17
+ return false;
18
+ }
19
+ export function createLocalOnlySessionPayload(audience) {
20
+ const issuedAt = Math.floor(Date.now() / 1000);
21
+ const expiresAt = issuedAt + 60 * 60;
22
+ return {
23
+ sub: LOCAL_ONLY_USER_ID,
24
+ email: LOCAL_ONLY_EMAIL,
25
+ iss: "local",
26
+ aud: audience,
27
+ iat: issuedAt,
28
+ exp: expiresAt,
29
+ };
30
+ }
@@ -0,0 +1,14 @@
1
+ export declare const LOCAL_ONLY_TOKEN = "DEMO_MODE_LOCAL_ONLY";
2
+ export declare const LOCAL_ONLY_USER_ID = "demo-local-user";
3
+ export declare const LOCAL_ONLY_EMAIL = "demo-local-user@local";
4
+ export declare function isLocalOnlyClient(): boolean;
5
+ export declare function isLocalOnlyServer(): boolean;
6
+ export declare function createLocalOnlySessionPayload(audience: string): {
7
+ sub: string;
8
+ email: string;
9
+ iss: string;
10
+ aud: string;
11
+ iat: number;
12
+ exp: number;
13
+ };
14
+ //# sourceMappingURL=localOnly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localOnly.d.ts","sourceRoot":"","sources":["../../src/shared/localOnly.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AACvD,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AACpD,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAExD,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAa3C;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM;;;;;;;EAY7D"}
@@ -0,0 +1,30 @@
1
+ export const LOCAL_ONLY_TOKEN = "DEMO_MODE_LOCAL_ONLY";
2
+ export const LOCAL_ONLY_USER_ID = "demo-local-user";
3
+ export const LOCAL_ONLY_EMAIL = "demo-local-user@local";
4
+ export function isLocalOnlyClient() {
5
+ return import.meta.env.VITE_LOCAL_ONLY === "true";
6
+ }
7
+ export function isLocalOnlyServer() {
8
+ const metaEnv = import.meta
9
+ .env;
10
+ const metaValue = metaEnv?.LOCAL_ONLY ?? metaEnv?.VITE_LOCAL_ONLY;
11
+ if (metaValue === "true") {
12
+ return true;
13
+ }
14
+ if (typeof process !== "undefined" && process.env?.LOCAL_ONLY === "true") {
15
+ return true;
16
+ }
17
+ return false;
18
+ }
19
+ export function createLocalOnlySessionPayload(audience) {
20
+ const issuedAt = Math.floor(Date.now() / 1000);
21
+ const expiresAt = issuedAt + 60 * 60;
22
+ return {
23
+ sub: LOCAL_ONLY_USER_ID,
24
+ email: LOCAL_ONLY_EMAIL,
25
+ iss: "local",
26
+ aud: audience,
27
+ iat: issuedAt,
28
+ exp: expiresAt,
29
+ };
30
+ }
@@ -11,8 +11,8 @@ export function EmbeddedAppProvider({ children, ...config }) {
11
11
  useEveryAppRouter({ sessionManager });
12
12
  if (!sessionManager)
13
13
  return null;
14
- // Check if the app is running outside of the Gateway iframe
15
- if (!sessionManager.isInIframe) {
14
+ // Check if the app is running outside of the Gateway iframe (skip in demo mode)
15
+ if (!sessionManager.isInIframe && !sessionManager.isDemoModeLocalOnly) {
16
16
  return (_jsx(GatewayRequiredError, { gatewayOrigin: sessionManager.parentOrigin, appId: config.appId }));
17
17
  }
18
18
  const value = {
@@ -1,4 +1,7 @@
1
- import { SessionManager, SessionManagerConfig } from "../../core/sessionManager";
1
+ import { SessionManager } from "../../core/sessionManager";
2
+ interface SessionManagerConfig {
3
+ appId: string;
4
+ }
2
5
  interface UseEveryAppSessionParams {
3
6
  sessionManagerConfig: SessionManagerConfig;
4
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useEveryAppSession.d.ts","sourceRoot":"","sources":["../../../src/tanstack/_internal/useEveryAppSession.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EACd,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AAEnC,UAAU,wBAAwB;IAChC,oBAAoB,EAAE,oBAAoB,CAAC;CAC5C;AAED,wBAAgB,kBAAkB,CAAC,EACjC,oBAAoB,GACrB,EAAE,wBAAwB;;;;;;EAyC1B"}
1
+ {"version":3,"file":"useEveryAppSession.d.ts","sourceRoot":"","sources":["../../../src/tanstack/_internal/useEveryAppSession.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,wBAAwB;IAChC,oBAAoB,EAAE,oBAAoB,CAAC;CAC5C;AAED,wBAAgB,kBAAkB,CAAC,EACjC,oBAAoB,GACrB,EAAE,wBAAwB;;;;;;EA+C1B"}
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useRef, useState } from "react";
2
- import { SessionManager, } from "../../core/sessionManager";
2
+ import { SessionManager } from "../../core/sessionManager";
3
3
  export function useEveryAppSession({ sessionManagerConfig, }) {
4
4
  const sessionManagerRef = useRef(null);
5
5
  const [sessionTokenState, setSessionTokenState] = useState({
@@ -13,13 +13,18 @@ export function useEveryAppSession({ sessionManagerConfig, }) {
13
13
  useEffect(() => {
14
14
  if (!sessionManager)
15
15
  return;
16
- // Skip token requests when not in iframe - the app will show GatewayRequiredError instead
17
- if (!sessionManager.isInIframe)
16
+ // Skip token requests when not in iframe (unless in demo mode) - the app will show GatewayRequiredError instead
17
+ if (!sessionManager.isInIframe && !sessionManager.isDemoModeLocalOnly)
18
18
  return;
19
19
  const interval = setInterval(() => {
20
20
  setSessionTokenState(sessionManager.getTokenState());
21
21
  }, 5000);
22
- sessionManager.getToken().catch((err) => {
22
+ sessionManager
23
+ .getToken()
24
+ .then(() => {
25
+ setSessionTokenState(sessionManager.getTokenState());
26
+ })
27
+ .catch((err) => {
23
28
  console.error("[EmbeddedProvider] Initial token request failed:", err);
24
29
  });
25
30
  return () => {
@@ -1 +1 @@
1
- {"version":3,"file":"authConfig.d.ts","sourceRoot":"","sources":["../../../src/tanstack/server/authConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C,wBAAgB,aAAa,IAAI,UAAU,CAK1C"}
1
+ {"version":3,"file":"authConfig.d.ts","sourceRoot":"","sources":["../../../src/tanstack/server/authConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,wBAAgB,aAAa,IAAI,UAAU,CAU1C"}
@@ -1,7 +1,11 @@
1
1
  import { env } from "cloudflare:workers";
2
+ import { isLocalOnlyServer } from "../../shared/demoModeLocalOnly";
2
3
  export function getAuthConfig() {
4
+ const demoModeLocalOnlyEnv = env.LOCAL_ONLY;
5
+ const isDemoModeLocalOnly = demoModeLocalOnlyEnv === "true" || isLocalOnlyServer() === true;
6
+ const issuer = env.GATEWAY_URL || (isDemoModeLocalOnly ? "local" : "");
3
7
  return {
4
- issuer: env.GATEWAY_URL,
8
+ issuer,
5
9
  audience: import.meta.env.VITE_APP_ID,
6
10
  };
7
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authenticateRequest.d.ts","sourceRoot":"","sources":["../../../src/tanstack/server/authenticateRequest.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C;;;GAGG;AACH,UAAU,mBAAmB;IAC3B,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,UAAU,EACtB,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA+BrC;AAyCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK3E"}
1
+ {"version":3,"file":"authenticateRequest.d.ts","sourceRoot":"","sources":["../../../src/tanstack/server/authenticateRequest.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAQ1C;;;GAGG;AACH,UAAU,mBAAmB;IAC3B,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,UAAU,EACtB,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA2CrC;AAyCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK3E"}
@@ -1,9 +1,12 @@
1
1
  import { getRequest } from "@tanstack/react-start/server";
2
2
  import { createLocalJWKSet, jwtVerify, } from "jose";
3
3
  import { env } from "cloudflare:workers";
4
+ import { LOCAL_ONLY_TOKEN, createLocalOnlySessionPayload, isLocalOnlyServer, } from "../../shared/demoModeLocalOnly";
4
5
  export async function authenticateRequest(authConfig, providedRequest) {
5
6
  const request = providedRequest || getRequest();
6
7
  const authHeader = request.headers.get("authorization");
8
+ const demoModeLocalOnlyEnv = env.LOCAL_ONLY;
9
+ const isDemoModeLocalOnly = demoModeLocalOnlyEnv === "true" || isLocalOnlyServer() === true;
7
10
  if (!authHeader) {
8
11
  console.log("No auth header found");
9
12
  return null;
@@ -12,6 +15,12 @@ export async function authenticateRequest(authConfig, providedRequest) {
12
15
  if (!token) {
13
16
  return null;
14
17
  }
18
+ if (isDemoModeLocalOnly) {
19
+ if (token !== LOCAL_ONLY_TOKEN) {
20
+ return null;
21
+ }
22
+ return createLocalOnlySessionPayload(authConfig.audience);
23
+ }
15
24
  try {
16
25
  const session = await verifySessionToken(token, authConfig);
17
26
  return session;
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionTokenClientMiddleware.d.ts","sourceRoot":"","sources":["../../src/tanstack/useSessionTokenClientMiddleware.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,+BAA+B,6GA2B1C,CAAC"}
1
+ {"version":3,"file":"useSessionTokenClientMiddleware.d.ts","sourceRoot":"","sources":["../../src/tanstack/useSessionTokenClientMiddleware.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,+BAA+B,6GAmC1C,CAAC"}
@@ -1,7 +1,15 @@
1
1
  import { createMiddleware } from "@tanstack/react-start";
2
+ import { LOCAL_ONLY_TOKEN, isLocalOnlyClient, } from "../shared/demoModeLocalOnly";
2
3
  export const useSessionTokenClientMiddleware = createMiddleware({
3
4
  type: "function",
4
5
  }).client(async ({ next }) => {
6
+ if (isLocalOnlyClient()) {
7
+ return next({
8
+ headers: {
9
+ Authorization: `Bearer ${LOCAL_ONLY_TOKEN}`,
10
+ },
11
+ });
12
+ }
5
13
  // Get the global sessionManager - this MUST be available for embedded apps
6
14
  const sessionManager = window
7
15
  .__embeddedSessionManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@every-app/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,3 +1,8 @@
1
+ import {
2
+ DEMO_MODE_LOCAL_ONLY_TOKEN,
3
+ isDemoModeLocalOnlyClient,
4
+ } from "../shared/demoModeLocalOnly";
5
+
1
6
  interface SessionManager {
2
7
  getToken(): Promise<string>;
3
8
  }
@@ -10,6 +15,10 @@ interface WindowWithSessionManager extends Window {
10
15
  * Gets the current session token from the embedded session manager
11
16
  */
12
17
  export async function getSessionToken(): Promise<string> {
18
+ if (isDemoModeLocalOnlyClient()) {
19
+ return DEMO_MODE_LOCAL_ONLY_TOKEN;
20
+ }
21
+
13
22
  const windowWithSession = window as WindowWithSessionManager;
14
23
  const sessionManager = windowWithSession.__embeddedSessionManager;
15
24
 
@@ -1,3 +1,10 @@
1
+ import {
2
+ DEMO_MODE_LOCAL_ONLY_EMAIL,
3
+ DEMO_MODE_LOCAL_ONLY_TOKEN,
4
+ DEMO_MODE_LOCAL_ONLY_USER_ID,
5
+ isDemoModeLocalOnlyClient,
6
+ } from "../shared/demoModeLocalOnly";
7
+
1
8
  interface SessionToken {
2
9
  token: string;
3
10
  expiresAt: number;
@@ -35,6 +42,7 @@ export class SessionManager {
35
42
  readonly parentOrigin: string;
36
43
  readonly appId: string;
37
44
  readonly isInIframe: boolean;
45
+ readonly isDemoModeLocalOnly: boolean;
38
46
 
39
47
  private token: SessionToken | null = null;
40
48
  private refreshPromise: Promise<string> | null = null;
@@ -44,20 +52,35 @@ export class SessionManager {
44
52
  throw new Error("[SessionManager] appId is required.");
45
53
  }
46
54
 
55
+ this.isDemoModeLocalOnly = isDemoModeLocalOnlyClient();
56
+
47
57
  const gatewayUrl = import.meta.env.VITE_GATEWAY_URL;
48
- if (!gatewayUrl) {
49
- throw new Error("[SessionManager] VITE_GATEWAY_URL env var is required.");
50
- }
58
+ if (!this.isDemoModeLocalOnly) {
59
+ if (!gatewayUrl) {
60
+ throw new Error(
61
+ "[SessionManager] VITE_GATEWAY_URL env var is required.",
62
+ );
63
+ }
51
64
 
52
- try {
53
- new URL(gatewayUrl);
54
- } catch {
55
- throw new Error(`[SessionManager] Invalid gateway URL: ${gatewayUrl}`);
65
+ try {
66
+ new URL(gatewayUrl);
67
+ } catch {
68
+ throw new Error(`[SessionManager] Invalid gateway URL: ${gatewayUrl}`);
69
+ }
56
70
  }
57
71
 
58
72
  this.appId = config.appId;
59
- this.parentOrigin = gatewayUrl;
73
+ this.parentOrigin = this.isDemoModeLocalOnly
74
+ ? window.location.origin
75
+ : gatewayUrl;
60
76
  this.isInIframe = isRunningInIframe();
77
+
78
+ if (this.isDemoModeLocalOnly) {
79
+ this.token = {
80
+ token: DEMO_MODE_LOCAL_ONLY_TOKEN,
81
+ expiresAt: Date.now() + DEFAULT_TOKEN_LIFETIME_MS,
82
+ };
83
+ }
61
84
  }
62
85
 
63
86
  private isTokenExpiringSoon(
@@ -107,6 +130,14 @@ export class SessionManager {
107
130
  }
108
131
 
109
132
  async requestNewToken(): Promise<string> {
133
+ if (this.isDemoModeLocalOnly) {
134
+ this.token = {
135
+ token: DEMO_MODE_LOCAL_ONLY_TOKEN,
136
+ expiresAt: Date.now() + DEFAULT_TOKEN_LIFETIME_MS,
137
+ };
138
+ return this.token.token;
139
+ }
140
+
110
141
  if (this.refreshPromise) {
111
142
  return this.refreshPromise;
112
143
  }
@@ -153,6 +184,13 @@ export class SessionManager {
153
184
  }
154
185
 
155
186
  async getToken(): Promise<string> {
187
+ if (this.isDemoModeLocalOnly) {
188
+ if (!this.token || this.isTokenExpiringSoon()) {
189
+ return this.requestNewToken();
190
+ }
191
+ return this.token.token;
192
+ }
193
+
156
194
  if (this.isTokenExpiringSoon()) {
157
195
  return this.requestNewToken();
158
196
  }
@@ -183,6 +221,13 @@ export class SessionManager {
183
221
  * Returns null if no valid token is available.
184
222
  */
185
223
  getUser(): { userId: string; email: string } | null {
224
+ if (this.isDemoModeLocalOnly) {
225
+ return {
226
+ userId: DEMO_MODE_LOCAL_ONLY_USER_ID,
227
+ email: DEMO_MODE_LOCAL_ONLY_EMAIL,
228
+ };
229
+ }
230
+
186
231
  if (!this.token) {
187
232
  return null;
188
233
  }
@@ -0,0 +1,36 @@
1
+ export const DEMO_MODE_LOCAL_ONLY_TOKEN = "DEMO_MODE_LOCAL_ONLY";
2
+ export const DEMO_MODE_LOCAL_ONLY_USER_ID = "demo-local-user";
3
+ export const DEMO_MODE_LOCAL_ONLY_EMAIL = "demo-local-user@local";
4
+
5
+ export function isDemoModeLocalOnlyClient(): boolean {
6
+ return import.meta.env.VITE_LOCAL_ONLY === "true";
7
+ }
8
+
9
+ export function isDemoModeLocalOnlyServer(): boolean {
10
+ const metaEnv = (import.meta as { env?: Record<string, string | undefined> })
11
+ .env;
12
+ const metaValue = metaEnv?.LOCAL_ONLY ?? metaEnv?.VITE_LOCAL_ONLY;
13
+ if (metaValue === "true") {
14
+ return true;
15
+ }
16
+
17
+ if (typeof process !== "undefined" && process.env?.LOCAL_ONLY === "true") {
18
+ return true;
19
+ }
20
+
21
+ return false;
22
+ }
23
+
24
+ export function createDemoModeLocalOnlySessionPayload(audience: string) {
25
+ const issuedAt = Math.floor(Date.now() / 1000);
26
+ const expiresAt = issuedAt + 60 * 60;
27
+
28
+ return {
29
+ sub: DEMO_MODE_LOCAL_ONLY_USER_ID,
30
+ email: DEMO_MODE_LOCAL_ONLY_EMAIL,
31
+ iss: "local",
32
+ aud: audience,
33
+ iat: issuedAt,
34
+ exp: expiresAt,
35
+ };
36
+ }
@@ -27,8 +27,8 @@ export function EmbeddedAppProvider({
27
27
 
28
28
  if (!sessionManager) return null;
29
29
 
30
- // Check if the app is running outside of the Gateway iframe
31
- if (!sessionManager.isInIframe) {
30
+ // Check if the app is running outside of the Gateway iframe (skip in demo mode)
31
+ if (!sessionManager.isInIframe && !sessionManager.isDemoModeLocalOnly) {
32
32
  return (
33
33
  <GatewayRequiredError
34
34
  gatewayOrigin={sessionManager.parentOrigin}
@@ -1,8 +1,9 @@
1
1
  import { useEffect, useRef, useState } from "react";
2
- import {
3
- SessionManager,
4
- SessionManagerConfig,
5
- } from "../../core/sessionManager";
2
+ import { SessionManager } from "../../core/sessionManager";
3
+
4
+ interface SessionManagerConfig {
5
+ appId: string;
6
+ }
6
7
 
7
8
  interface UseEveryAppSessionParams {
8
9
  sessionManagerConfig: SessionManagerConfig;
@@ -27,16 +28,22 @@ export function useEveryAppSession({
27
28
 
28
29
  useEffect(() => {
29
30
  if (!sessionManager) return;
30
- // Skip token requests when not in iframe - the app will show GatewayRequiredError instead
31
- if (!sessionManager.isInIframe) return;
31
+ // Skip token requests when not in iframe (unless in demo mode) - the app will show GatewayRequiredError instead
32
+ if (!sessionManager.isInIframe && !sessionManager.isDemoModeLocalOnly)
33
+ return;
32
34
 
33
35
  const interval = setInterval(() => {
34
36
  setSessionTokenState(sessionManager.getTokenState());
35
37
  }, 5000);
36
38
 
37
- sessionManager.getToken().catch((err) => {
38
- console.error("[EmbeddedProvider] Initial token request failed:", err);
39
- });
39
+ sessionManager
40
+ .getToken()
41
+ .then(() => {
42
+ setSessionTokenState(sessionManager.getTokenState());
43
+ })
44
+ .catch((err) => {
45
+ console.error("[EmbeddedProvider] Initial token request failed:", err);
46
+ });
40
47
 
41
48
  return () => {
42
49
  clearInterval(interval);
@@ -1,9 +1,15 @@
1
1
  import type { AuthConfig } from "./types";
2
2
  import { env } from "cloudflare:workers";
3
+ import { isDemoModeLocalOnlyServer } from "../../shared/demoModeLocalOnly";
3
4
 
4
5
  export function getAuthConfig(): AuthConfig {
6
+ const demoModeLocalOnlyEnv = (env as { LOCAL_ONLY?: string }).LOCAL_ONLY;
7
+ const isDemoModeLocalOnly =
8
+ demoModeLocalOnlyEnv === "true" || isDemoModeLocalOnlyServer() === true;
9
+ const issuer = env.GATEWAY_URL || (isDemoModeLocalOnly ? "local" : "");
10
+
5
11
  return {
6
- issuer: env.GATEWAY_URL,
12
+ issuer,
7
13
  audience: import.meta.env.VITE_APP_ID,
8
14
  };
9
15
  }
@@ -8,6 +8,11 @@ import {
8
8
 
9
9
  import type { AuthConfig } from "./types";
10
10
  import { env } from "cloudflare:workers";
11
+ import {
12
+ DEMO_MODE_LOCAL_ONLY_TOKEN,
13
+ createDemoModeLocalOnlySessionPayload,
14
+ isDemoModeLocalOnlyServer,
15
+ } from "../../shared/demoModeLocalOnly";
11
16
 
12
17
  /**
13
18
  * JWT payload structure for embedded app session tokens.
@@ -35,6 +40,10 @@ export async function authenticateRequest(
35
40
  const request = providedRequest || getRequest();
36
41
  const authHeader = request.headers.get("authorization");
37
42
 
43
+ const demoModeLocalOnlyEnv = (env as { LOCAL_ONLY?: string }).LOCAL_ONLY;
44
+ const isDemoModeLocalOnly =
45
+ demoModeLocalOnlyEnv === "true" || isDemoModeLocalOnlyServer() === true;
46
+
38
47
  if (!authHeader) {
39
48
  console.log("No auth header found");
40
49
  return null;
@@ -46,6 +55,14 @@ export async function authenticateRequest(
46
55
  return null;
47
56
  }
48
57
 
58
+ if (isDemoModeLocalOnly) {
59
+ if (token !== DEMO_MODE_LOCAL_ONLY_TOKEN) {
60
+ return null;
61
+ }
62
+
63
+ return createDemoModeLocalOnlySessionPayload(authConfig.audience);
64
+ }
65
+
49
66
  try {
50
67
  const session = await verifySessionToken(token, authConfig);
51
68
  return session;
@@ -1,9 +1,21 @@
1
1
  import { createMiddleware } from "@tanstack/react-start";
2
2
  import type { SessionManager } from "../core/sessionManager";
3
+ import {
4
+ DEMO_MODE_LOCAL_ONLY_TOKEN,
5
+ isDemoModeLocalOnlyClient,
6
+ } from "../shared/demoModeLocalOnly";
3
7
 
4
8
  export const useSessionTokenClientMiddleware = createMiddleware({
5
9
  type: "function",
6
10
  }).client(async ({ next }) => {
11
+ if (isDemoModeLocalOnlyClient()) {
12
+ return next({
13
+ headers: {
14
+ Authorization: `Bearer ${DEMO_MODE_LOCAL_ONLY_TOKEN}`,
15
+ },
16
+ });
17
+ }
18
+
7
19
  // Get the global sessionManager - this MUST be available for embedded apps
8
20
  const sessionManager = (window as any)
9
21
  .__embeddedSessionManager as SessionManager;