@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.
- package/dist/core/authenticatedFetch.d.ts.map +1 -1
- package/dist/core/authenticatedFetch.js +4 -0
- package/dist/core/localDemoSessionManager.d.ts +42 -0
- package/dist/core/localDemoSessionManager.d.ts.map +1 -0
- package/dist/core/localDemoSessionManager.js +52 -0
- package/dist/core/sessionManager.d.ts +1 -0
- package/dist/core/sessionManager.d.ts.map +1 -1
- package/dist/core/sessionManager.js +41 -40
- package/dist/shared/demoModeLocalOnly.d.ts +14 -0
- package/dist/shared/demoModeLocalOnly.d.ts.map +1 -0
- package/dist/shared/demoModeLocalOnly.js +30 -0
- package/dist/shared/localOnly.d.ts +14 -0
- package/dist/shared/localOnly.d.ts.map +1 -0
- package/dist/shared/localOnly.js +30 -0
- package/dist/tanstack/EmbeddedAppProvider.js +2 -2
- package/dist/tanstack/_internal/useEveryAppSession.d.ts +4 -1
- package/dist/tanstack/_internal/useEveryAppSession.d.ts.map +1 -1
- package/dist/tanstack/_internal/useEveryAppSession.js +10 -12
- package/dist/tanstack/server/authConfig.d.ts.map +1 -1
- package/dist/tanstack/server/authConfig.js +5 -1
- package/dist/tanstack/server/authenticateRequest.d.ts.map +1 -1
- package/dist/tanstack/server/authenticateRequest.js +9 -0
- package/dist/tanstack/useSessionTokenClientMiddleware.d.ts.map +1 -1
- package/dist/tanstack/useSessionTokenClientMiddleware.js +8 -0
- package/package.json +1 -1
- package/src/core/authenticatedFetch.ts +9 -0
- package/src/core/sessionManager.ts +53 -8
- package/src/shared/demoModeLocalOnly.ts +40 -0
- package/src/tanstack/EmbeddedAppProvider.tsx +2 -2
- package/src/tanstack/_internal/useEveryAppSession.tsx +3 -2
- package/src/tanstack/server/authConfig.ts +8 -1
- package/src/tanstack/server/authenticateRequest.ts +18 -0
- package/src/tanstack/useSessionTokenClientMiddleware.ts +12 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticatedFetch.d.ts","sourceRoot":"","sources":["../../src/core/authenticatedFetch.ts"],"names":[],"mappings":"
|
|
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":"
|
|
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 (!
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 =
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
25
|
-
console.log("[EmbeddedProvider] Session token state", tokenState);
|
|
26
|
-
setSessionTokenState(tokenState);
|
|
20
|
+
setSessionTokenState(sessionManager.getTokenState());
|
|
27
21
|
}, 5000);
|
|
28
|
-
|
|
29
|
-
|
|
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;
|
|
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
|
|
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;
|
|
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":"
|
|
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,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 (!
|
|
49
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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 =
|
|
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)
|
|
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
|
|
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;
|