@every-app/sdk 0.1.12 → 0.1.13
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/cloudflare/server/gateway.js +5 -0
- package/dist/tanstack/server/authenticateRequest.d.ts.map +1 -1
- package/dist/tanstack/server/authenticateRequest.js +6 -1
- package/package.json +1 -1
- package/src/cloudflare/server/gateway.test.ts +47 -0
- package/src/cloudflare/server/gateway.ts +8 -0
- package/src/tanstack/server/authenticateRequest.test.ts +35 -0
- package/src/tanstack/server/authenticateRequest.ts +7 -1
|
@@ -32,6 +32,11 @@ export async function fetchGateway({ env, url, init, }) {
|
|
|
32
32
|
return fetch(authenticatedRequest);
|
|
33
33
|
}
|
|
34
34
|
function applyAppTokenAuth(request, env) {
|
|
35
|
+
const gatewayOrigin = new URL(getGatewayUrl(env)).origin;
|
|
36
|
+
const requestOrigin = new URL(request.url).origin;
|
|
37
|
+
if (requestOrigin !== gatewayOrigin) {
|
|
38
|
+
throw new Error(`Refusing to send gateway token to non-gateway origin: ${requestOrigin}`);
|
|
39
|
+
}
|
|
35
40
|
const appToken = getGatewayAppApiToken(env);
|
|
36
41
|
if (!appToken) {
|
|
37
42
|
throw new Error("GATEWAY_APP_API_TOKEN is required. Run `npx everyapp app deploy` to provision one.");
|
|
@@ -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,YAAY,CAAC;AAQ7C;;;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,
|
|
1
|
+
{"version":3,"file":"authenticateRequest.d.ts","sourceRoot":"","sources":["../../../src/tanstack/server/authenticateRequest.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C;;;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,CAoDrC;AAyCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK3E"}
|
|
@@ -27,10 +27,15 @@ export async function authenticateRequest(authConfig, providedRequest) {
|
|
|
27
27
|
return session;
|
|
28
28
|
}
|
|
29
29
|
catch (error) {
|
|
30
|
+
const isProd = import.meta.env.PROD === true;
|
|
30
31
|
console.error(JSON.stringify({
|
|
31
32
|
message: "Error verifying session token",
|
|
32
33
|
error: error instanceof Error ? error.message : String(error),
|
|
33
|
-
stack:
|
|
34
|
+
stack: isProd === true
|
|
35
|
+
? undefined
|
|
36
|
+
: error instanceof Error
|
|
37
|
+
? error.stack
|
|
38
|
+
: undefined,
|
|
34
39
|
errorType: error instanceof Error ? error.constructor.name : "Unknown",
|
|
35
40
|
issuer: authConfig.issuer,
|
|
36
41
|
audience: authConfig.audience,
|
package/package.json
CHANGED
|
@@ -56,6 +56,53 @@ describe("gateway server helpers", () => {
|
|
|
56
56
|
);
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
+
it("throws when absolute URL points to non-gateway origin", async () => {
|
|
60
|
+
const fetchMock = vi
|
|
61
|
+
.spyOn(globalThis, "fetch")
|
|
62
|
+
.mockResolvedValue(new Response("ok", { status: 200 }));
|
|
63
|
+
|
|
64
|
+
const env: TestEnv = {
|
|
65
|
+
GATEWAY_URL: "https://gateway.example.com",
|
|
66
|
+
GATEWAY_APP_API_TOKEN: "eat_test_token",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
await expect(
|
|
70
|
+
fetchGateway({
|
|
71
|
+
env,
|
|
72
|
+
url: "https://evil.example.com/api/ai/openai/v1/responses",
|
|
73
|
+
init: { method: "POST" },
|
|
74
|
+
}),
|
|
75
|
+
).rejects.toThrow(
|
|
76
|
+
"Refusing to send gateway token to non-gateway origin: https://evil.example.com",
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("allows absolute URL when it matches gateway origin", async () => {
|
|
83
|
+
const fetchMock = vi
|
|
84
|
+
.spyOn(globalThis, "fetch")
|
|
85
|
+
.mockResolvedValue(new Response("ok", { status: 200 }));
|
|
86
|
+
|
|
87
|
+
const env: TestEnv = {
|
|
88
|
+
GATEWAY_URL: "https://gateway.example.com",
|
|
89
|
+
GATEWAY_APP_API_TOKEN: "eat_test_token",
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
await fetchGateway({
|
|
93
|
+
env,
|
|
94
|
+
url: "https://gateway.example.com/api/ai/openai/v1/responses",
|
|
95
|
+
init: { method: "POST" },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
99
|
+
const [requestArg] = fetchMock.mock.calls[0];
|
|
100
|
+
const request = requestArg as Request;
|
|
101
|
+
expect(request.url).toBe(
|
|
102
|
+
"https://gateway.example.com/api/ai/openai/v1/responses",
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
59
106
|
it("fetches via service binding when available in production", async () => {
|
|
60
107
|
// Service binding is only used when import.meta.env.PROD is true
|
|
61
108
|
const originalProd = import.meta.env.PROD;
|
|
@@ -61,6 +61,14 @@ export async function fetchGateway({
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
function applyAppTokenAuth(request: Request, env: GatewayEnv): Request {
|
|
64
|
+
const gatewayOrigin = new URL(getGatewayUrl(env)).origin;
|
|
65
|
+
const requestOrigin = new URL(request.url).origin;
|
|
66
|
+
if (requestOrigin !== gatewayOrigin) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Refusing to send gateway token to non-gateway origin: ${requestOrigin}`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
const appToken = getGatewayAppApiToken(env);
|
|
65
73
|
if (!appToken) {
|
|
66
74
|
throw new Error(
|
|
@@ -444,4 +444,39 @@ describe("authenticateRequest", () => {
|
|
|
444
444
|
expect(result).toBeNull();
|
|
445
445
|
});
|
|
446
446
|
});
|
|
447
|
+
|
|
448
|
+
describe("error logging", () => {
|
|
449
|
+
it("omits stack details in production logs", async () => {
|
|
450
|
+
const originalProd = import.meta.env.PROD;
|
|
451
|
+
import.meta.env.PROD = true;
|
|
452
|
+
|
|
453
|
+
const consoleErrorSpy = vi
|
|
454
|
+
.spyOn(console, "error")
|
|
455
|
+
.mockImplementation(() => undefined);
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
const request = createRequest("Bearer malformed.token");
|
|
459
|
+
const result = await authenticateRequest(authConfig, request);
|
|
460
|
+
|
|
461
|
+
expect(result).toBeNull();
|
|
462
|
+
expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
|
|
463
|
+
|
|
464
|
+
const [payload] = consoleErrorSpy.mock.calls[0];
|
|
465
|
+
expect(typeof payload).toBe("string");
|
|
466
|
+
|
|
467
|
+
const parsed = JSON.parse(payload as string) as {
|
|
468
|
+
stack?: string;
|
|
469
|
+
message: string;
|
|
470
|
+
issuer: string;
|
|
471
|
+
audience: string;
|
|
472
|
+
};
|
|
473
|
+
expect(parsed.message).toBe("Error verifying session token");
|
|
474
|
+
expect(parsed.issuer).toBe(authConfig.issuer);
|
|
475
|
+
expect(parsed.audience).toBe(authConfig.audience);
|
|
476
|
+
expect(parsed.stack).toBeUndefined();
|
|
477
|
+
} finally {
|
|
478
|
+
import.meta.env.PROD = originalProd;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
});
|
|
447
482
|
});
|
|
@@ -70,11 +70,17 @@ export async function authenticateRequest(
|
|
|
70
70
|
const session = await verifySessionToken(token, authConfig);
|
|
71
71
|
return session;
|
|
72
72
|
} catch (error) {
|
|
73
|
+
const isProd = import.meta.env.PROD === true;
|
|
73
74
|
console.error(
|
|
74
75
|
JSON.stringify({
|
|
75
76
|
message: "Error verifying session token",
|
|
76
77
|
error: error instanceof Error ? error.message : String(error),
|
|
77
|
-
stack:
|
|
78
|
+
stack:
|
|
79
|
+
isProd === true
|
|
80
|
+
? undefined
|
|
81
|
+
: error instanceof Error
|
|
82
|
+
? error.stack
|
|
83
|
+
: undefined,
|
|
78
84
|
errorType: error instanceof Error ? error.constructor.name : "Unknown",
|
|
79
85
|
issuer: authConfig.issuer,
|
|
80
86
|
audience: authConfig.audience,
|