@every-app/sdk 0.1.4 → 0.1.6

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 (37) hide show
  1. package/dist/cloudflare/server/gateway.d.ts +29 -0
  2. package/dist/cloudflare/server/gateway.d.ts.map +1 -0
  3. package/dist/cloudflare/server/gateway.js +63 -0
  4. package/dist/cloudflare/server/index.d.ts +1 -0
  5. package/dist/cloudflare/server/index.d.ts.map +1 -1
  6. package/dist/cloudflare/server/index.js +1 -0
  7. package/dist/core/authenticatedFetch.d.ts.map +1 -1
  8. package/dist/core/authenticatedFetch.js +0 -4
  9. package/dist/core/sessionManager.d.ts +0 -1
  10. package/dist/core/sessionManager.d.ts.map +1 -1
  11. package/dist/core/sessionManager.js +9 -41
  12. package/dist/shared/demoModeLocalOnly.d.ts +6 -6
  13. package/dist/shared/demoModeLocalOnly.d.ts.map +1 -1
  14. package/dist/shared/demoModeLocalOnly.js +12 -11
  15. package/dist/tanstack/EmbeddedAppProvider.js +2 -2
  16. package/dist/tanstack/_internal/useEveryAppSession.d.ts.map +1 -1
  17. package/dist/tanstack/_internal/useEveryAppSession.js +2 -2
  18. package/dist/tanstack/server/authConfig.d.ts.map +1 -1
  19. package/dist/tanstack/server/authConfig.js +1 -5
  20. package/dist/tanstack/server/authenticateRequest.d.ts.map +1 -1
  21. package/dist/tanstack/server/authenticateRequest.js +0 -10
  22. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts +5 -1
  23. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts.map +1 -1
  24. package/dist/tanstack/useSessionTokenClientMiddleware.js +6 -9
  25. package/package.json +1 -1
  26. package/src/cloudflare/server/gateway.test.ts +183 -0
  27. package/src/cloudflare/server/gateway.ts +105 -0
  28. package/src/cloudflare/server/index.ts +1 -0
  29. package/src/core/authenticatedFetch.ts +0 -9
  30. package/src/core/sessionManager.ts +8 -53
  31. package/src/env.d.ts +2 -0
  32. package/src/tanstack/EmbeddedAppProvider.tsx +2 -2
  33. package/src/tanstack/_internal/useEveryAppSession.tsx +2 -3
  34. package/src/tanstack/server/authConfig.ts +1 -8
  35. package/src/tanstack/server/authenticateRequest.ts +0 -19
  36. package/src/tanstack/useSessionTokenClientMiddleware.ts +8 -13
  37. package/src/shared/demoModeLocalOnly.ts +0 -40
@@ -0,0 +1,29 @@
1
+ interface GatewayFetcher {
2
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
3
+ }
4
+ interface GatewayEnv {
5
+ GATEWAY_URL?: string;
6
+ EVERY_APP_GATEWAY?: GatewayFetcher;
7
+ GATEWAY_APP_API_TOKEN?: string;
8
+ APP_TOKEN?: string;
9
+ }
10
+ interface FetchGatewayOptions {
11
+ env: GatewayEnv;
12
+ /** The URL, path, or Request to send to the gateway. Typically the full URL
13
+ * passed by a provider SDK's custom `fetch` override. */
14
+ url: string | URL | Request;
15
+ /** Standard `RequestInit` (method, headers, body, etc.) from the provider SDK. */
16
+ init?: RequestInit;
17
+ }
18
+ export declare function getGatewayUrl(env: GatewayEnv): string;
19
+ /**
20
+ * Fetch from the gateway proxy, authenticating with the app token.
21
+ *
22
+ * - Strips any existing `Authorization` header (the gateway only accepts
23
+ * app token auth via `x-every-app-token`).
24
+ * - Requires `GATEWAY_APP_API_TOKEN` (or legacy `APP_TOKEN`) in the env.
25
+ * - Routes via service binding in production, falls back to HTTP in dev.
26
+ */
27
+ export declare function fetchGateway({ env, url, init, }: FetchGatewayOptions): Promise<Response>;
28
+ export {};
29
+ //# sourceMappingURL=gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/server/gateway.ts"],"names":[],"mappings":"AAGA,UAAU,cAAc;IACtB,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxE;AAED,UAAU,UAAU;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,cAAc,CAAC;IACnC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,mBAAmB;IAC3B,GAAG,EAAE,UAAU,CAAC;IAChB;8DAC0D;IAC1D,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC;IAC5B,kFAAkF;IAClF,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAMrD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,EACjC,GAAG,EACH,GAAG,EACH,IAAI,GACL,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgBzC"}
@@ -0,0 +1,63 @@
1
+ const SERVICE_BINDING_ORIGIN = "http://localhost";
2
+ const APP_TOKEN_HEADER = "x-every-app-token";
3
+ export function getGatewayUrl(env) {
4
+ const gatewayUrl = env.GATEWAY_URL?.trim();
5
+ if (!gatewayUrl) {
6
+ throw new Error("GATEWAY_URL is required");
7
+ }
8
+ return gatewayUrl;
9
+ }
10
+ /**
11
+ * Fetch from the gateway proxy, authenticating with the app token.
12
+ *
13
+ * - Strips any existing `Authorization` header (the gateway only accepts
14
+ * app token auth via `x-every-app-token`).
15
+ * - Requires `GATEWAY_APP_API_TOKEN` (or legacy `APP_TOKEN`) in the env.
16
+ * - Routes via service binding in production, falls back to HTTP in dev.
17
+ */
18
+ export async function fetchGateway({ env, url, init, }) {
19
+ const gatewayBaseUrl = getGatewayUrl(env);
20
+ const resolvedRequest = toRequest(url, init, gatewayBaseUrl);
21
+ const authenticatedRequest = applyAppTokenAuth(resolvedRequest, env);
22
+ // Use service binding when available for zero-latency internal routing
23
+ // (available in production Workers, not in local dev)
24
+ if (env.EVERY_APP_GATEWAY) {
25
+ const url = new URL(authenticatedRequest.url);
26
+ const bindingUrl = `${SERVICE_BINDING_ORIGIN}${url.pathname}${url.search}`;
27
+ const bindingRequest = new Request(bindingUrl, authenticatedRequest);
28
+ return env.EVERY_APP_GATEWAY.fetch(bindingRequest);
29
+ }
30
+ // Fall back to HTTP fetch for local dev
31
+ return fetch(authenticatedRequest);
32
+ }
33
+ function applyAppTokenAuth(request, env) {
34
+ const appToken = getGatewayAppApiToken(env);
35
+ if (!appToken) {
36
+ throw new Error("GATEWAY_APP_API_TOKEN is required. Run `npx everyapp app deploy` to provision one.");
37
+ }
38
+ const headers = new Headers(request.headers);
39
+ headers.delete("authorization");
40
+ headers.set(APP_TOKEN_HEADER, appToken);
41
+ return new Request(request, { headers });
42
+ }
43
+ function getGatewayAppApiToken(env) {
44
+ const configuredToken = env.GATEWAY_APP_API_TOKEN?.trim();
45
+ if (configuredToken) {
46
+ return configuredToken;
47
+ }
48
+ const legacyToken = env.APP_TOKEN?.trim();
49
+ return legacyToken || null;
50
+ }
51
+ function toRequest(input, init, baseUrl) {
52
+ if (input instanceof Request) {
53
+ return init ? new Request(input, init) : input;
54
+ }
55
+ if (input instanceof URL) {
56
+ return new Request(input.toString(), init);
57
+ }
58
+ if (typeof input === "string" && baseUrl && !/^https?:\/\//i.test(input)) {
59
+ const normalizedPath = input.startsWith("/") ? input : `/${input}`;
60
+ return new Request(new URL(normalizedPath, baseUrl).toString(), init);
61
+ }
62
+ return new Request(input, init);
63
+ }
@@ -1,2 +1,3 @@
1
1
  export { getLocalD1Url } from "../getLocalD1Url.js";
2
+ export { fetchGateway, getGatewayUrl } from "./gateway";
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -1 +1,2 @@
1
1
  export { getLocalD1Url } from "../getLocalD1Url.js";
2
+ export { fetchGateway, getGatewayUrl } from "./gateway";
@@ -1 +1 @@
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
+ {"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,11 +1,7 @@
1
- import { LOCAL_ONLY_TOKEN, isLocalOnlyClient, } from "../shared/demoModeLocalOnly";
2
1
  /**
3
2
  * Gets the current session token from the embedded session manager
4
3
  */
5
4
  export async function getSessionToken() {
6
- if (isLocalOnlyClient()) {
7
- return LOCAL_ONLY_TOKEN;
8
- }
9
5
  const windowWithSession = window;
10
6
  const sessionManager = windowWithSession.__embeddedSessionManager;
11
7
  if (!sessionManager) {
@@ -10,7 +10,6 @@ export declare class SessionManager {
10
10
  readonly parentOrigin: string;
11
11
  readonly appId: string;
12
12
  readonly isInIframe: boolean;
13
- readonly isDemoModeLocalOnly: boolean;
14
13
  private token;
15
14
  private refreshPromise;
16
15
  constructor(config: SessionManagerConfig);
@@ -1 +1 @@
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
+ {"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,4 +1,3 @@
1
- import { LOCAL_ONLY_EMAIL, LOCAL_ONLY_TOKEN, LOCAL_ONLY_USER_ID, isLocalOnlyClient, } from "../shared/demoModeLocalOnly";
2
1
  const MESSAGE_TIMEOUT_MS = 5000;
3
2
  const TOKEN_EXPIRY_BUFFER_MS = 10000;
4
3
  const DEFAULT_TOKEN_LIFETIME_MS = 60000;
@@ -20,37 +19,25 @@ export class SessionManager {
20
19
  parentOrigin;
21
20
  appId;
22
21
  isInIframe;
23
- isDemoModeLocalOnly;
24
22
  token = null;
25
23
  refreshPromise = null;
26
24
  constructor(config) {
27
25
  if (!config.appId) {
28
26
  throw new Error("[SessionManager] appId is required.");
29
27
  }
30
- this.isDemoModeLocalOnly = isLocalOnlyClient();
31
28
  const gatewayUrl = import.meta.env.VITE_GATEWAY_URL;
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
- }
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}`);
42
37
  }
43
38
  this.appId = config.appId;
44
- this.parentOrigin = this.isDemoModeLocalOnly
45
- ? window.location.origin
46
- : gatewayUrl;
39
+ this.parentOrigin = gatewayUrl;
47
40
  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
- }
54
41
  }
55
42
  isTokenExpiringSoon(bufferMs = TOKEN_EXPIRY_BUFFER_MS) {
56
43
  if (!this.token)
@@ -90,13 +77,6 @@ export class SessionManager {
90
77
  });
91
78
  }
92
79
  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
- }
100
80
  if (this.refreshPromise) {
101
81
  return this.refreshPromise;
102
82
  }
@@ -132,12 +112,6 @@ export class SessionManager {
132
112
  }
133
113
  }
134
114
  async getToken() {
135
- if (this.isDemoModeLocalOnly) {
136
- if (!this.token || this.isTokenExpiringSoon()) {
137
- return this.requestNewToken();
138
- }
139
- return this.token.token;
140
- }
141
115
  if (this.isTokenExpiringSoon()) {
142
116
  return this.requestNewToken();
143
117
  }
@@ -160,12 +134,6 @@ export class SessionManager {
160
134
  * Returns null if no valid token is available.
161
135
  */
162
136
  getUser() {
163
- if (this.isDemoModeLocalOnly) {
164
- return {
165
- userId: LOCAL_ONLY_USER_ID,
166
- email: LOCAL_ONLY_EMAIL,
167
- };
168
- }
169
137
  if (!this.token) {
170
138
  return null;
171
139
  }
@@ -1,9 +1,9 @@
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): {
1
+ export declare const DEMO_MODE_LOCAL_ONLY_TOKEN = "DEMO_MODE_LOCAL_ONLY";
2
+ export declare const DEMO_MODE_LOCAL_ONLY_USER_ID = "demo-local-user";
3
+ export declare const DEMO_MODE_LOCAL_ONLY_EMAIL = "demo-local-user@local";
4
+ export declare function isDemoModeLocalOnlyClient(): boolean;
5
+ export declare function isDemoModeLocalOnlyServer(): boolean;
6
+ export declare function createDemoModeLocalOnlySessionPayload(audience: string): {
7
7
  sub: string;
8
8
  email: string;
9
9
  iss: string;
@@ -1 +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"}
1
+ {"version":3,"file":"demoModeLocalOnly.d.ts","sourceRoot":"","sources":["../../src/shared/demoModeLocalOnly.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AACjE,eAAO,MAAM,4BAA4B,oBAAoB,CAAC;AAC9D,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAElE,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,wBAAgB,yBAAyB,IAAI,OAAO,CAiBnD;AAED,wBAAgB,qCAAqC,CAAC,QAAQ,EAAE,MAAM;;;;;;;EAYrE"}
@@ -1,27 +1,28 @@
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";
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
+ export function isDemoModeLocalOnlyClient() {
5
+ return import.meta.env.VITE_DEMO_MODE_LOCAL_ONLY === "true";
6
6
  }
7
- export function isLocalOnlyServer() {
7
+ export function isDemoModeLocalOnlyServer() {
8
8
  const metaEnv = import.meta
9
9
  .env;
10
- const metaValue = metaEnv?.LOCAL_ONLY ?? metaEnv?.VITE_LOCAL_ONLY;
10
+ const metaValue = metaEnv?.DEMO_MODE_LOCAL_ONLY ?? metaEnv?.VITE_DEMO_MODE_LOCAL_ONLY;
11
11
  if (metaValue === "true") {
12
12
  return true;
13
13
  }
14
- if (typeof process !== "undefined" && process.env?.LOCAL_ONLY === "true") {
14
+ if (typeof process !== "undefined" &&
15
+ process.env?.DEMO_MODE_LOCAL_ONLY === "true") {
15
16
  return true;
16
17
  }
17
18
  return false;
18
19
  }
19
- export function createLocalOnlySessionPayload(audience) {
20
+ export function createDemoModeLocalOnlySessionPayload(audience) {
20
21
  const issuedAt = Math.floor(Date.now() / 1000);
21
22
  const expiresAt = issuedAt + 60 * 60;
22
23
  return {
23
- sub: LOCAL_ONLY_USER_ID,
24
- email: LOCAL_ONLY_EMAIL,
24
+ sub: DEMO_MODE_LOCAL_ONLY_USER_ID,
25
+ email: DEMO_MODE_LOCAL_ONLY_EMAIL,
25
26
  iss: "local",
26
27
  aud: audience,
27
28
  iat: issuedAt,
@@ -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 (skip in demo mode)
15
- if (!sessionManager.isInIframe && !sessionManager.isDemoModeLocalOnly) {
14
+ // Check if the app is running outside of the Gateway iframe
15
+ if (!sessionManager.isInIframe) {
16
16
  return (_jsx(GatewayRequiredError, { gatewayOrigin: sessionManager.parentOrigin, appId: config.appId }));
17
17
  }
18
18
  const value = {
@@ -1 +1 @@
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
+ {"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;;;;;;EA8C1B"}
@@ -13,8 +13,8 @@ export function useEveryAppSession({ sessionManagerConfig, }) {
13
13
  useEffect(() => {
14
14
  if (!sessionManager)
15
15
  return;
16
- // Skip token requests when not in iframe (unless in demo mode) - the app will show GatewayRequiredError instead
17
- if (!sessionManager.isInIframe && !sessionManager.isDemoModeLocalOnly)
16
+ // Skip token requests when not in iframe - the app will show GatewayRequiredError instead
17
+ if (!sessionManager.isInIframe)
18
18
  return;
19
19
  const interval = setInterval(() => {
20
20
  setSessionTokenState(sessionManager.getTokenState());
@@ -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;AAI1C,wBAAgB,aAAa,IAAI,UAAU,CAU1C"}
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,11 +1,7 @@
1
1
  import { env } from "cloudflare:workers";
2
- import { isLocalOnlyServer } from "../../shared/demoModeLocalOnly";
3
2
  export function getAuthConfig() {
4
- const demoModeLocalOnlyEnv = env.LOCAL_ONLY;
5
- const isDemoModeLocalOnly = demoModeLocalOnlyEnv === "true" || isLocalOnlyServer() === true;
6
- const issuer = env.GATEWAY_URL || (isDemoModeLocalOnly ? "local" : "");
7
3
  return {
8
- issuer,
4
+ issuer: env.GATEWAY_URL,
9
5
  audience: import.meta.env.VITE_APP_ID,
10
6
  };
11
7
  }
@@ -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;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
+ {"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,CA8BrC;AAyCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK3E"}
@@ -1,26 +1,16 @@
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";
5
4
  export async function authenticateRequest(authConfig, providedRequest) {
6
5
  const request = providedRequest || getRequest();
7
6
  const authHeader = request.headers.get("authorization");
8
- const demoModeLocalOnlyEnv = env.LOCAL_ONLY;
9
- const isDemoModeLocalOnly = demoModeLocalOnlyEnv === "true" || isLocalOnlyServer() === true;
10
7
  if (!authHeader) {
11
- console.log("No auth header found");
12
8
  return null;
13
9
  }
14
10
  const token = extractBearerToken(authHeader);
15
11
  if (!token) {
16
12
  return null;
17
13
  }
18
- if (isDemoModeLocalOnly) {
19
- if (token !== LOCAL_ONLY_TOKEN) {
20
- return null;
21
- }
22
- return createLocalOnlySessionPayload(authConfig.audience);
23
- }
24
14
  try {
25
15
  const session = await verifySessionToken(token, authConfig);
26
16
  return session;
@@ -1,2 +1,6 @@
1
- export declare const useSessionTokenClientMiddleware: import("@tanstack/react-start").FunctionMiddlewareAfterClient<{}, unknown, undefined, undefined, undefined>;
1
+ /**
2
+ * Exported as `any` to avoid cross-package type identity issues when apps and
3
+ * the SDK resolve different `@tanstack/react-start` instances in a monorepo.
4
+ */
5
+ export declare const useSessionTokenClientMiddleware: any;
2
6
  //# sourceMappingURL=useSessionTokenClientMiddleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionTokenClientMiddleware.d.ts","sourceRoot":"","sources":["../../src/tanstack/useSessionTokenClientMiddleware.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,+BAA+B,6GAmC1C,CAAC"}
1
+ {"version":3,"file":"useSessionTokenClientMiddleware.d.ts","sourceRoot":"","sources":["../../src/tanstack/useSessionTokenClientMiddleware.ts"],"names":[],"mappings":"AAgCA;;;GAGG;AACH,eAAO,MAAM,+BAA+B,EAAE,GACZ,CAAC"}
@@ -1,15 +1,7 @@
1
1
  import { createMiddleware } from "@tanstack/react-start";
2
- import { LOCAL_ONLY_TOKEN, isLocalOnlyClient, } from "../shared/demoModeLocalOnly";
3
- export const useSessionTokenClientMiddleware = createMiddleware({
2
+ const _useSessionTokenClientMiddleware = createMiddleware({
4
3
  type: "function",
5
4
  }).client(async ({ next }) => {
6
- if (isLocalOnlyClient()) {
7
- return next({
8
- headers: {
9
- Authorization: `Bearer ${LOCAL_ONLY_TOKEN}`,
10
- },
11
- });
12
- }
13
5
  // Get the global sessionManager - this MUST be available for embedded apps
14
6
  const sessionManager = window
15
7
  .__embeddedSessionManager;
@@ -27,3 +19,8 @@ export const useSessionTokenClientMiddleware = createMiddleware({
27
19
  },
28
20
  });
29
21
  });
22
+ /**
23
+ * Exported as `any` to avoid cross-package type identity issues when apps and
24
+ * the SDK resolve different `@tanstack/react-start` instances in a monorepo.
25
+ */
26
+ export const useSessionTokenClientMiddleware = _useSessionTokenClientMiddleware;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@every-app/sdk",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -0,0 +1,183 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { fetchGateway, getGatewayUrl } from "./gateway";
3
+
4
+ type TestFetcher = {
5
+ fetch: ReturnType<typeof vi.fn>;
6
+ };
7
+
8
+ type TestEnv = {
9
+ GATEWAY_URL?: string;
10
+ EVERY_APP_GATEWAY?: TestFetcher;
11
+ GATEWAY_APP_API_TOKEN?: string;
12
+ APP_TOKEN?: string;
13
+ };
14
+
15
+ describe("gateway server helpers", () => {
16
+ beforeEach(() => {
17
+ vi.restoreAllMocks();
18
+ });
19
+
20
+ afterEach(() => {
21
+ vi.restoreAllMocks();
22
+ });
23
+
24
+ it("returns gateway URL and throws when missing", () => {
25
+ expect(getGatewayUrl({ GATEWAY_URL: "https://gateway.example.com" })).toBe(
26
+ "https://gateway.example.com",
27
+ );
28
+
29
+ expect(() => getGatewayUrl({} as TestEnv)).toThrow(
30
+ "GATEWAY_URL is required",
31
+ );
32
+ });
33
+
34
+ it("fetches via HTTP when service binding is unavailable", async () => {
35
+ const fetchMock = vi
36
+ .spyOn(globalThis, "fetch")
37
+ .mockResolvedValue(new Response("ok", { status: 200 }));
38
+
39
+ const env: TestEnv = {
40
+ GATEWAY_URL: "https://gateway.example.com",
41
+ GATEWAY_APP_API_TOKEN: "eat_test_token",
42
+ };
43
+
44
+ await fetchGateway({
45
+ env,
46
+ url: "/api/ai/openai/v1/responses?stream=true",
47
+ init: { method: "POST" },
48
+ });
49
+
50
+ expect(fetchMock).toHaveBeenCalledTimes(1);
51
+ const [requestArg] = fetchMock.mock.calls[0];
52
+ const request = requestArg as Request;
53
+
54
+ expect(request.url).toBe(
55
+ "https://gateway.example.com/api/ai/openai/v1/responses?stream=true",
56
+ );
57
+ });
58
+
59
+ it("fetches via service binding when available", async () => {
60
+ const bindingFetch = vi
61
+ .fn()
62
+ .mockResolvedValue(new Response("ok", { status: 200 }));
63
+
64
+ const env: TestEnv = {
65
+ GATEWAY_URL: "https://gateway.example.com",
66
+ EVERY_APP_GATEWAY: { fetch: bindingFetch },
67
+ GATEWAY_APP_API_TOKEN: "eat_test_token",
68
+ };
69
+
70
+ await fetchGateway({
71
+ env,
72
+ url: "/api/ai/openai/v1/chat/completions",
73
+ init: { method: "POST" },
74
+ });
75
+
76
+ expect(bindingFetch).toHaveBeenCalledTimes(1);
77
+ const [requestArg] = bindingFetch.mock.calls[0];
78
+ const request = requestArg as Request;
79
+ expect(request.url).toBe(
80
+ "http://localhost/api/ai/openai/v1/chat/completions",
81
+ );
82
+ });
83
+
84
+ it("always injects app token and strips Authorization header", async () => {
85
+ const fetchMock = vi
86
+ .spyOn(globalThis, "fetch")
87
+ .mockResolvedValue(new Response("ok", { status: 200 }));
88
+
89
+ const env: TestEnv = {
90
+ GATEWAY_URL: "https://gateway.example.com",
91
+ GATEWAY_APP_API_TOKEN: "eat_my_token",
92
+ };
93
+
94
+ await fetchGateway({
95
+ env,
96
+ url: "/api/ai/openai/v1/responses",
97
+ init: {
98
+ method: "POST",
99
+ headers: {
100
+ authorization: "Bearer some-sdk-dummy-value",
101
+ },
102
+ },
103
+ });
104
+
105
+ expect(fetchMock).toHaveBeenCalledTimes(1);
106
+ const [requestArg] = fetchMock.mock.calls[0];
107
+ const request = requestArg as Request;
108
+
109
+ expect(request.headers.get("x-every-app-token")).toBe("eat_my_token");
110
+ expect(request.headers.get("authorization")).toBeNull();
111
+ });
112
+
113
+ it("throws when app token is missing", async () => {
114
+ const env: TestEnv = {
115
+ GATEWAY_URL: "https://gateway.example.com",
116
+ };
117
+
118
+ await expect(
119
+ fetchGateway({
120
+ env,
121
+ url: "/api/ai/openai/v1/responses",
122
+ }),
123
+ ).rejects.toThrow("GATEWAY_APP_API_TOKEN is required");
124
+ });
125
+
126
+ it("supports legacy APP_TOKEN env variable", async () => {
127
+ const fetchMock = vi
128
+ .spyOn(globalThis, "fetch")
129
+ .mockResolvedValue(new Response("ok", { status: 200 }));
130
+
131
+ const env: TestEnv = {
132
+ GATEWAY_URL: "https://gateway.example.com",
133
+ APP_TOKEN: "eat_legacy_token",
134
+ };
135
+
136
+ await fetchGateway({
137
+ env,
138
+ url: "/api/ai/openai/v1/responses",
139
+ init: { method: "POST" },
140
+ });
141
+
142
+ expect(fetchMock).toHaveBeenCalledTimes(1);
143
+ const [requestArg] = fetchMock.mock.calls[0];
144
+ const request = requestArg as Request;
145
+
146
+ expect(request.headers.get("x-every-app-token")).toBe("eat_legacy_token");
147
+ expect(request.headers.get("authorization")).toBeNull();
148
+ });
149
+
150
+ it("supports Request input and preserves method/body", async () => {
151
+ const fetchMock = vi
152
+ .spyOn(globalThis, "fetch")
153
+ .mockResolvedValue(new Response("ok", { status: 200 }));
154
+
155
+ const env: TestEnv = {
156
+ GATEWAY_URL: "https://gateway.example.com",
157
+ GATEWAY_APP_API_TOKEN: "eat_test_token",
158
+ };
159
+
160
+ const sourceRequest = new Request(
161
+ "https://gateway.example.com/api/ai/openai/v1/responses",
162
+ {
163
+ method: "POST",
164
+ body: JSON.stringify({ model: "gpt-5.2" }),
165
+ headers: { "content-type": "application/json" },
166
+ },
167
+ );
168
+
169
+ await fetchGateway({
170
+ env,
171
+ url: sourceRequest,
172
+ });
173
+
174
+ expect(fetchMock).toHaveBeenCalledTimes(1);
175
+ const [requestArg] = fetchMock.mock.calls[0];
176
+ const request = requestArg as Request;
177
+ expect(request.url).toBe(
178
+ "https://gateway.example.com/api/ai/openai/v1/responses",
179
+ );
180
+ expect(request.method).toBe("POST");
181
+ expect(request.headers.get("content-type")).toBe("application/json");
182
+ });
183
+ });
@@ -0,0 +1,105 @@
1
+ const SERVICE_BINDING_ORIGIN = "http://localhost";
2
+ const APP_TOKEN_HEADER = "x-every-app-token";
3
+
4
+ interface GatewayFetcher {
5
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
6
+ }
7
+
8
+ interface GatewayEnv {
9
+ GATEWAY_URL?: string;
10
+ EVERY_APP_GATEWAY?: GatewayFetcher;
11
+ GATEWAY_APP_API_TOKEN?: string;
12
+ APP_TOKEN?: string;
13
+ }
14
+
15
+ interface FetchGatewayOptions {
16
+ env: GatewayEnv;
17
+ /** The URL, path, or Request to send to the gateway. Typically the full URL
18
+ * passed by a provider SDK's custom `fetch` override. */
19
+ url: string | URL | Request;
20
+ /** Standard `RequestInit` (method, headers, body, etc.) from the provider SDK. */
21
+ init?: RequestInit;
22
+ }
23
+
24
+ export function getGatewayUrl(env: GatewayEnv): string {
25
+ const gatewayUrl = env.GATEWAY_URL?.trim();
26
+ if (!gatewayUrl) {
27
+ throw new Error("GATEWAY_URL is required");
28
+ }
29
+ return gatewayUrl;
30
+ }
31
+
32
+ /**
33
+ * Fetch from the gateway proxy, authenticating with the app token.
34
+ *
35
+ * - Strips any existing `Authorization` header (the gateway only accepts
36
+ * app token auth via `x-every-app-token`).
37
+ * - Requires `GATEWAY_APP_API_TOKEN` (or legacy `APP_TOKEN`) in the env.
38
+ * - Routes via service binding in production, falls back to HTTP in dev.
39
+ */
40
+ export async function fetchGateway({
41
+ env,
42
+ url,
43
+ init,
44
+ }: FetchGatewayOptions): Promise<Response> {
45
+ const gatewayBaseUrl = getGatewayUrl(env);
46
+ const resolvedRequest = toRequest(url, init, gatewayBaseUrl);
47
+ const authenticatedRequest = applyAppTokenAuth(resolvedRequest, env);
48
+
49
+ // Use service binding when available for zero-latency internal routing
50
+ // (available in production Workers, not in local dev)
51
+ if (env.EVERY_APP_GATEWAY) {
52
+ const url = new URL(authenticatedRequest.url);
53
+ const bindingUrl = `${SERVICE_BINDING_ORIGIN}${url.pathname}${url.search}`;
54
+ const bindingRequest = new Request(bindingUrl, authenticatedRequest);
55
+ return env.EVERY_APP_GATEWAY.fetch(bindingRequest);
56
+ }
57
+
58
+ // Fall back to HTTP fetch for local dev
59
+ return fetch(authenticatedRequest);
60
+ }
61
+
62
+ function applyAppTokenAuth(request: Request, env: GatewayEnv): Request {
63
+ const appToken = getGatewayAppApiToken(env);
64
+ if (!appToken) {
65
+ throw new Error(
66
+ "GATEWAY_APP_API_TOKEN is required. Run `npx everyapp app deploy` to provision one.",
67
+ );
68
+ }
69
+
70
+ const headers = new Headers(request.headers);
71
+ headers.delete("authorization");
72
+ headers.set(APP_TOKEN_HEADER, appToken);
73
+ return new Request(request, { headers });
74
+ }
75
+
76
+ function getGatewayAppApiToken(env: GatewayEnv): string | null {
77
+ const configuredToken = env.GATEWAY_APP_API_TOKEN?.trim();
78
+ if (configuredToken) {
79
+ return configuredToken;
80
+ }
81
+
82
+ const legacyToken = env.APP_TOKEN?.trim();
83
+ return legacyToken || null;
84
+ }
85
+
86
+ function toRequest(
87
+ input: RequestInfo | URL,
88
+ init?: RequestInit,
89
+ baseUrl?: string,
90
+ ): Request {
91
+ if (input instanceof Request) {
92
+ return init ? new Request(input, init) : input;
93
+ }
94
+
95
+ if (input instanceof URL) {
96
+ return new Request(input.toString(), init);
97
+ }
98
+
99
+ if (typeof input === "string" && baseUrl && !/^https?:\/\//i.test(input)) {
100
+ const normalizedPath = input.startsWith("/") ? input : `/${input}`;
101
+ return new Request(new URL(normalizedPath, baseUrl).toString(), init);
102
+ }
103
+
104
+ return new Request(input, init);
105
+ }
@@ -1 +1,2 @@
1
1
  export { getLocalD1Url } from "../getLocalD1Url.js";
2
+ export { fetchGateway, getGatewayUrl } from "./gateway";
@@ -1,8 +1,3 @@
1
- import {
2
- DEMO_MODE_LOCAL_ONLY_TOKEN,
3
- isDemoModeLocalOnlyClient,
4
- } from "../shared/demoModeLocalOnly";
5
-
6
1
  interface SessionManager {
7
2
  getToken(): Promise<string>;
8
3
  }
@@ -15,10 +10,6 @@ interface WindowWithSessionManager extends Window {
15
10
  * Gets the current session token from the embedded session manager
16
11
  */
17
12
  export async function getSessionToken(): Promise<string> {
18
- if (isDemoModeLocalOnlyClient()) {
19
- return DEMO_MODE_LOCAL_ONLY_TOKEN;
20
- }
21
-
22
13
  const windowWithSession = window as WindowWithSessionManager;
23
14
  const sessionManager = windowWithSession.__embeddedSessionManager;
24
15
 
@@ -1,10 +1,3 @@
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
-
8
1
  interface SessionToken {
9
2
  token: string;
10
3
  expiresAt: number;
@@ -42,7 +35,6 @@ export class SessionManager {
42
35
  readonly parentOrigin: string;
43
36
  readonly appId: string;
44
37
  readonly isInIframe: boolean;
45
- readonly isDemoModeLocalOnly: boolean;
46
38
 
47
39
  private token: SessionToken | null = null;
48
40
  private refreshPromise: Promise<string> | null = null;
@@ -52,35 +44,20 @@ export class SessionManager {
52
44
  throw new Error("[SessionManager] appId is required.");
53
45
  }
54
46
 
55
- this.isDemoModeLocalOnly = isDemoModeLocalOnlyClient();
56
-
57
47
  const gatewayUrl = import.meta.env.VITE_GATEWAY_URL;
58
- if (!this.isDemoModeLocalOnly) {
59
- if (!gatewayUrl) {
60
- throw new Error(
61
- "[SessionManager] VITE_GATEWAY_URL env var is required.",
62
- );
63
- }
48
+ if (!gatewayUrl) {
49
+ throw new Error("[SessionManager] VITE_GATEWAY_URL env var is required.");
50
+ }
64
51
 
65
- try {
66
- new URL(gatewayUrl);
67
- } catch {
68
- throw new Error(`[SessionManager] Invalid gateway URL: ${gatewayUrl}`);
69
- }
52
+ try {
53
+ new URL(gatewayUrl);
54
+ } catch {
55
+ throw new Error(`[SessionManager] Invalid gateway URL: ${gatewayUrl}`);
70
56
  }
71
57
 
72
58
  this.appId = config.appId;
73
- this.parentOrigin = this.isDemoModeLocalOnly
74
- ? window.location.origin
75
- : gatewayUrl;
59
+ this.parentOrigin = gatewayUrl;
76
60
  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
- }
84
61
  }
85
62
 
86
63
  private isTokenExpiringSoon(
@@ -130,14 +107,6 @@ export class SessionManager {
130
107
  }
131
108
 
132
109
  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
-
141
110
  if (this.refreshPromise) {
142
111
  return this.refreshPromise;
143
112
  }
@@ -184,13 +153,6 @@ export class SessionManager {
184
153
  }
185
154
 
186
155
  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
-
194
156
  if (this.isTokenExpiringSoon()) {
195
157
  return this.requestNewToken();
196
158
  }
@@ -221,13 +183,6 @@ export class SessionManager {
221
183
  * Returns null if no valid token is available.
222
184
  */
223
185
  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
-
231
186
  if (!this.token) {
232
187
  return null;
233
188
  }
package/src/env.d.ts CHANGED
@@ -5,6 +5,8 @@ declare namespace Cloudflare {
5
5
  interface Env {
6
6
  GATEWAY_URL: string;
7
7
  EVERY_APP_GATEWAY?: Fetcher;
8
+ GATEWAY_APP_API_TOKEN?: string;
9
+ APP_TOKEN?: string;
8
10
  }
9
11
  }
10
12
 
@@ -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 (skip in demo mode)
31
- if (!sessionManager.isInIframe && !sessionManager.isDemoModeLocalOnly) {
30
+ // Check if the app is running outside of the Gateway iframe
31
+ if (!sessionManager.isInIframe) {
32
32
  return (
33
33
  <GatewayRequiredError
34
34
  gatewayOrigin={sessionManager.parentOrigin}
@@ -28,9 +28,8 @@ export function useEveryAppSession({
28
28
 
29
29
  useEffect(() => {
30
30
  if (!sessionManager) 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;
31
+ // Skip token requests when not in iframe - the app will show GatewayRequiredError instead
32
+ if (!sessionManager.isInIframe) return;
34
33
 
35
34
  const interval = setInterval(() => {
36
35
  setSessionTokenState(sessionManager.getTokenState());
@@ -1,16 +1,9 @@
1
1
  import type { AuthConfig } from "./types";
2
2
  import { env } from "cloudflare:workers";
3
- import { isDemoModeLocalOnlyServer } from "../../shared/demoModeLocalOnly";
4
3
 
5
4
  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
-
12
5
  return {
13
- issuer,
6
+ issuer: env.GATEWAY_URL,
14
7
  audience: import.meta.env.VITE_APP_ID,
15
8
  };
16
9
  }
@@ -8,11 +8,6 @@ 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";
16
11
 
17
12
  /**
18
13
  * JWT payload structure for embedded app session tokens.
@@ -40,13 +35,7 @@ export async function authenticateRequest(
40
35
  const request = providedRequest || getRequest();
41
36
  const authHeader = request.headers.get("authorization");
42
37
 
43
- const demoModeLocalOnlyEnv = (env as { DEMO_MODE_LOCAL_ONLY?: string })
44
- .DEMO_MODE_LOCAL_ONLY;
45
- const isDemoModeLocalOnly =
46
- demoModeLocalOnlyEnv === "true" || isDemoModeLocalOnlyServer() === true;
47
-
48
38
  if (!authHeader) {
49
- console.log("No auth header found");
50
39
  return null;
51
40
  }
52
41
 
@@ -56,14 +45,6 @@ export async function authenticateRequest(
56
45
  return null;
57
46
  }
58
47
 
59
- if (isDemoModeLocalOnly) {
60
- if (token !== DEMO_MODE_LOCAL_ONLY_TOKEN) {
61
- return null;
62
- }
63
-
64
- return createDemoModeLocalOnlySessionPayload(authConfig.audience);
65
- }
66
-
67
48
  try {
68
49
  const session = await verifySessionToken(token, authConfig);
69
50
  return session;
@@ -1,21 +1,9 @@
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";
7
3
 
8
- export const useSessionTokenClientMiddleware = createMiddleware({
4
+ const _useSessionTokenClientMiddleware = createMiddleware({
9
5
  type: "function",
10
6
  }).client(async ({ next }) => {
11
- if (isDemoModeLocalOnlyClient()) {
12
- return next({
13
- headers: {
14
- Authorization: `Bearer ${DEMO_MODE_LOCAL_ONLY_TOKEN}`,
15
- },
16
- });
17
- }
18
-
19
7
  // Get the global sessionManager - this MUST be available for embedded apps
20
8
  const sessionManager = (window as any)
21
9
  .__embeddedSessionManager as SessionManager;
@@ -41,3 +29,10 @@ export const useSessionTokenClientMiddleware = createMiddleware({
41
29
  },
42
30
  });
43
31
  });
32
+
33
+ /**
34
+ * Exported as `any` to avoid cross-package type identity issues when apps and
35
+ * the SDK resolve different `@tanstack/react-start` instances in a monorepo.
36
+ */
37
+ export const useSessionTokenClientMiddleware: any =
38
+ _useSessionTokenClientMiddleware;
@@ -1,40 +0,0 @@
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
- }