@teleporthq/teleport-plugin-next-workflows 0.43.50 → 0.43.53
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/__tests__/session-cookie-resolver.test.ts +412 -0
- package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
- package/dist/cjs/account-delete-route-generator.js +3 -3
- package/dist/cjs/account-delete-route-generator.js.map +1 -1
- package/dist/cjs/auth-generator.d.ts.map +1 -1
- package/dist/cjs/auth-generator.js +14 -8
- package/dist/cjs/auth-generator.js.map +1 -1
- package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
- package/dist/cjs/data-api-route-generator.js +8 -2
- package/dist/cjs/data-api-route-generator.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +5 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/session-cookie-resolver.d.ts +84 -0
- package/dist/cjs/session-cookie-resolver.d.ts.map +1 -0
- package/dist/cjs/session-cookie-resolver.js +282 -0
- package/dist/cjs/session-cookie-resolver.js.map +1 -0
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/workflow-auth-generator.d.ts +6 -0
- package/dist/cjs/workflow-auth-generator.d.ts.map +1 -1
- package/dist/cjs/workflow-auth-generator.js +9 -16
- package/dist/cjs/workflow-auth-generator.js.map +1 -1
- package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
- package/dist/esm/account-delete-route-generator.js +3 -3
- package/dist/esm/account-delete-route-generator.js.map +1 -1
- package/dist/esm/auth-generator.d.ts.map +1 -1
- package/dist/esm/auth-generator.js +14 -8
- package/dist/esm/auth-generator.js.map +1 -1
- package/dist/esm/data-api-route-generator.d.ts.map +1 -1
- package/dist/esm/data-api-route-generator.js +8 -2
- package/dist/esm/data-api-route-generator.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/session-cookie-resolver.d.ts +84 -0
- package/dist/esm/session-cookie-resolver.d.ts.map +1 -0
- package/dist/esm/session-cookie-resolver.js +277 -0
- package/dist/esm/session-cookie-resolver.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/workflow-auth-generator.d.ts +6 -0
- package/dist/esm/workflow-auth-generator.d.ts.map +1 -1
- package/dist/esm/workflow-auth-generator.js +9 -16
- package/dist/esm/workflow-auth-generator.js.map +1 -1
- package/package.json +4 -4
- package/src/account-delete-route-generator.ts +3 -3
- package/src/auth-generator.ts +14 -8
- package/src/data-api-route-generator.ts +7 -2
- package/src/index.ts +5 -0
- package/src/session-cookie-resolver.ts +280 -0
- package/src/workflow-auth-generator.ts +9 -16
package/dist/cjs/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { collectSecrets } from './secret-collector';
|
|
|
6
6
|
export { generateClientRuntimeCode, generateServerRuntimeCode, generateSharedRuntimeUtilsCode, } from './executor-generator';
|
|
7
7
|
export { generateServerSegmentAPIRoute, generateStreamingServerSegmentAPIRoute, generateCronAPIRoute, generateWebhookWorkflowAPIRoute, getAPIRouteFileName, getCronRouteFileName, getWebhookRouteFileName, getWebhookRoutePath, hasStreamingAINode, } from './api-route-generator';
|
|
8
8
|
export { generateTriggerCode } from './trigger-generator';
|
|
9
|
+
export { SESSION_TOKEN_RESOLVER_FN, generateSessionTokenResolverCode, generateCommonJsSessionTokenResolverCode, } from './session-cookie-resolver';
|
|
9
10
|
export { projectUsesRealtime, REALTIME_NODE_TYPES, REALTIME_TRIGGER_TYPES } from './graph-utils';
|
|
10
11
|
export * from './realtime-generator';
|
|
11
12
|
export { generateInvoiceFiles, resolveInvoiceDataSource } from './invoice';
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,6BAA6B,EAC7B,sCAAsC,EACtC,oBAAoB,EACpB,+BAA+B,EAC/B,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAChG,cAAc,sBAAsB,CAAA;AACpC,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAA;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EACL,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,6BAA6B,CAAA;AACpC,cAAc,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,6BAA6B,EAC7B,sCAAsC,EACtC,oBAAoB,EACpB,+BAA+B,EAC/B,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,wCAAwC,GACzC,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAChG,cAAc,sBAAsB,CAAA;AACpC,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAA;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EACL,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,6BAA6B,CAAA;AACpC,cAAc,SAAS,CAAA"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.generateRuntimeStorageUploadRoute = exports.needsRuntimeStorageRoute = exports.generateWebhookFiles = exports.resolveInvoiceDataSource = exports.generateInvoiceFiles = exports.REALTIME_TRIGGER_TYPES = exports.REALTIME_NODE_TYPES = exports.projectUsesRealtime = exports.generateTriggerCode = exports.hasStreamingAINode = exports.getWebhookRoutePath = exports.getWebhookRouteFileName = exports.getCronRouteFileName = exports.getAPIRouteFileName = exports.generateWebhookWorkflowAPIRoute = exports.generateCronAPIRoute = exports.generateStreamingServerSegmentAPIRoute = exports.generateServerSegmentAPIRoute = exports.generateSharedRuntimeUtilsCode = exports.generateServerRuntimeCode = exports.generateClientRuntimeCode = exports.collectSecrets = exports.getClientSegments = exports.getServerSegments = exports.splitIntoSegments = exports.nodeRegistry = exports.NextWorkflowProjectPlugin = exports.createNextWorkflowPlugin = void 0;
|
|
17
|
+
exports.generateRuntimeStorageUploadRoute = exports.needsRuntimeStorageRoute = exports.generateWebhookFiles = exports.resolveInvoiceDataSource = exports.generateInvoiceFiles = exports.REALTIME_TRIGGER_TYPES = exports.REALTIME_NODE_TYPES = exports.projectUsesRealtime = exports.generateCommonJsSessionTokenResolverCode = exports.generateSessionTokenResolverCode = exports.SESSION_TOKEN_RESOLVER_FN = exports.generateTriggerCode = exports.hasStreamingAINode = exports.getWebhookRoutePath = exports.getWebhookRouteFileName = exports.getCronRouteFileName = exports.getAPIRouteFileName = exports.generateWebhookWorkflowAPIRoute = exports.generateCronAPIRoute = exports.generateStreamingServerSegmentAPIRoute = exports.generateServerSegmentAPIRoute = exports.generateSharedRuntimeUtilsCode = exports.generateServerRuntimeCode = exports.generateClientRuntimeCode = exports.collectSecrets = exports.getClientSegments = exports.getServerSegments = exports.splitIntoSegments = exports.nodeRegistry = exports.NextWorkflowProjectPlugin = exports.createNextWorkflowPlugin = void 0;
|
|
18
18
|
var workflow_component_plugin_1 = require("./workflow-component-plugin");
|
|
19
19
|
Object.defineProperty(exports, "createNextWorkflowPlugin", { enumerable: true, get: function () { return workflow_component_plugin_1.createNextWorkflowPlugin; } });
|
|
20
20
|
var workflow_project_plugin_1 = require("./workflow-project-plugin");
|
|
@@ -43,6 +43,10 @@ Object.defineProperty(exports, "getWebhookRoutePath", { enumerable: true, get: f
|
|
|
43
43
|
Object.defineProperty(exports, "hasStreamingAINode", { enumerable: true, get: function () { return api_route_generator_1.hasStreamingAINode; } });
|
|
44
44
|
var trigger_generator_1 = require("./trigger-generator");
|
|
45
45
|
Object.defineProperty(exports, "generateTriggerCode", { enumerable: true, get: function () { return trigger_generator_1.generateTriggerCode; } });
|
|
46
|
+
var session_cookie_resolver_1 = require("./session-cookie-resolver");
|
|
47
|
+
Object.defineProperty(exports, "SESSION_TOKEN_RESOLVER_FN", { enumerable: true, get: function () { return session_cookie_resolver_1.SESSION_TOKEN_RESOLVER_FN; } });
|
|
48
|
+
Object.defineProperty(exports, "generateSessionTokenResolverCode", { enumerable: true, get: function () { return session_cookie_resolver_1.generateSessionTokenResolverCode; } });
|
|
49
|
+
Object.defineProperty(exports, "generateCommonJsSessionTokenResolverCode", { enumerable: true, get: function () { return session_cookie_resolver_1.generateCommonJsSessionTokenResolverCode; } });
|
|
46
50
|
var graph_utils_1 = require("./graph-utils");
|
|
47
51
|
Object.defineProperty(exports, "projectUsesRealtime", { enumerable: true, get: function () { return graph_utils_1.projectUsesRealtime; } });
|
|
48
52
|
Object.defineProperty(exports, "REALTIME_NODE_TYPES", { enumerable: true, get: function () { return graph_utils_1.REALTIME_NODE_TYPES; } });
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yEAAsE;AAA7D,qIAAA,wBAAwB,OAAA;AACjC,qEAAqE;AAA5D,oIAAA,yBAAyB,OAAA;AAClC,iCAAsC;AAA7B,qGAAA,YAAY,OAAA;AACrB,uDAA4F;AAAnF,qHAAA,iBAAiB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAChE,uDAAmD;AAA1C,kHAAA,cAAc,OAAA;AACvB,2DAI6B;AAH3B,+HAAA,yBAAyB,OAAA;AACzB,+HAAA,yBAAyB,OAAA;AACzB,oIAAA,8BAA8B,OAAA;AAEhC,6DAU8B;AAT5B,oIAAA,6BAA6B,OAAA;AAC7B,6IAAA,sCAAsC,OAAA;AACtC,2HAAA,oBAAoB,OAAA;AACpB,sIAAA,+BAA+B,OAAA;AAC/B,0HAAA,mBAAmB,OAAA;AACnB,2HAAA,oBAAoB,OAAA;AACpB,8HAAA,uBAAuB,OAAA;AACvB,0HAAA,mBAAmB,OAAA;AACnB,yHAAA,kBAAkB,OAAA;AAEpB,yDAAyD;AAAhD,wHAAA,mBAAmB,OAAA;AAC5B,6CAAgG;AAAvF,kHAAA,mBAAmB,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAAE,qHAAA,sBAAsB,OAAA;AACzE,uDAAoC;AACpC,qCAA0E;AAAjE,+GAAA,oBAAoB,OAAA;AAAE,mHAAA,wBAAwB,OAAA;AACvD,yDAA0D;AAAjD,yHAAA,oBAAoB,OAAA;AAC7B,yEAGoC;AAFlC,qIAAA,wBAAwB,OAAA;AACxB,8IAAA,iCAAiC,OAAA;AAEnC,0CAAuB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yEAAsE;AAA7D,qIAAA,wBAAwB,OAAA;AACjC,qEAAqE;AAA5D,oIAAA,yBAAyB,OAAA;AAClC,iCAAsC;AAA7B,qGAAA,YAAY,OAAA;AACrB,uDAA4F;AAAnF,qHAAA,iBAAiB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAChE,uDAAmD;AAA1C,kHAAA,cAAc,OAAA;AACvB,2DAI6B;AAH3B,+HAAA,yBAAyB,OAAA;AACzB,+HAAA,yBAAyB,OAAA;AACzB,oIAAA,8BAA8B,OAAA;AAEhC,6DAU8B;AAT5B,oIAAA,6BAA6B,OAAA;AAC7B,6IAAA,sCAAsC,OAAA;AACtC,2HAAA,oBAAoB,OAAA;AACpB,sIAAA,+BAA+B,OAAA;AAC/B,0HAAA,mBAAmB,OAAA;AACnB,2HAAA,oBAAoB,OAAA;AACpB,8HAAA,uBAAuB,OAAA;AACvB,0HAAA,mBAAmB,OAAA;AACnB,yHAAA,kBAAkB,OAAA;AAEpB,yDAAyD;AAAhD,wHAAA,mBAAmB,OAAA;AAC5B,qEAIkC;AAHhC,oIAAA,yBAAyB,OAAA;AACzB,2IAAA,gCAAgC,OAAA;AAChC,mJAAA,wCAAwC,OAAA;AAE1C,6CAAgG;AAAvF,kHAAA,mBAAmB,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAAE,qHAAA,sBAAsB,OAAA;AACzE,uDAAoC;AACpC,qCAA0E;AAAjE,+GAAA,oBAAoB,OAAA;AAAE,mHAAA,wBAAwB,OAAA;AACvD,yDAA0D;AAAjD,yHAAA,oBAAoB,OAAA;AAC7B,yEAGoC;AAFlC,qIAAA,wBAAwB,OAAA;AACxB,8IAAA,iCAAiC,OAAA;AAEnC,0CAAuB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolving the NextAuth session token in a generated route, WITHOUT asking
|
|
3
|
+
* `process.env.NEXTAUTH_URL` what the session cookie is called.
|
|
4
|
+
*
|
|
5
|
+
* ## ⛔ THE REPORTED DEFECT
|
|
6
|
+
*
|
|
7
|
+
* A published project showed "Failed to load dashboard data. Please refresh."
|
|
8
|
+
* on the home page, "Failed to load meeting data." on the list page and "could
|
|
9
|
+
* not fetch the templates" on a third — for a user who was signed in, on a page
|
|
10
|
+
* whose own `/api/auth/session` returned that user. The failing call was the
|
|
11
|
+
* page-load workflow's server segment, answering **401 `Unauthenticated`** from
|
|
12
|
+
* `guardWorkflowRequest`. Reloading sometimes fixed it; fanning 50 concurrent
|
|
13
|
+
* requests at the same route returned **33 × 401 and 17 × 200**, while 40
|
|
14
|
+
* concurrent `/api/auth/session` calls resolved the user 40/40.
|
|
15
|
+
*
|
|
16
|
+
* ## The mechanism
|
|
17
|
+
*
|
|
18
|
+
* next-auth v4's `getToken()` derives the cookie it reads from an env var:
|
|
19
|
+
*
|
|
20
|
+
* ```js
|
|
21
|
+
* secureCookie = process.env.NEXTAUTH_URL?.startsWith('https://') ?? !!process.env.VERCEL,
|
|
22
|
+
* cookieName = secureCookie ? '__Secure-next-auth.session-token' : 'next-auth.session-token',
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* A generated project ships `NEXTAUTH_URL=http://localhost:3000` — the build
|
|
26
|
+
* cannot know the domain it will be published to, so `pages/api/auth/[...nextauth].js`
|
|
27
|
+
* repairs `process.env.NEXTAUTH_URL` **from the incoming request** instead. That
|
|
28
|
+
* repair is process-local: it fixes the value for whichever serverless instance
|
|
29
|
+
* happened to serve an auth request, and for no other. Every other instance
|
|
30
|
+
* still holds `http://localhost:3000`, so `startsWith('https://')` is `false`
|
|
31
|
+
* (NOT `undefined` — the `??` fallback to `!!process.env.VERCEL` never runs),
|
|
32
|
+
* `getToken` looks for `next-auth.session-token`, the browser is holding
|
|
33
|
+
* `__Secure-next-auth.session-token`, nothing is found, and a signed-in user is
|
|
34
|
+
* reported as anonymous.
|
|
35
|
+
*
|
|
36
|
+
* Hence the coin-flip: it depends on whether the instance that served your
|
|
37
|
+
* request had previously served an auth request. Nothing about the session, the
|
|
38
|
+
* secret or the cookie is wrong.
|
|
39
|
+
*
|
|
40
|
+
* The same defect is why the generated middleware carries a `hasSessionCookie`
|
|
41
|
+
* fallback and a round trip to `/api/auth/session`, attributed there to an
|
|
42
|
+
* "Edge runtime quirk" — the Edge process holds that same localhost value.
|
|
43
|
+
*
|
|
44
|
+
* ## The rule
|
|
45
|
+
*
|
|
46
|
+
* ⭐ **A request must be authenticated from the REQUEST, never from an ambient
|
|
47
|
+
* env var that describes the deployment.** So this resolver reads which session
|
|
48
|
+
* cookie the caller actually sent, and tells `getToken` exactly that — falling
|
|
49
|
+
* back to the request's own protocol when the cookie header is unavailable.
|
|
50
|
+
*
|
|
51
|
+
* Emitted as plain ES5 text and inlined into each generated route: a route that
|
|
52
|
+
* carries its own copy cannot be broken by a missing sibling module or an
|
|
53
|
+
* untraced dependency, and every call site gets the identical implementation
|
|
54
|
+
* from this one definition.
|
|
55
|
+
*/
|
|
56
|
+
/** The `__tq`-prefixed globals the emitted snippet declares. */
|
|
57
|
+
export declare const SESSION_TOKEN_RESOLVER_FN = "__tqResolveSessionToken";
|
|
58
|
+
/**
|
|
59
|
+
* ES5 source for the shared session-token resolver, safe to inline into any
|
|
60
|
+
* generated CommonJS route or ESM middleware.
|
|
61
|
+
*
|
|
62
|
+
* Declares:
|
|
63
|
+
* - `__tqCookieNamesPresent(req)` — the set of cookie names on the request,
|
|
64
|
+
* parsed properly (a substring test would see `next-auth.session-token`
|
|
65
|
+
* inside `__Secure-next-auth.session-token` and pick the wrong one).
|
|
66
|
+
* - `__tqRequestIsSecure(req)` — https as the REQUEST reports it.
|
|
67
|
+
* - `__tqSessionTokenCandidates(req)` — `{cookieName, secureCookie}` pairs to try.
|
|
68
|
+
* - `__tqResolveSessionToken(getToken, req, secret)` — the token, or null.
|
|
69
|
+
*
|
|
70
|
+
* `getToken` is passed IN rather than required here, so the same body serves a
|
|
71
|
+
* CommonJS route (lazy `require('next-auth/jwt')`) and the Edge middleware
|
|
72
|
+
* (static `import`). Pure, total, never throws, no env reads.
|
|
73
|
+
*/
|
|
74
|
+
export declare const generateSessionTokenResolverCode: () => string;
|
|
75
|
+
/**
|
|
76
|
+
* The resolver plus a lazy `require('next-auth/jwt')`, for a CommonJS route.
|
|
77
|
+
*
|
|
78
|
+
* The require is lazy and guarded because a project generated WITHOUT
|
|
79
|
+
* authentication does not ship `next-auth`; such a project also has no session
|
|
80
|
+
* to read, so resolving to `null` there is the correct answer rather than a
|
|
81
|
+
* module-load crash.
|
|
82
|
+
*/
|
|
83
|
+
export declare const generateCommonJsSessionTokenResolverCode: () => string;
|
|
84
|
+
//# sourceMappingURL=session-cookie-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-cookie-resolver.d.ts","sourceRoot":"","sources":["../../src/session-cookie-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,4BAA4B,CAAA;AAiBlE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,gCAAgC,QAAO,MA6JnD,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,wCAAwC,QAAO,MAsB3D,CAAA"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Resolving the NextAuth session token in a generated route, WITHOUT asking
|
|
4
|
+
* `process.env.NEXTAUTH_URL` what the session cookie is called.
|
|
5
|
+
*
|
|
6
|
+
* ## ⛔ THE REPORTED DEFECT
|
|
7
|
+
*
|
|
8
|
+
* A published project showed "Failed to load dashboard data. Please refresh."
|
|
9
|
+
* on the home page, "Failed to load meeting data." on the list page and "could
|
|
10
|
+
* not fetch the templates" on a third — for a user who was signed in, on a page
|
|
11
|
+
* whose own `/api/auth/session` returned that user. The failing call was the
|
|
12
|
+
* page-load workflow's server segment, answering **401 `Unauthenticated`** from
|
|
13
|
+
* `guardWorkflowRequest`. Reloading sometimes fixed it; fanning 50 concurrent
|
|
14
|
+
* requests at the same route returned **33 × 401 and 17 × 200**, while 40
|
|
15
|
+
* concurrent `/api/auth/session` calls resolved the user 40/40.
|
|
16
|
+
*
|
|
17
|
+
* ## The mechanism
|
|
18
|
+
*
|
|
19
|
+
* next-auth v4's `getToken()` derives the cookie it reads from an env var:
|
|
20
|
+
*
|
|
21
|
+
* ```js
|
|
22
|
+
* secureCookie = process.env.NEXTAUTH_URL?.startsWith('https://') ?? !!process.env.VERCEL,
|
|
23
|
+
* cookieName = secureCookie ? '__Secure-next-auth.session-token' : 'next-auth.session-token',
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* A generated project ships `NEXTAUTH_URL=http://localhost:3000` — the build
|
|
27
|
+
* cannot know the domain it will be published to, so `pages/api/auth/[...nextauth].js`
|
|
28
|
+
* repairs `process.env.NEXTAUTH_URL` **from the incoming request** instead. That
|
|
29
|
+
* repair is process-local: it fixes the value for whichever serverless instance
|
|
30
|
+
* happened to serve an auth request, and for no other. Every other instance
|
|
31
|
+
* still holds `http://localhost:3000`, so `startsWith('https://')` is `false`
|
|
32
|
+
* (NOT `undefined` — the `??` fallback to `!!process.env.VERCEL` never runs),
|
|
33
|
+
* `getToken` looks for `next-auth.session-token`, the browser is holding
|
|
34
|
+
* `__Secure-next-auth.session-token`, nothing is found, and a signed-in user is
|
|
35
|
+
* reported as anonymous.
|
|
36
|
+
*
|
|
37
|
+
* Hence the coin-flip: it depends on whether the instance that served your
|
|
38
|
+
* request had previously served an auth request. Nothing about the session, the
|
|
39
|
+
* secret or the cookie is wrong.
|
|
40
|
+
*
|
|
41
|
+
* The same defect is why the generated middleware carries a `hasSessionCookie`
|
|
42
|
+
* fallback and a round trip to `/api/auth/session`, attributed there to an
|
|
43
|
+
* "Edge runtime quirk" — the Edge process holds that same localhost value.
|
|
44
|
+
*
|
|
45
|
+
* ## The rule
|
|
46
|
+
*
|
|
47
|
+
* ⭐ **A request must be authenticated from the REQUEST, never from an ambient
|
|
48
|
+
* env var that describes the deployment.** So this resolver reads which session
|
|
49
|
+
* cookie the caller actually sent, and tells `getToken` exactly that — falling
|
|
50
|
+
* back to the request's own protocol when the cookie header is unavailable.
|
|
51
|
+
*
|
|
52
|
+
* Emitted as plain ES5 text and inlined into each generated route: a route that
|
|
53
|
+
* carries its own copy cannot be broken by a missing sibling module or an
|
|
54
|
+
* untraced dependency, and every call site gets the identical implementation
|
|
55
|
+
* from this one definition.
|
|
56
|
+
*/
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.generateCommonJsSessionTokenResolverCode = exports.generateSessionTokenResolverCode = exports.SESSION_TOKEN_RESOLVER_FN = void 0;
|
|
59
|
+
/** The `__tq`-prefixed globals the emitted snippet declares. */
|
|
60
|
+
exports.SESSION_TOKEN_RESOLVER_FN = '__tqResolveSessionToken';
|
|
61
|
+
/**
|
|
62
|
+
* Session-cookie names next-auth/Auth.js writes, with the `secureCookie` flag
|
|
63
|
+
* that produces each. Order within a protocol is irrelevant — only ONE of these
|
|
64
|
+
* is ever present — but the https/http split decides which pair is tried first.
|
|
65
|
+
*
|
|
66
|
+
* `__Host-` is deliberately absent: next-auth uses it only for the CSRF and
|
|
67
|
+
* callback cookies, never for the session token.
|
|
68
|
+
*/
|
|
69
|
+
const KNOWN_SESSION_COOKIES = [
|
|
70
|
+
{ name: '__Secure-next-auth.session-token', secure: true },
|
|
71
|
+
{ name: 'next-auth.session-token', secure: false },
|
|
72
|
+
{ name: '__Secure-authjs.session-token', secure: true },
|
|
73
|
+
{ name: 'authjs.session-token', secure: false },
|
|
74
|
+
];
|
|
75
|
+
/**
|
|
76
|
+
* ES5 source for the shared session-token resolver, safe to inline into any
|
|
77
|
+
* generated CommonJS route or ESM middleware.
|
|
78
|
+
*
|
|
79
|
+
* Declares:
|
|
80
|
+
* - `__tqCookieNamesPresent(req)` — the set of cookie names on the request,
|
|
81
|
+
* parsed properly (a substring test would see `next-auth.session-token`
|
|
82
|
+
* inside `__Secure-next-auth.session-token` and pick the wrong one).
|
|
83
|
+
* - `__tqRequestIsSecure(req)` — https as the REQUEST reports it.
|
|
84
|
+
* - `__tqSessionTokenCandidates(req)` — `{cookieName, secureCookie}` pairs to try.
|
|
85
|
+
* - `__tqResolveSessionToken(getToken, req, secret)` — the token, or null.
|
|
86
|
+
*
|
|
87
|
+
* `getToken` is passed IN rather than required here, so the same body serves a
|
|
88
|
+
* CommonJS route (lazy `require('next-auth/jwt')`) and the Edge middleware
|
|
89
|
+
* (static `import`). Pure, total, never throws, no env reads.
|
|
90
|
+
*/
|
|
91
|
+
const generateSessionTokenResolverCode = () => {
|
|
92
|
+
return `// GENERATED — see generateSessionTokenResolverCode in
|
|
93
|
+
// @teleporthq/teleport-plugin-next-workflows/src/session-cookie-resolver.ts.
|
|
94
|
+
//
|
|
95
|
+
// next-auth's getToken() picks the session cookie name from
|
|
96
|
+
// process.env.NEXTAUTH_URL, which a generated project ships as a localhost
|
|
97
|
+
// default — so on a published https domain it looks for the non-secure cookie
|
|
98
|
+
// and reports a signed-in user as anonymous. These helpers read the cookie the
|
|
99
|
+
// request actually carries and tell getToken exactly which one it is.
|
|
100
|
+
var __TQ_SESSION_COOKIES = ${JSON.stringify(KNOWN_SESSION_COOKIES.map((c) => [c.name, c.secure]))};
|
|
101
|
+
|
|
102
|
+
// Every cookie NAME on the request. Parsed on the "; " separator rather than
|
|
103
|
+
// matched as a substring: "next-auth.session-token" occurs inside
|
|
104
|
+
// "__Secure-next-auth.session-token", so a substring test reports the plain
|
|
105
|
+
// cookie as present whenever the secure one is, and getToken then decodes the
|
|
106
|
+
// wrong (missing) cookie.
|
|
107
|
+
function __tqCookieNamesPresent(req) {
|
|
108
|
+
var present = {};
|
|
109
|
+
var raw = '';
|
|
110
|
+
try {
|
|
111
|
+
var headers = req && req.headers;
|
|
112
|
+
if (headers && typeof headers.get === 'function') {
|
|
113
|
+
// Edge / fetch Headers.
|
|
114
|
+
raw = headers.get('cookie') || '';
|
|
115
|
+
} else if (headers) {
|
|
116
|
+
var value = headers.cookie || headers.Cookie;
|
|
117
|
+
raw = Array.isArray(value) ? value.join('; ') : value || '';
|
|
118
|
+
}
|
|
119
|
+
} catch (e) {
|
|
120
|
+
raw = '';
|
|
121
|
+
}
|
|
122
|
+
var parts = String(raw).split(';');
|
|
123
|
+
for (var i = 0; i < parts.length; i++) {
|
|
124
|
+
var eq = parts[i].indexOf('=');
|
|
125
|
+
if (eq > 0) {
|
|
126
|
+
present[parts[i].slice(0, eq).trim()] = true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Second source: the runtime's own parsed cookies. A Next.js API route hands
|
|
130
|
+
// over a plain object; the Edge RequestCookies exposes getAll().
|
|
131
|
+
try {
|
|
132
|
+
var cookies = req && req.cookies;
|
|
133
|
+
if (cookies && typeof cookies.getAll === 'function') {
|
|
134
|
+
var all = cookies.getAll() || [];
|
|
135
|
+
for (var a = 0; a < all.length; a++) {
|
|
136
|
+
if (all[a] && all[a].name) {
|
|
137
|
+
present[all[a].name] = true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} else if (cookies && typeof cookies === 'object') {
|
|
141
|
+
for (var key in cookies) {
|
|
142
|
+
if (Object.prototype.hasOwnProperty.call(cookies, key)) {
|
|
143
|
+
present[key] = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} catch (e) {
|
|
148
|
+
/* the header pass above is enough */
|
|
149
|
+
}
|
|
150
|
+
return present;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Is this request https? Read from the proxy header the platform sets, then the
|
|
154
|
+
// socket, then the URL — never from an env var describing the deployment.
|
|
155
|
+
function __tqRequestIsSecure(req) {
|
|
156
|
+
try {
|
|
157
|
+
var headers = (req && req.headers) || {};
|
|
158
|
+
var proto =
|
|
159
|
+
typeof headers.get === 'function'
|
|
160
|
+
? headers.get('x-forwarded-proto')
|
|
161
|
+
: headers['x-forwarded-proto'];
|
|
162
|
+
if (Array.isArray(proto)) {
|
|
163
|
+
proto = proto[0];
|
|
164
|
+
}
|
|
165
|
+
if (typeof proto === 'string' && proto) {
|
|
166
|
+
// A chain of proxies appends: "https,http" — the client-facing hop is first.
|
|
167
|
+
return proto.split(',')[0].trim().toLowerCase() === 'https';
|
|
168
|
+
}
|
|
169
|
+
if (req && req.nextUrl && req.nextUrl.protocol === 'https:') {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
if (req && req.socket && req.socket.encrypted) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
if (req && req.connection && req.connection.encrypted) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
if (typeof (req && req.url) === 'string' && req.url.indexOf('https://') === 0) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
} catch (e) {
|
|
182
|
+
/* fall through to false */
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// The { cookieName, secureCookie } pairs worth trying, most likely first.
|
|
188
|
+
// Normally exactly one cookie is present and this returns a single entry; the
|
|
189
|
+
// list only grows when a site has been reached over both http and https.
|
|
190
|
+
function __tqSessionTokenCandidates(req) {
|
|
191
|
+
var present = __tqCookieNamesPresent(req);
|
|
192
|
+
var secure = __tqRequestIsSecure(req);
|
|
193
|
+
var candidates = [];
|
|
194
|
+
for (var i = 0; i < __TQ_SESSION_COOKIES.length; i++) {
|
|
195
|
+
var name = __TQ_SESSION_COOKIES[i][0];
|
|
196
|
+
var isSecureName = __TQ_SESSION_COOKIES[i][1];
|
|
197
|
+
if (present[name] || present[name + '.0']) {
|
|
198
|
+
candidates.push({ cookieName: name, secureCookie: isSecureName });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
candidates.sort(function (a, b) {
|
|
202
|
+
if (a.secureCookie === b.secureCookie) {
|
|
203
|
+
return 0;
|
|
204
|
+
}
|
|
205
|
+
return a.secureCookie === secure ? -1 : 1;
|
|
206
|
+
});
|
|
207
|
+
if (candidates.length === 0) {
|
|
208
|
+
// No cookie we recognise. The project may configure a custom cookie name in
|
|
209
|
+
// authOptions, so hand getToken the request's own protocol and let it apply
|
|
210
|
+
// its defaults — same behaviour as before this resolver existed, minus the
|
|
211
|
+
// localhost env var.
|
|
212
|
+
candidates.push({ secureCookie: secure });
|
|
213
|
+
}
|
|
214
|
+
return candidates;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// The decoded session token, or null. Tries each candidate cookie in turn so a
|
|
218
|
+
// project that renamed its cookie, or one reached over both protocols, still
|
|
219
|
+
// resolves. Never throws.
|
|
220
|
+
function ${exports.SESSION_TOKEN_RESOLVER_FN}(getToken, req, secret) {
|
|
221
|
+
if (!secret || typeof getToken !== 'function') {
|
|
222
|
+
return Promise.resolve(null);
|
|
223
|
+
}
|
|
224
|
+
var candidates = __tqSessionTokenCandidates(req);
|
|
225
|
+
var attempt = function (index) {
|
|
226
|
+
if (index >= candidates.length) {
|
|
227
|
+
return Promise.resolve(null);
|
|
228
|
+
}
|
|
229
|
+
var candidate = candidates[index];
|
|
230
|
+
var params = { req: req, secret: secret, secureCookie: candidate.secureCookie };
|
|
231
|
+
if (candidate.cookieName) {
|
|
232
|
+
params.cookieName = candidate.cookieName;
|
|
233
|
+
}
|
|
234
|
+
return Promise.resolve()
|
|
235
|
+
.then(function () {
|
|
236
|
+
return getToken(params);
|
|
237
|
+
})
|
|
238
|
+
.catch(function () {
|
|
239
|
+
return null;
|
|
240
|
+
})
|
|
241
|
+
.then(function (token) {
|
|
242
|
+
return token || attempt(index + 1);
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
return attempt(0);
|
|
246
|
+
}
|
|
247
|
+
`;
|
|
248
|
+
};
|
|
249
|
+
exports.generateSessionTokenResolverCode = generateSessionTokenResolverCode;
|
|
250
|
+
/**
|
|
251
|
+
* The resolver plus a lazy `require('next-auth/jwt')`, for a CommonJS route.
|
|
252
|
+
*
|
|
253
|
+
* The require is lazy and guarded because a project generated WITHOUT
|
|
254
|
+
* authentication does not ship `next-auth`; such a project also has no session
|
|
255
|
+
* to read, so resolving to `null` there is the correct answer rather than a
|
|
256
|
+
* module-load crash.
|
|
257
|
+
*/
|
|
258
|
+
const generateCommonJsSessionTokenResolverCode = () => {
|
|
259
|
+
return `${(0, exports.generateSessionTokenResolverCode)()}
|
|
260
|
+
// Lazy + guarded: a project generated without authentication has no next-auth
|
|
261
|
+
// installed, and no session to read either — null is the right answer there.
|
|
262
|
+
function __tqGetTokenFn() {
|
|
263
|
+
try {
|
|
264
|
+
var jwt = require('next-auth/jwt');
|
|
265
|
+
return jwt && typeof jwt.getToken === 'function' ? jwt.getToken : null;
|
|
266
|
+
} catch (e) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// The session token for this request, or null. Reads NEXTAUTH_SECRET itself.
|
|
272
|
+
function __tqSessionToken(req) {
|
|
273
|
+
var secret = process.env.NEXTAUTH_SECRET;
|
|
274
|
+
if (!secret) {
|
|
275
|
+
return Promise.resolve(null);
|
|
276
|
+
}
|
|
277
|
+
return ${exports.SESSION_TOKEN_RESOLVER_FN}(__tqGetTokenFn(), req, secret);
|
|
278
|
+
}
|
|
279
|
+
`;
|
|
280
|
+
};
|
|
281
|
+
exports.generateCommonJsSessionTokenResolverCode = generateCommonJsSessionTokenResolverCode;
|
|
282
|
+
//# sourceMappingURL=session-cookie-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-cookie-resolver.js","sourceRoot":"","sources":["../../src/session-cookie-resolver.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;;;AAEH,gEAAgE;AACnD,QAAA,yBAAyB,GAAG,yBAAyB,CAAA;AAElE;;;;;;;GAOG;AACH,MAAM,qBAAqB,GAAqD;IAC9E,EAAE,IAAI,EAAE,kCAAkC,EAAE,MAAM,EAAE,IAAI,EAAE;IAC1D,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,EAAE,KAAK,EAAE;IAClD,EAAE,IAAI,EAAE,+BAA+B,EAAE,MAAM,EAAE,IAAI,EAAE;IACvD,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,KAAK,EAAE;CAChD,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACI,MAAM,gCAAgC,GAAG,GAAW,EAAE;IAC3D,OAAO;;;;;;;;6BAQoB,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAwHtF,iCAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BnC,CAAA;AACD,CAAC,CAAA;AA7JY,QAAA,gCAAgC,oCA6J5C;AAED;;;;;;;GAOG;AACI,MAAM,wCAAwC,GAAG,GAAW,EAAE;IACnE,OAAO,GAAG,IAAA,wCAAgC,GAAE;;;;;;;;;;;;;;;;;;WAkBnC,iCAAyB;;CAEnC,CAAA;AACD,CAAC,CAAA;AAtBY,QAAA,wCAAwC,4CAsBpD"}
|