@growth-labs/auth 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/routes/callback.d.ts.map +1 -1
- package/dist/routes/callback.js +9 -2
- package/dist/routes/callback.js.map +1 -1
- package/dist/routes/logout.d.ts.map +1 -1
- package/dist/routes/logout.js +4 -2
- package/dist/routes/logout.js.map +1 -1
- package/dist/utils/wait-until.d.ts +13 -0
- package/dist/utils/wait-until.d.ts.map +1 -0
- package/dist/utils/wait-until.js +12 -0
- package/dist/utils/wait-until.js.map +1 -0
- package/package.json +2 -2
- package/src/index.ts +5 -1
- package/src/routes/callback.ts +13 -2
- package/src/routes/logout.ts +7 -2
- package/src/utils/wait-until.ts +48 -0
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,UAAU,gBAAgB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE;QACN,oBAAoB,EAAE,CAAC,MAAM,EAAE;YAC9B,aAAa,EAAE,CAAC,IAAI,EAAE;gBAAE,UAAU,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAAA;aAAE,KAAK,IAAI,CAAA;YAC5E,WAAW,EAAE,CAAC,IAAI,EAAE;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,UAAU,EAAE,MAAM,CAAC;gBAAC,SAAS,CAAC,EAAE,OAAO,CAAA;aAAE,KAAK,IAAI,CAAA;YACzF,YAAY,EAAE,CAAC,MAAM,EAAE;gBACtB,IAAI,CAAC,EAAE;oBAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;iBAAE,CAAA;aAC/D,KAAK,IAAI,CAAA;SACV,KAAK,IAAI,CAAA;KACV,CAAA;CACD;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,UAAU,gBAAgB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE;QACN,oBAAoB,EAAE,CAAC,MAAM,EAAE;YAC9B,aAAa,EAAE,CAAC,IAAI,EAAE;gBAAE,UAAU,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAAA;aAAE,KAAK,IAAI,CAAA;YAC5E,WAAW,EAAE,CAAC,IAAI,EAAE;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,UAAU,EAAE,MAAM,CAAC;gBAAC,SAAS,CAAC,EAAE,OAAO,CAAA;aAAE,KAAK,IAAI,CAAA;YACzF,YAAY,EAAE,CAAC,MAAM,EAAE;gBACtB,IAAI,CAAC,EAAE;oBAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;iBAAE,CAAA;aAC/D,KAAK,IAAI,CAAA;SACV,KAAK,IAAI,CAAA;KACV,CAAA;CACD;AAYD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,CAuBjE;AAWD,MAAM,CAAC,OAAO,UAAU,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,gBAAgB,CAyGvE"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { _setConfig } from './config-store.js';
|
|
2
2
|
import { authOptionsSchema } from './options.js';
|
|
3
|
-
|
|
3
|
+
function isSourceEntrypoint() {
|
|
4
|
+
return typeof import.meta.url === 'string' && import.meta.url.endsWith('.ts');
|
|
5
|
+
}
|
|
6
|
+
const ENTRYPOINT_EXTENSION = isSourceEntrypoint() ? '.ts' : '.js';
|
|
4
7
|
function resolveEntrypoint(path) {
|
|
5
8
|
return decodeURIComponent(new URL(`${path}${ENTRYPOINT_EXTENSION}`, import.meta.url).pathname);
|
|
6
9
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAgBhD,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/routes/callback.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/routes/callback.ts"],"names":[],"mappings":"AAcA,UAAU,eAAe;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAKhC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;CAC/C;AAOD,wBAAsB,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqFrE"}
|
package/dist/routes/callback.js
CHANGED
|
@@ -5,6 +5,7 @@ import { clearAuthFlowCookies, getCookie, setIdentityCookie, setTokenCookies, }
|
|
|
5
5
|
import { createIdentityCookiePayload, signIdentityCookie } from '../utils/identity-cookie.js';
|
|
6
6
|
import { exchangeCode } from '../utils/openauth.js';
|
|
7
7
|
import { verifyState } from '../utils/state.js';
|
|
8
|
+
import { resolveWaitUntil } from '../utils/wait-until.js';
|
|
8
9
|
function getIdentitySecret() {
|
|
9
10
|
const secret = getRuntimeEnv().GL_IDENTITY_SECRET;
|
|
10
11
|
return typeof secret === 'string' && secret.length > 0 ? secret : null;
|
|
@@ -53,7 +54,13 @@ export async function GET(context) {
|
|
|
53
54
|
// Keep login working if the optional analytics identity secret is misconfigured.
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
|
-
// Emit analytics event (non-blocking)
|
|
57
|
+
// Emit analytics event (non-blocking). Register the promise via the
|
|
58
|
+
// Cloudflare execution context's `waitUntil` so the dynamic import of
|
|
59
|
+
// `@growth-labs/analytics/utils` and the downstream WAE + D1 writes
|
|
60
|
+
// survive past the 302 response. Without this, the Cloudflare runtime
|
|
61
|
+
// terminates the orphaned promise before the conversion event lands —
|
|
62
|
+
// the root cause of the missing `login_completed` / `signup_completed`
|
|
63
|
+
// rows in `gl_conversion_events` after the Fronts cutover.
|
|
57
64
|
if (analyticsAvailable(context)) {
|
|
58
65
|
const eventName = tokenResponse.isNewUser ? 'signup_completed' : 'login_completed';
|
|
59
66
|
const promise = emitAuthEvent(context, eventName, {
|
|
@@ -62,7 +69,7 @@ export async function GET(context) {
|
|
|
62
69
|
auth_path: authPath,
|
|
63
70
|
identity_user_id: tokenResponse.claims.sub,
|
|
64
71
|
});
|
|
65
|
-
context
|
|
72
|
+
resolveWaitUntil(context)(promise);
|
|
66
73
|
}
|
|
67
74
|
return mutableResponse;
|
|
68
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callback.js","sourceRoot":"","sources":["../../src/routes/callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACzE,OAAO,EACN,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,eAAe,GACf,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAC7F,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"callback.js","sourceRoot":"","sources":["../../src/routes/callback.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"AAYA,UAAU,aAAa;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,GAAG,CAAA;IAIR,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyCnE"}
|
package/dist/routes/logout.js
CHANGED
|
@@ -3,17 +3,19 @@ import { analyticsAvailable, emitAuthEvent } from '../utils/analytics.js';
|
|
|
3
3
|
import { resolveClientSecret } from '../utils/client-secret.js';
|
|
4
4
|
import { clearAuthFlowCookies, clearIdentityCookie, clearTokenCookies, getCookie, } from '../utils/cookies.js';
|
|
5
5
|
import { revokeToken } from '../utils/openauth.js';
|
|
6
|
+
import { resolveWaitUntil } from '../utils/wait-until.js';
|
|
6
7
|
export async function GET(context) {
|
|
7
8
|
const options = getConfig();
|
|
8
9
|
const refreshToken = getCookie(context.request, `${options.cookiePrefix}_rt`);
|
|
9
10
|
const clientId = options.clientId || context.url.hostname;
|
|
11
|
+
const waitUntil = resolveWaitUntil(context);
|
|
10
12
|
// Revoke at issuer (non-blocking)
|
|
11
13
|
if (refreshToken) {
|
|
12
14
|
const clientSecret = resolveClientSecret(options.clientSecret);
|
|
13
15
|
const promise = clientSecret
|
|
14
16
|
? revokeToken(refreshToken, clientId, clientSecret)
|
|
15
17
|
: revokeToken(refreshToken, clientId);
|
|
16
|
-
|
|
18
|
+
waitUntil(promise);
|
|
17
19
|
}
|
|
18
20
|
// Emit auth_logout (non-blocking) when the consumer has @growth-labs/analytics
|
|
19
21
|
// wired. Without analytics installed this is a no-op (analyticsAvailable
|
|
@@ -22,7 +24,7 @@ export async function GET(context) {
|
|
|
22
24
|
const promise = emitAuthEvent(context, 'auth_logout', {
|
|
23
25
|
revoked: refreshToken ? 'true' : 'false',
|
|
24
26
|
});
|
|
25
|
-
|
|
27
|
+
waitUntil(promise);
|
|
26
28
|
}
|
|
27
29
|
// Build redirect response
|
|
28
30
|
const redirectUrl = new URL(options.logoutRedirect, context.url.origin).toString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,GACT,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,GACT,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAYzD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAsB;IAC/C,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;IAC3B,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;IACzD,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAE3C,kCAAkC;IAClC,IAAI,YAAY,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;QAC9D,MAAM,OAAO,GAAG,YAAY;YAC3B,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC;YACnD,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;QACtC,SAAS,CAAC,OAAO,CAAC,CAAA;IACnB,CAAC;IAED,+EAA+E;IAC/E,yEAAyE;IACzE,iEAAiE;IACjE,IAAI,kBAAkB,CAAC,OAA+C,CAAC,EAAE,CAAC;QACzE,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE;YACrD,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;SACxC,CAAC,CAAA;QACF,SAAS,CAAC,OAAO,CAAC,CAAA;IACnB,CAAC;IAED,0BAA0B;IAC1B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;IAClF,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IAEpD,oCAAoC;IACpC,MAAM,eAAe,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QACnD,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,OAAO,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;KACtC,CAAC,CAAA;IAEF,iBAAiB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAC3C,mBAAmB,CAAC,eAAe,CAAC,CAAA;IACpC,oBAAoB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAE9C,OAAO,eAAe,CAAA;AACvB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface CfExecutionContext {
|
|
2
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
3
|
+
}
|
|
4
|
+
interface ContextWithWaitUntil {
|
|
5
|
+
locals?: {
|
|
6
|
+
cfContext?: CfExecutionContext;
|
|
7
|
+
};
|
|
8
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
9
|
+
}
|
|
10
|
+
export type WaitUntilFn = (promise: Promise<unknown>) => void;
|
|
11
|
+
export declare function resolveWaitUntil(context: ContextWithWaitUntil): WaitUntilFn;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=wait-until.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-until.d.ts","sourceRoot":"","sources":["../../src/utils/wait-until.ts"],"names":[],"mappings":"AAuBA,UAAU,kBAAkB;IAC3B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;CAC/C;AAED,UAAU,oBAAoB;IAC7B,MAAM,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,kBAAkB,CAAA;KAC9B,CAAA;IACD,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;CAC/C;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;AAI7D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,WAAW,CAS3E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const NO_OP_WAIT_UNTIL = () => undefined;
|
|
2
|
+
export function resolveWaitUntil(context) {
|
|
3
|
+
const cfWaitUntil = context.locals?.cfContext?.waitUntil;
|
|
4
|
+
if (typeof cfWaitUntil === 'function') {
|
|
5
|
+
return cfWaitUntil.bind(context.locals.cfContext);
|
|
6
|
+
}
|
|
7
|
+
if (typeof context.waitUntil === 'function') {
|
|
8
|
+
return context.waitUntil;
|
|
9
|
+
}
|
|
10
|
+
return NO_OP_WAIT_UNTIL;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=wait-until.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-until.js","sourceRoot":"","sources":["../../src/utils/wait-until.ts"],"names":[],"mappings":"AAoCA,MAAM,gBAAgB,GAAgB,GAAG,EAAE,CAAC,SAAS,CAAA;AAErD,MAAM,UAAU,gBAAgB,CAAC,OAA6B;IAC7D,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,CAAA;IACxD,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;QACvC,OAAO,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,MAAO,CAAC,SAAS,CAAC,CAAA;IACnD,CAAC;IACD,IAAI,OAAO,OAAO,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;QAC7C,OAAO,OAAO,CAAC,SAAS,CAAA;IACzB,CAAC;IACD,OAAO,gBAAgB,CAAA;AACxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@growth-labs/auth",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"typescript": "^5.8.0",
|
|
63
63
|
"vite": "^7.3.2",
|
|
64
64
|
"vitest": "^3.0.0",
|
|
65
|
-
"@growth-labs/analytics": "0.
|
|
65
|
+
"@growth-labs/analytics": "0.5.0"
|
|
66
66
|
},
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build": "tsc",
|
package/src/index.ts
CHANGED
|
@@ -16,7 +16,11 @@ interface AstroIntegration {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
function isSourceEntrypoint(): boolean {
|
|
20
|
+
return typeof import.meta.url === 'string' && import.meta.url.endsWith('.ts')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ENTRYPOINT_EXTENSION = isSourceEntrypoint() ? '.ts' : '.js'
|
|
20
24
|
|
|
21
25
|
function resolveEntrypoint(path: string): string {
|
|
22
26
|
return decodeURIComponent(new URL(`${path}${ENTRYPOINT_EXTENSION}`, import.meta.url).pathname)
|
package/src/routes/callback.ts
CHANGED
|
@@ -10,11 +10,16 @@ import {
|
|
|
10
10
|
import { createIdentityCookiePayload, signIdentityCookie } from '../utils/identity-cookie.js'
|
|
11
11
|
import { exchangeCode } from '../utils/openauth.js'
|
|
12
12
|
import { verifyState } from '../utils/state.js'
|
|
13
|
+
import { resolveWaitUntil } from '../utils/wait-until.js'
|
|
13
14
|
|
|
14
15
|
interface CallbackContext {
|
|
15
16
|
request: Request
|
|
16
17
|
url: URL
|
|
17
18
|
locals?: Record<string, unknown>
|
|
19
|
+
// Some callers may surface `waitUntil` at the top level (synthetic
|
|
20
|
+
// contexts in tests; future runtimes). The production wiring on Astro v6
|
|
21
|
+
// + @astrojs/cloudflare@13 instead exposes it at
|
|
22
|
+
// `locals.cfContext.waitUntil`, which `resolveWaitUntil` handles below.
|
|
18
23
|
waitUntil?: (promise: Promise<unknown>) => void
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -89,7 +94,13 @@ export async function GET(context: CallbackContext): Promise<Response> {
|
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
|
|
92
|
-
// Emit analytics event (non-blocking)
|
|
97
|
+
// Emit analytics event (non-blocking). Register the promise via the
|
|
98
|
+
// Cloudflare execution context's `waitUntil` so the dynamic import of
|
|
99
|
+
// `@growth-labs/analytics/utils` and the downstream WAE + D1 writes
|
|
100
|
+
// survive past the 302 response. Without this, the Cloudflare runtime
|
|
101
|
+
// terminates the orphaned promise before the conversion event lands —
|
|
102
|
+
// the root cause of the missing `login_completed` / `signup_completed`
|
|
103
|
+
// rows in `gl_conversion_events` after the Fronts cutover.
|
|
93
104
|
if (analyticsAvailable(context)) {
|
|
94
105
|
const eventName = tokenResponse.isNewUser ? 'signup_completed' : 'login_completed'
|
|
95
106
|
const promise = emitAuthEvent(context, eventName, {
|
|
@@ -98,7 +109,7 @@ export async function GET(context: CallbackContext): Promise<Response> {
|
|
|
98
109
|
auth_path: authPath,
|
|
99
110
|
identity_user_id: tokenResponse.claims.sub,
|
|
100
111
|
})
|
|
101
|
-
context
|
|
112
|
+
resolveWaitUntil(context)(promise)
|
|
102
113
|
}
|
|
103
114
|
|
|
104
115
|
return mutableResponse
|
package/src/routes/logout.ts
CHANGED
|
@@ -8,10 +8,14 @@ import {
|
|
|
8
8
|
getCookie,
|
|
9
9
|
} from '../utils/cookies.js'
|
|
10
10
|
import { revokeToken } from '../utils/openauth.js'
|
|
11
|
+
import { resolveWaitUntil } from '../utils/wait-until.js'
|
|
11
12
|
|
|
12
13
|
interface LogoutContext {
|
|
13
14
|
request: Request
|
|
14
15
|
url: URL
|
|
16
|
+
// See callback.ts: Astro v6 + @astrojs/cloudflare@13 places the Worker
|
|
17
|
+
// execution context's `waitUntil` at `locals.cfContext.waitUntil`, not
|
|
18
|
+
// at the top level. `resolveWaitUntil` handles both shapes.
|
|
15
19
|
waitUntil?: (promise: Promise<unknown>) => void
|
|
16
20
|
locals?: Record<string, unknown>
|
|
17
21
|
}
|
|
@@ -20,6 +24,7 @@ export async function GET(context: LogoutContext): Promise<Response> {
|
|
|
20
24
|
const options = getConfig()
|
|
21
25
|
const refreshToken = getCookie(context.request, `${options.cookiePrefix}_rt`)
|
|
22
26
|
const clientId = options.clientId || context.url.hostname
|
|
27
|
+
const waitUntil = resolveWaitUntil(context)
|
|
23
28
|
|
|
24
29
|
// Revoke at issuer (non-blocking)
|
|
25
30
|
if (refreshToken) {
|
|
@@ -27,7 +32,7 @@ export async function GET(context: LogoutContext): Promise<Response> {
|
|
|
27
32
|
const promise = clientSecret
|
|
28
33
|
? revokeToken(refreshToken, clientId, clientSecret)
|
|
29
34
|
: revokeToken(refreshToken, clientId)
|
|
30
|
-
|
|
35
|
+
waitUntil(promise)
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
// Emit auth_logout (non-blocking) when the consumer has @growth-labs/analytics
|
|
@@ -37,7 +42,7 @@ export async function GET(context: LogoutContext): Promise<Response> {
|
|
|
37
42
|
const promise = emitAuthEvent(context, 'auth_logout', {
|
|
38
43
|
revoked: refreshToken ? 'true' : 'false',
|
|
39
44
|
})
|
|
40
|
-
|
|
45
|
+
waitUntil(promise)
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
// Build redirect response
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Resolve the Cloudflare Worker execution context's `waitUntil` from a
|
|
2
|
+
// request context.
|
|
3
|
+
//
|
|
4
|
+
// Astro v6 + @astrojs/cloudflare@13 places the Worker execution context on
|
|
5
|
+
// `context.locals.cfContext`, NOT directly on the APIContext — so the
|
|
6
|
+
// previously-used `context.waitUntil?.(promise)` was a silent no-op for
|
|
7
|
+
// every injected auth route, orphaning the analytics-emit promise so the
|
|
8
|
+
// dynamic import of `@growth-labs/analytics/utils` (and the WAE + D1 writes
|
|
9
|
+
// it triggers) was terminated before completing. Manifested in production
|
|
10
|
+
// as `login_completed` / `signup_completed` / `auth_logout` rows never
|
|
11
|
+
// landing in `gl_conversion_events`.
|
|
12
|
+
//
|
|
13
|
+
// The analytics package's own `runtime.ts` already uses this pattern;
|
|
14
|
+
// keeping the resolution shape identical guarantees both packages register
|
|
15
|
+
// promises against the same execution context.
|
|
16
|
+
//
|
|
17
|
+
// Fallback order, mirroring the runtime expectations of consumers:
|
|
18
|
+
// 1. `context.locals.cfContext.waitUntil` — Astro v6 + cloudflare adapter.
|
|
19
|
+
// 2. `context.waitUntil` — direct callers passing a synthetic context
|
|
20
|
+
// (e.g., tests, or future runtimes that surface `waitUntil` at the top
|
|
21
|
+
// level).
|
|
22
|
+
// 3. A no-op — so emit calls degrade silently when no execution context
|
|
23
|
+
// is reachable (dev environments without a Worker, unit tests).
|
|
24
|
+
interface CfExecutionContext {
|
|
25
|
+
waitUntil?: (promise: Promise<unknown>) => void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ContextWithWaitUntil {
|
|
29
|
+
locals?: {
|
|
30
|
+
cfContext?: CfExecutionContext
|
|
31
|
+
}
|
|
32
|
+
waitUntil?: (promise: Promise<unknown>) => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type WaitUntilFn = (promise: Promise<unknown>) => void
|
|
36
|
+
|
|
37
|
+
const NO_OP_WAIT_UNTIL: WaitUntilFn = () => undefined
|
|
38
|
+
|
|
39
|
+
export function resolveWaitUntil(context: ContextWithWaitUntil): WaitUntilFn {
|
|
40
|
+
const cfWaitUntil = context.locals?.cfContext?.waitUntil
|
|
41
|
+
if (typeof cfWaitUntil === 'function') {
|
|
42
|
+
return cfWaitUntil.bind(context.locals!.cfContext)
|
|
43
|
+
}
|
|
44
|
+
if (typeof context.waitUntil === 'function') {
|
|
45
|
+
return context.waitUntil
|
|
46
|
+
}
|
|
47
|
+
return NO_OP_WAIT_UNTIL
|
|
48
|
+
}
|