@every-app/sdk 0.1.2 → 0.1.4

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 (33) hide show
  1. package/dist/core/authenticatedFetch.d.ts.map +1 -1
  2. package/dist/core/authenticatedFetch.js +4 -0
  3. package/dist/core/localDemoSessionManager.d.ts +42 -0
  4. package/dist/core/localDemoSessionManager.d.ts.map +1 -0
  5. package/dist/core/localDemoSessionManager.js +52 -0
  6. package/dist/core/sessionManager.d.ts +1 -0
  7. package/dist/core/sessionManager.d.ts.map +1 -1
  8. package/dist/core/sessionManager.js +41 -40
  9. package/dist/shared/demoModeLocalOnly.d.ts +14 -0
  10. package/dist/shared/demoModeLocalOnly.d.ts.map +1 -0
  11. package/dist/shared/demoModeLocalOnly.js +30 -0
  12. package/dist/shared/localOnly.d.ts +14 -0
  13. package/dist/shared/localOnly.d.ts.map +1 -0
  14. package/dist/shared/localOnly.js +30 -0
  15. package/dist/tanstack/EmbeddedAppProvider.js +2 -2
  16. package/dist/tanstack/_internal/useEveryAppSession.d.ts +4 -1
  17. package/dist/tanstack/_internal/useEveryAppSession.d.ts.map +1 -1
  18. package/dist/tanstack/_internal/useEveryAppSession.js +10 -12
  19. package/dist/tanstack/server/authConfig.d.ts.map +1 -1
  20. package/dist/tanstack/server/authConfig.js +5 -1
  21. package/dist/tanstack/server/authenticateRequest.d.ts.map +1 -1
  22. package/dist/tanstack/server/authenticateRequest.js +9 -0
  23. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts.map +1 -1
  24. package/dist/tanstack/useSessionTokenClientMiddleware.js +8 -0
  25. package/package.json +1 -1
  26. package/src/core/authenticatedFetch.ts +9 -0
  27. package/src/core/sessionManager.ts +53 -8
  28. package/src/shared/demoModeLocalOnly.ts +40 -0
  29. package/src/tanstack/EmbeddedAppProvider.tsx +2 -2
  30. package/src/tanstack/_internal/useEveryAppSession.tsx +3 -2
  31. package/src/tanstack/server/authConfig.ts +8 -1
  32. package/src/tanstack/server/authenticateRequest.ts +18 -0
  33. package/src/tanstack/useSessionTokenClientMiddleware.ts +12 -0
@@ -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;IAuDzB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IA+DlC,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)
@@ -46,7 +59,6 @@ export class SessionManager {
46
59
  }
47
60
  postMessageWithResponse(request, responseType, requestId) {
48
61
  return new Promise((resolve, reject) => {
49
- const startTime = Date.now();
50
62
  const cleanup = () => {
51
63
  clearTimeout(timeout);
52
64
  window.removeEventListener("message", handler);
@@ -61,11 +73,6 @@ export class SessionManager {
61
73
  if (event.data.type === responseType &&
62
74
  event.data.requestId === requestId) {
63
75
  cleanup();
64
- console.log("[SessionManager] postMessage response received", {
65
- requestId,
66
- responseType,
67
- elapsedMs: Date.now() - startTime,
68
- });
69
76
  if (event.data.error) {
70
77
  reject(new Error(event.data.error));
71
78
  }
@@ -76,38 +83,25 @@ export class SessionManager {
76
83
  };
77
84
  const timeout = setTimeout(() => {
78
85
  cleanup();
79
- console.log("[SessionManager] postMessage response timeout", {
80
- requestId,
81
- responseType,
82
- timeoutMs: MESSAGE_TIMEOUT_MS,
83
- });
84
86
  reject(new Error("Token request timeout - parent did not respond"));
85
87
  }, MESSAGE_TIMEOUT_MS);
86
88
  window.addEventListener("message", handler);
87
- console.log("[SessionManager] postMessage request sent", {
88
- requestId,
89
- requestType: request.type,
90
- parentOrigin: this.parentOrigin,
91
- });
92
89
  window.parent.postMessage(request, this.parentOrigin);
93
90
  });
94
91
  }
95
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
+ }
96
100
  if (this.refreshPromise) {
97
- console.log("[SessionManager] Reusing in-flight token request", {
98
- appId: this.appId,
99
- });
100
101
  return this.refreshPromise;
101
102
  }
102
103
  this.refreshPromise = (async () => {
103
104
  const requestId = crypto.randomUUID();
104
- const startTime = Date.now();
105
- console.log("[SessionManager] Requesting new session token", {
106
- requestId,
107
- appId: this.appId,
108
- parentOrigin: this.parentOrigin,
109
- isInIframe: this.isInIframe,
110
- });
111
105
  const response = await this.postMessageWithResponse({
112
106
  type: "SESSION_TOKEN_REQUEST",
113
107
  requestId,
@@ -128,11 +122,6 @@ export class SessionManager {
128
122
  token: response.token,
129
123
  expiresAt,
130
124
  };
131
- console.log("[SessionManager] Session token stored", {
132
- requestId,
133
- elapsedMs: Date.now() - startTime,
134
- expiresAt,
135
- });
136
125
  return this.token.token;
137
126
  })();
138
127
  try {
@@ -143,6 +132,12 @@ export class SessionManager {
143
132
  }
144
133
  }
145
134
  async getToken() {
135
+ if (this.isDemoModeLocalOnly) {
136
+ if (!this.token || this.isTokenExpiringSoon()) {
137
+ return this.requestNewToken();
138
+ }
139
+ return this.token.token;
140
+ }
146
141
  if (this.isTokenExpiringSoon()) {
147
142
  return this.requestNewToken();
148
143
  }
@@ -165,6 +160,12 @@ export class SessionManager {
165
160
  * Returns null if no valid token is available.
166
161
  */
167
162
  getUser() {
163
+ if (this.isDemoModeLocalOnly) {
164
+ return {
165
+ userId: LOCAL_ONLY_USER_ID,
166
+ email: LOCAL_ONLY_EMAIL,
167
+ };
168
+ }
168
169
  if (!this.token) {
169
170
  return null;
170
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;;;;;;EAiD1B"}
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,20 +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
- console.log("[EmbeddedProvider] Initializing session token flow", {
20
- appId: sessionManager.appId,
21
- parentOrigin: sessionManager.parentOrigin,
22
- });
23
19
  const interval = setInterval(() => {
24
- const tokenState = sessionManager.getTokenState();
25
- console.log("[EmbeddedProvider] Session token state", tokenState);
26
- setSessionTokenState(tokenState);
20
+ setSessionTokenState(sessionManager.getTokenState());
27
21
  }, 5000);
28
- console.log("[EmbeddedProvider] Requesting initial session token");
29
- sessionManager.getToken().catch((err) => {
22
+ sessionManager
23
+ .getToken()
24
+ .then(() => {
25
+ setSessionTokenState(sessionManager.getTokenState());
26
+ })
27
+ .catch((err) => {
30
28
  console.error("[EmbeddedProvider] Initial token request failed:", err);
31
29
  });
32
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.2",
3
+ "version": "0.1.4",
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,40 @@
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_DEMO_MODE_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 =
13
+ metaEnv?.DEMO_MODE_LOCAL_ONLY ?? metaEnv?.VITE_DEMO_MODE_LOCAL_ONLY;
14
+ if (metaValue === "true") {
15
+ return true;
16
+ }
17
+
18
+ if (
19
+ typeof process !== "undefined" &&
20
+ process.env?.DEMO_MODE_LOCAL_ONLY === "true"
21
+ ) {
22
+ return true;
23
+ }
24
+
25
+ return false;
26
+ }
27
+
28
+ export function createDemoModeLocalOnlySessionPayload(audience: string) {
29
+ const issuedAt = Math.floor(Date.now() / 1000);
30
+ const expiresAt = issuedAt + 60 * 60;
31
+
32
+ return {
33
+ sub: DEMO_MODE_LOCAL_ONLY_USER_ID,
34
+ email: DEMO_MODE_LOCAL_ONLY_EMAIL,
35
+ iss: "local",
36
+ aud: audience,
37
+ iat: issuedAt,
38
+ exp: expiresAt,
39
+ };
40
+ }
@@ -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}
@@ -28,8 +28,9 @@ export function useEveryAppSession({
28
28
 
29
29
  useEffect(() => {
30
30
  if (!sessionManager) return;
31
- // Skip token requests when not in iframe - the app will show GatewayRequiredError instead
32
- 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;
33
34
 
34
35
  const interval = setInterval(() => {
35
36
  setSessionTokenState(sessionManager.getTokenState());
@@ -1,9 +1,16 @@
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 { DEMO_MODE_LOCAL_ONLY?: string })
7
+ .DEMO_MODE_LOCAL_ONLY;
8
+ const isDemoModeLocalOnly =
9
+ demoModeLocalOnlyEnv === "true" || isDemoModeLocalOnlyServer() === true;
10
+ const issuer = env.GATEWAY_URL || (isDemoModeLocalOnly ? "local" : "");
11
+
5
12
  return {
6
- issuer: env.GATEWAY_URL,
13
+ issuer,
7
14
  audience: import.meta.env.VITE_APP_ID,
8
15
  };
9
16
  }
@@ -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,11 @@ 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 { DEMO_MODE_LOCAL_ONLY?: string })
44
+ .DEMO_MODE_LOCAL_ONLY;
45
+ const isDemoModeLocalOnly =
46
+ demoModeLocalOnlyEnv === "true" || isDemoModeLocalOnlyServer() === true;
47
+
38
48
  if (!authHeader) {
39
49
  console.log("No auth header found");
40
50
  return null;
@@ -46,6 +56,14 @@ export async function authenticateRequest(
46
56
  return null;
47
57
  }
48
58
 
59
+ if (isDemoModeLocalOnly) {
60
+ if (token !== DEMO_MODE_LOCAL_ONLY_TOKEN) {
61
+ return null;
62
+ }
63
+
64
+ return createDemoModeLocalOnlySessionPayload(authConfig.audience);
65
+ }
66
+
49
67
  try {
50
68
  const session = await verifySessionToken(token, authConfig);
51
69
  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;