@teleporthq/teleport-plugin-next-workflows 0.43.45 → 0.43.47
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__/_helpers/run-generated-middleware.ts +130 -0
- package/__tests__/auth-env-secret-preservation.test.ts +35 -0
- package/__tests__/auth-nextauth-url.test.ts +28 -0
- package/__tests__/auth-session-cost.test.ts +614 -0
- package/__tests__/custom-js-params-env-invariance.test.ts +134 -0
- package/__tests__/data-node-not-awaited.test.ts +644 -0
- package/__tests__/element-trigger-static-attr-replace.test.ts +99 -0
- package/__tests__/element-visible-trigger-scoping.test.ts +296 -0
- package/__tests__/form-submitted-trigger-context.test.ts +100 -0
- package/__tests__/middleware-guest-order-details.test.ts +258 -0
- package/__tests__/middleware-row-owned-pages.test.ts +32 -9
- package/__tests__/payment-charge-user-handler-serialization.test.ts +7 -5
- package/__tests__/payment-redirect-and-order-notification.test.ts +6 -4
- package/__tests__/raw-sql-param-binding.test.ts +82 -0
- package/__tests__/reserved-word-state-binding.test.ts +112 -0
- package/__tests__/strip-event-handler-attrs.test.ts +59 -0
- package/__tests__/workflow-auth-guard.test.ts +277 -0
- package/dist/cjs/api-route-generator.d.ts +3 -3
- package/dist/cjs/api-route-generator.d.ts.map +1 -1
- package/dist/cjs/api-route-generator.js +136 -11
- package/dist/cjs/api-route-generator.js.map +1 -1
- package/dist/cjs/auth-generator.d.ts +67 -1
- package/dist/cjs/auth-generator.d.ts.map +1 -1
- package/dist/cjs/auth-generator.js +573 -31
- package/dist/cjs/auth-generator.js.map +1 -1
- package/dist/cjs/await-result.d.ts +31 -0
- package/dist/cjs/await-result.d.ts.map +1 -0
- package/dist/cjs/await-result.js +50 -0
- package/dist/cjs/await-result.js.map +1 -0
- package/dist/cjs/executor-generator.d.ts.map +1 -1
- package/dist/cjs/executor-generator.js +150 -1
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/nodes/account/account-get-current.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-get-current.js +44 -11
- package/dist/cjs/nodes/account/account-get-current.js.map +1 -1
- package/dist/cjs/nodes/account/account-login.d.ts.map +1 -1
- package/dist/cjs/nodes/account/account-login.js +10 -1
- package/dist/cjs/nodes/account/account-login.js.map +1 -1
- package/dist/cjs/raw-sql-param-binding.d.ts.map +1 -1
- package/dist/cjs/raw-sql-param-binding.js +32 -0
- package/dist/cjs/raw-sql-param-binding.js.map +1 -1
- package/dist/cjs/segment-splitter.d.ts.map +1 -1
- package/dist/cjs/segment-splitter.js +15 -7
- package/dist/cjs/segment-splitter.js.map +1 -1
- package/dist/cjs/trigger-generator.js +7 -1
- package/dist/cjs/trigger-generator.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/workflow-auth-generator.d.ts +26 -0
- package/dist/cjs/workflow-auth-generator.d.ts.map +1 -0
- package/dist/cjs/workflow-auth-generator.js +166 -0
- package/dist/cjs/workflow-auth-generator.js.map +1 -0
- package/dist/cjs/workflow-component-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-component-plugin.js +124 -17
- package/dist/cjs/workflow-component-plugin.js.map +1 -1
- package/dist/cjs/workflow-project-plugin.d.ts +2 -1
- package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-project-plugin.js +170 -20
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/esm/api-route-generator.d.ts +3 -3
- package/dist/esm/api-route-generator.d.ts.map +1 -1
- package/dist/esm/api-route-generator.js +136 -11
- package/dist/esm/api-route-generator.js.map +1 -1
- package/dist/esm/auth-generator.d.ts +67 -1
- package/dist/esm/auth-generator.d.ts.map +1 -1
- package/dist/esm/auth-generator.js +568 -30
- package/dist/esm/auth-generator.js.map +1 -1
- package/dist/esm/await-result.d.ts +31 -0
- package/dist/esm/await-result.d.ts.map +1 -0
- package/dist/esm/await-result.js +45 -0
- package/dist/esm/await-result.js.map +1 -0
- package/dist/esm/executor-generator.d.ts.map +1 -1
- package/dist/esm/executor-generator.js +150 -1
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/nodes/account/account-get-current.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-get-current.js +44 -11
- package/dist/esm/nodes/account/account-get-current.js.map +1 -1
- package/dist/esm/nodes/account/account-login.d.ts.map +1 -1
- package/dist/esm/nodes/account/account-login.js +10 -1
- package/dist/esm/nodes/account/account-login.js.map +1 -1
- package/dist/esm/raw-sql-param-binding.d.ts.map +1 -1
- package/dist/esm/raw-sql-param-binding.js +32 -0
- package/dist/esm/raw-sql-param-binding.js.map +1 -1
- package/dist/esm/segment-splitter.d.ts.map +1 -1
- package/dist/esm/segment-splitter.js +15 -7
- package/dist/esm/segment-splitter.js.map +1 -1
- package/dist/esm/trigger-generator.js +7 -1
- package/dist/esm/trigger-generator.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/workflow-auth-generator.d.ts +26 -0
- package/dist/esm/workflow-auth-generator.d.ts.map +1 -0
- package/dist/esm/workflow-auth-generator.js +161 -0
- package/dist/esm/workflow-auth-generator.js.map +1 -0
- package/dist/esm/workflow-component-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-component-plugin.js +125 -18
- package/dist/esm/workflow-component-plugin.js.map +1 -1
- package/dist/esm/workflow-project-plugin.d.ts +2 -1
- package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-project-plugin.js +169 -20
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/package.json +4 -4
- package/src/api-route-generator.ts +139 -11
- package/src/auth-generator.ts +600 -30
- package/src/await-result.ts +52 -0
- package/src/executor-generator.ts +150 -1
- package/src/nodes/account/account-get-current.ts +44 -9
- package/src/nodes/account/account-login.ts +12 -1
- package/src/raw-sql-param-binding.ts +33 -0
- package/src/segment-splitter.ts +15 -7
- package/src/trigger-generator.ts +7 -1
- package/src/workflow-auth-generator.ts +187 -0
- package/src/workflow-component-plugin.ts +146 -21
- package/src/workflow-project-plugin.ts +186 -19
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { UIDLAuthentication } from '@teleporthq/teleport-types'
|
|
2
|
+
import { generateMiddlewareFile } from '../../src/auth-generator'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Loads the middleware `generateMiddlewareFile` emits and runs it against a
|
|
6
|
+
* synthetic request, so tests can assert on BEHAVIOUR ("does a guest reach
|
|
7
|
+
* /orders/ORD-42?") instead of grepping the generated source.
|
|
8
|
+
*
|
|
9
|
+
* The emitted file is an ES module that imports `next/server` and
|
|
10
|
+
* `next-auth/jwt`; neither is installed in this package, so the loader strips
|
|
11
|
+
* the module boundary and injects the pieces the middleware actually uses.
|
|
12
|
+
* `getToken` always resolves to `null` — the generated code then falls back to
|
|
13
|
+
* cookie presence plus `/api/auth/session`, which the fetch stub answers, so
|
|
14
|
+
* both the authenticated and the anonymous path stay exercisable.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface MiddlewareResult {
|
|
18
|
+
kind: 'next' | 'redirect'
|
|
19
|
+
/** Only set for `kind: 'redirect'`. */
|
|
20
|
+
location?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface MiddlewareSessionUser {
|
|
24
|
+
id?: string
|
|
25
|
+
role?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface MiddlewareRequestOptions {
|
|
29
|
+
/** Session user the stubbed `/api/auth/session` returns; omit for a guest. */
|
|
30
|
+
sessionUser?: MiddlewareSessionUser | null
|
|
31
|
+
origin?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface RawMiddlewareResult {
|
|
35
|
+
__kind: 'next' | 'redirect'
|
|
36
|
+
__location?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type MiddlewareFn = (request: unknown) => Promise<RawMiddlewareResult>
|
|
40
|
+
|
|
41
|
+
type MiddlewareFactory = (
|
|
42
|
+
nextResponse: unknown,
|
|
43
|
+
getToken: unknown,
|
|
44
|
+
fetchImpl: unknown
|
|
45
|
+
) => MiddlewareFn
|
|
46
|
+
|
|
47
|
+
const stripModuleSyntax = (code: string): string =>
|
|
48
|
+
code
|
|
49
|
+
.replace("import { NextResponse } from 'next/server';", '')
|
|
50
|
+
.replace("import { getToken } from 'next-auth/jwt';", '')
|
|
51
|
+
.replace('export default middleware;', '')
|
|
52
|
+
.replace('export const config = {', 'const config = {')
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The route table the generated middleware gates on. Parsed out of the emitted
|
|
56
|
+
* source so assertions can target the actual map instead of substring-matching
|
|
57
|
+
* a file that also contains comments and the self-guarded route list.
|
|
58
|
+
*/
|
|
59
|
+
export const extractProtectedRoutes = (
|
|
60
|
+
code: string
|
|
61
|
+
): Record<string, { requiresAuth: boolean; allowedRoles: string[] }> => {
|
|
62
|
+
// Non-greedy up to the first `};`. `JSON.stringify(…, null, 2)` never emits
|
|
63
|
+
// that sequence inside the object, so the first hit is the real terminator —
|
|
64
|
+
// and the empty-map case (`= {};`) is covered by the same pattern.
|
|
65
|
+
const match = code.match(/const protectedRoutes = (\{[\s\S]*?\});/)
|
|
66
|
+
if (!match) {
|
|
67
|
+
throw new Error('generated middleware has no protectedRoutes declaration')
|
|
68
|
+
}
|
|
69
|
+
return JSON.parse(match[1])
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Route patterns whose page-load SQL is the access control. */
|
|
73
|
+
export const extractSelfGuardedRoutes = (code: string): string[] => {
|
|
74
|
+
const match = code.match(/const selfGuardedRoutes = (\[[\s\S]*?\]);/)
|
|
75
|
+
if (!match) {
|
|
76
|
+
throw new Error('generated middleware has no selfGuardedRoutes declaration')
|
|
77
|
+
}
|
|
78
|
+
return JSON.parse(match[1])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const NEXT_RESPONSE_STUB = {
|
|
82
|
+
next: (): RawMiddlewareResult => ({ __kind: 'next' }),
|
|
83
|
+
redirect: (url: URL): RawMiddlewareResult => ({
|
|
84
|
+
__kind: 'redirect',
|
|
85
|
+
__location: String(url),
|
|
86
|
+
}),
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Compiles the middleware once for an auth config. Reuse the returned function
|
|
91
|
+
* across requests in a test to avoid re-generating the file per assertion.
|
|
92
|
+
*/
|
|
93
|
+
export const compileGeneratedMiddleware = (auth: UIDLAuthentication) => {
|
|
94
|
+
const factory = new Function(
|
|
95
|
+
'NextResponse',
|
|
96
|
+
'getToken',
|
|
97
|
+
'fetch',
|
|
98
|
+
`${stripModuleSyntax(generateMiddlewareFile(auth))}; return middleware;`
|
|
99
|
+
) as unknown as MiddlewareFactory
|
|
100
|
+
|
|
101
|
+
return async (
|
|
102
|
+
pathname: string,
|
|
103
|
+
options: MiddlewareRequestOptions = {}
|
|
104
|
+
): Promise<MiddlewareResult> => {
|
|
105
|
+
const origin = options.origin || 'https://shop.test'
|
|
106
|
+
const sessionUser = options.sessionUser ?? null
|
|
107
|
+
const cookieHeader = sessionUser ? 'next-auth.session-token=stub' : ''
|
|
108
|
+
|
|
109
|
+
const fetchImpl = async () => ({
|
|
110
|
+
ok: true,
|
|
111
|
+
json: async () => ({ user: sessionUser }),
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const getTokenStub = async (): Promise<null> => null
|
|
115
|
+
const middleware = factory(NEXT_RESPONSE_STUB, getTokenStub, fetchImpl)
|
|
116
|
+
const result = await middleware({
|
|
117
|
+
nextUrl: { pathname },
|
|
118
|
+
url: `${origin}${pathname}`,
|
|
119
|
+
cookies: {
|
|
120
|
+
get: (name: string) =>
|
|
121
|
+
sessionUser && name === 'next-auth.session-token' ? { name, value: 'stub' } : undefined,
|
|
122
|
+
},
|
|
123
|
+
headers: { get: (name: string) => (name === 'cookie' ? cookieHeader : '') },
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
return result.__kind === 'redirect'
|
|
127
|
+
? { kind: 'redirect', location: result.__location }
|
|
128
|
+
: { kind: 'next' }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -118,4 +118,39 @@ describe('resolveAuthEnvValue', () => {
|
|
|
118
118
|
expect(resolveAuthEnvValue('TELEPORT_DB_SSL', 'true', oauthKeys)).toBe('true')
|
|
119
119
|
expect(resolveAuthEnvValue('AUTH_CREDENTIALS_ENABLED', 'true', oauthKeys)).toBe('true')
|
|
120
120
|
})
|
|
121
|
+
|
|
122
|
+
// Regression: next-auth v4 `react/index.js` runs `parseUrl(process.env.NEXTAUTH_URL)`
|
|
123
|
+
// at module load, and `new URL('')` throws "Invalid URL" — crashing SSR for
|
|
124
|
+
// every page that mounts SessionProvider. `createEnvFiles` writes every key,
|
|
125
|
+
// so a BLANK NEXTAUTH_URL serializes as the crashing `NEXTAUTH_URL=`. The
|
|
126
|
+
// blank case is self-perpetuating (the standalone harness re-injects the
|
|
127
|
+
// on-disk empty value), so the resolver must heal it, not pass it through.
|
|
128
|
+
describe('blank auth-critical keys heal to their local default', () => {
|
|
129
|
+
it.each(['', ' ', undefined as unknown as string])(
|
|
130
|
+
'NEXTAUTH_URL=%p becomes the localhost default rather than an empty assignment',
|
|
131
|
+
(blank) => {
|
|
132
|
+
expect(resolveAuthEnvValue('NEXTAUTH_URL', blank, oauthKeys)).toBe('http://localhost:3000')
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
it('a blank NEXTAUTH_SECRET heals to the placeholder default', () => {
|
|
137
|
+
expect(resolveAuthEnvValue('NEXTAUTH_SECRET', '', oauthKeys)).toBe(
|
|
138
|
+
'CHANGE_ME_TO_A_RANDOM_SECRET'
|
|
139
|
+
)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('a real configured NEXTAUTH_URL / NEXTAUTH_SECRET is left untouched', () => {
|
|
143
|
+
expect(resolveAuthEnvValue('NEXTAUTH_URL', 'https://shop.example.com', oauthKeys)).toBe(
|
|
144
|
+
'https://shop.example.com'
|
|
145
|
+
)
|
|
146
|
+
expect(
|
|
147
|
+
resolveAuthEnvValue('NEXTAUTH_SECRET', 'a-real-32-char-secret-value-xxxxx', oauthKeys)
|
|
148
|
+
).toBe('a-real-32-char-secret-value-xxxxx')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('a blank NON-auth key still serializes blank — no behavior change outside the two auth keys', () => {
|
|
152
|
+
expect(resolveAuthEnvValue('TELEPORT_DB_SSL', '', oauthKeys)).toBe('')
|
|
153
|
+
expect(resolveAuthEnvValue('SOME_OTHER_KEY', '', oauthKeys)).toBe('')
|
|
154
|
+
})
|
|
155
|
+
})
|
|
121
156
|
})
|
|
@@ -56,4 +56,32 @@ describe('generated NextAuth route — dynamic NEXTAUTH_URL', () => {
|
|
|
56
56
|
handler({ headers: { host: 'localhost:3000' } }, {})
|
|
57
57
|
expect(process.env.NEXTAUTH_URL).toBe('http://localhost:3000')
|
|
58
58
|
})
|
|
59
|
+
|
|
60
|
+
// Project a62338f9 published with `NEXTAUTH_URL=teleporthq.secrets.NEXTAUTH_URL`.
|
|
61
|
+
// The old check saw a non-empty, non-localhost string and treated it as
|
|
62
|
+
// explicitly configured, so NextAuth normalised it to
|
|
63
|
+
// `https://teleporthq.secrets.nextauth_url`, advertised that as the sign-in
|
|
64
|
+
// origin and issued `__Host-`/`__Secure-` cookies against it. Sign-in failed
|
|
65
|
+
// with a bare `credentialsSignin`. An unresolved placeholder is now treated
|
|
66
|
+
// as unset, so an already-published site self-heals on its next request.
|
|
67
|
+
it('overrides an unresolved secret placeholder on a published domain', () => {
|
|
68
|
+
process.env.NEXTAUTH_URL = 'teleporthq.secrets.NEXTAUTH_URL'
|
|
69
|
+
handler(
|
|
70
|
+
{ headers: { host: 'rare-last-dunlin.teleporthq.dev', 'x-forwarded-proto': 'https' } },
|
|
71
|
+
{}
|
|
72
|
+
)
|
|
73
|
+
expect(process.env.NEXTAUTH_URL).toBe('https://rare-last-dunlin.teleporthq.dev')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('falls back to an http origin locally, so cookies are not Secure-prefixed', () => {
|
|
77
|
+
process.env.NEXTAUTH_URL = 'teleporthq.secrets.NEXTAUTH_URL'
|
|
78
|
+
handler({ headers: { host: 'localhost:3001' } }, {})
|
|
79
|
+
expect(process.env.NEXTAUTH_URL).toBe('http://localhost:3001')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('overrides any value that is not an absolute http(s) origin', () => {
|
|
83
|
+
process.env.NEXTAUTH_URL = 'my-app.teleporthq.dev'
|
|
84
|
+
handler({ headers: { host: 'my-app.teleporthq.dev', 'x-forwarded-proto': 'https' } }, {})
|
|
85
|
+
expect(process.env.NEXTAUTH_URL).toBe('https://my-app.teleporthq.dev')
|
|
86
|
+
})
|
|
59
87
|
})
|