@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.
Files changed (112) hide show
  1. package/__tests__/_helpers/run-generated-middleware.ts +130 -0
  2. package/__tests__/auth-env-secret-preservation.test.ts +35 -0
  3. package/__tests__/auth-nextauth-url.test.ts +28 -0
  4. package/__tests__/auth-session-cost.test.ts +614 -0
  5. package/__tests__/custom-js-params-env-invariance.test.ts +134 -0
  6. package/__tests__/data-node-not-awaited.test.ts +644 -0
  7. package/__tests__/element-trigger-static-attr-replace.test.ts +99 -0
  8. package/__tests__/element-visible-trigger-scoping.test.ts +296 -0
  9. package/__tests__/form-submitted-trigger-context.test.ts +100 -0
  10. package/__tests__/middleware-guest-order-details.test.ts +258 -0
  11. package/__tests__/middleware-row-owned-pages.test.ts +32 -9
  12. package/__tests__/payment-charge-user-handler-serialization.test.ts +7 -5
  13. package/__tests__/payment-redirect-and-order-notification.test.ts +6 -4
  14. package/__tests__/raw-sql-param-binding.test.ts +82 -0
  15. package/__tests__/reserved-word-state-binding.test.ts +112 -0
  16. package/__tests__/strip-event-handler-attrs.test.ts +59 -0
  17. package/__tests__/workflow-auth-guard.test.ts +277 -0
  18. package/dist/cjs/api-route-generator.d.ts +3 -3
  19. package/dist/cjs/api-route-generator.d.ts.map +1 -1
  20. package/dist/cjs/api-route-generator.js +136 -11
  21. package/dist/cjs/api-route-generator.js.map +1 -1
  22. package/dist/cjs/auth-generator.d.ts +67 -1
  23. package/dist/cjs/auth-generator.d.ts.map +1 -1
  24. package/dist/cjs/auth-generator.js +573 -31
  25. package/dist/cjs/auth-generator.js.map +1 -1
  26. package/dist/cjs/await-result.d.ts +31 -0
  27. package/dist/cjs/await-result.d.ts.map +1 -0
  28. package/dist/cjs/await-result.js +50 -0
  29. package/dist/cjs/await-result.js.map +1 -0
  30. package/dist/cjs/executor-generator.d.ts.map +1 -1
  31. package/dist/cjs/executor-generator.js +150 -1
  32. package/dist/cjs/executor-generator.js.map +1 -1
  33. package/dist/cjs/nodes/account/account-get-current.d.ts.map +1 -1
  34. package/dist/cjs/nodes/account/account-get-current.js +44 -11
  35. package/dist/cjs/nodes/account/account-get-current.js.map +1 -1
  36. package/dist/cjs/nodes/account/account-login.d.ts.map +1 -1
  37. package/dist/cjs/nodes/account/account-login.js +10 -1
  38. package/dist/cjs/nodes/account/account-login.js.map +1 -1
  39. package/dist/cjs/raw-sql-param-binding.d.ts.map +1 -1
  40. package/dist/cjs/raw-sql-param-binding.js +32 -0
  41. package/dist/cjs/raw-sql-param-binding.js.map +1 -1
  42. package/dist/cjs/segment-splitter.d.ts.map +1 -1
  43. package/dist/cjs/segment-splitter.js +15 -7
  44. package/dist/cjs/segment-splitter.js.map +1 -1
  45. package/dist/cjs/trigger-generator.js +7 -1
  46. package/dist/cjs/trigger-generator.js.map +1 -1
  47. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  48. package/dist/cjs/workflow-auth-generator.d.ts +26 -0
  49. package/dist/cjs/workflow-auth-generator.d.ts.map +1 -0
  50. package/dist/cjs/workflow-auth-generator.js +166 -0
  51. package/dist/cjs/workflow-auth-generator.js.map +1 -0
  52. package/dist/cjs/workflow-component-plugin.d.ts.map +1 -1
  53. package/dist/cjs/workflow-component-plugin.js +124 -17
  54. package/dist/cjs/workflow-component-plugin.js.map +1 -1
  55. package/dist/cjs/workflow-project-plugin.d.ts +2 -1
  56. package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
  57. package/dist/cjs/workflow-project-plugin.js +170 -20
  58. package/dist/cjs/workflow-project-plugin.js.map +1 -1
  59. package/dist/esm/api-route-generator.d.ts +3 -3
  60. package/dist/esm/api-route-generator.d.ts.map +1 -1
  61. package/dist/esm/api-route-generator.js +136 -11
  62. package/dist/esm/api-route-generator.js.map +1 -1
  63. package/dist/esm/auth-generator.d.ts +67 -1
  64. package/dist/esm/auth-generator.d.ts.map +1 -1
  65. package/dist/esm/auth-generator.js +568 -30
  66. package/dist/esm/auth-generator.js.map +1 -1
  67. package/dist/esm/await-result.d.ts +31 -0
  68. package/dist/esm/await-result.d.ts.map +1 -0
  69. package/dist/esm/await-result.js +45 -0
  70. package/dist/esm/await-result.js.map +1 -0
  71. package/dist/esm/executor-generator.d.ts.map +1 -1
  72. package/dist/esm/executor-generator.js +150 -1
  73. package/dist/esm/executor-generator.js.map +1 -1
  74. package/dist/esm/nodes/account/account-get-current.d.ts.map +1 -1
  75. package/dist/esm/nodes/account/account-get-current.js +44 -11
  76. package/dist/esm/nodes/account/account-get-current.js.map +1 -1
  77. package/dist/esm/nodes/account/account-login.d.ts.map +1 -1
  78. package/dist/esm/nodes/account/account-login.js +10 -1
  79. package/dist/esm/nodes/account/account-login.js.map +1 -1
  80. package/dist/esm/raw-sql-param-binding.d.ts.map +1 -1
  81. package/dist/esm/raw-sql-param-binding.js +32 -0
  82. package/dist/esm/raw-sql-param-binding.js.map +1 -1
  83. package/dist/esm/segment-splitter.d.ts.map +1 -1
  84. package/dist/esm/segment-splitter.js +15 -7
  85. package/dist/esm/segment-splitter.js.map +1 -1
  86. package/dist/esm/trigger-generator.js +7 -1
  87. package/dist/esm/trigger-generator.js.map +1 -1
  88. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  89. package/dist/esm/workflow-auth-generator.d.ts +26 -0
  90. package/dist/esm/workflow-auth-generator.d.ts.map +1 -0
  91. package/dist/esm/workflow-auth-generator.js +161 -0
  92. package/dist/esm/workflow-auth-generator.js.map +1 -0
  93. package/dist/esm/workflow-component-plugin.d.ts.map +1 -1
  94. package/dist/esm/workflow-component-plugin.js +125 -18
  95. package/dist/esm/workflow-component-plugin.js.map +1 -1
  96. package/dist/esm/workflow-project-plugin.d.ts +2 -1
  97. package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
  98. package/dist/esm/workflow-project-plugin.js +169 -20
  99. package/dist/esm/workflow-project-plugin.js.map +1 -1
  100. package/package.json +4 -4
  101. package/src/api-route-generator.ts +139 -11
  102. package/src/auth-generator.ts +600 -30
  103. package/src/await-result.ts +52 -0
  104. package/src/executor-generator.ts +150 -1
  105. package/src/nodes/account/account-get-current.ts +44 -9
  106. package/src/nodes/account/account-login.ts +12 -1
  107. package/src/raw-sql-param-binding.ts +33 -0
  108. package/src/segment-splitter.ts +15 -7
  109. package/src/trigger-generator.ts +7 -1
  110. package/src/workflow-auth-generator.ts +187 -0
  111. package/src/workflow-component-plugin.ts +146 -21
  112. 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
  })