@teleporthq/teleport-plugin-next-workflows 0.45.14 → 0.45.16

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 (31) hide show
  1. package/__tests__/cron-route-loop-templateparams.test.ts +5 -4
  2. package/__tests__/custom-js-loop-scope.test.ts +10 -5
  3. package/__tests__/loop-collection-unwrap.test.ts +6 -1
  4. package/__tests__/server-loop-body-branches.test.ts +188 -0
  5. package/__tests__/server-loop-types.test.ts +371 -0
  6. package/__tests__/server-nested-loops.test.ts +392 -0
  7. package/__tests__/streaming-route-if-branch.test.ts +107 -0
  8. package/dist/cjs/api-route-generator.d.ts.map +1 -1
  9. package/dist/cjs/api-route-generator.js +57 -248
  10. package/dist/cjs/api-route-generator.js.map +1 -1
  11. package/dist/cjs/executor-generator.d.ts.map +1 -1
  12. package/dist/cjs/executor-generator.js +84 -27
  13. package/dist/cjs/executor-generator.js.map +1 -1
  14. package/dist/cjs/server-runtime-code.d.ts.map +1 -1
  15. package/dist/cjs/server-runtime-code.js +67 -0
  16. package/dist/cjs/server-runtime-code.js.map +1 -1
  17. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  18. package/dist/esm/api-route-generator.d.ts.map +1 -1
  19. package/dist/esm/api-route-generator.js +57 -248
  20. package/dist/esm/api-route-generator.js.map +1 -1
  21. package/dist/esm/executor-generator.d.ts.map +1 -1
  22. package/dist/esm/executor-generator.js +84 -27
  23. package/dist/esm/executor-generator.js.map +1 -1
  24. package/dist/esm/server-runtime-code.d.ts.map +1 -1
  25. package/dist/esm/server-runtime-code.js +67 -0
  26. package/dist/esm/server-runtime-code.js.map +1 -1
  27. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +2 -2
  29. package/src/api-route-generator.ts +57 -248
  30. package/src/executor-generator.ts +84 -27
  31. package/src/server-runtime-code.ts +67 -0
@@ -0,0 +1,392 @@
1
+ import {
2
+ generateCronAPIRoute,
3
+ generateServerSegmentAPIRoute,
4
+ generateStreamingServerSegmentAPIRoute,
5
+ } from '../src/api-route-generator'
6
+ import type { WorkflowSegment } from '../src/types'
7
+ import { loadServerRuntime } from './_helpers/load-server-runtime'
8
+ import { withEnv } from './_helpers/fake-fetch'
9
+
10
+ /**
11
+ * A loop inside the body of another loop runs all of its passes on every pass
12
+ * of the outer one. The server routes ran an outer body as one flat list: the
13
+ * inner loop node fell through to a stub and its body ran once per outer pass.
14
+ * Each route kind is booted here and run with nested loops.
15
+ */
16
+
17
+ const OUTER_ID = 'outer-1'
18
+ const MIDDLE_ID = 'middle-1'
19
+ const INNER_ID = 'inner-1'
20
+ const MAKE_ID = 'make-1'
21
+ const IF_ID = 'if-1'
22
+ const BODY_ID = 'body-1'
23
+ const HIGH_ID = 'high-1'
24
+ const LOW_ID = 'low-1'
25
+ const AFTER_ID = 'after-1'
26
+ const REPORT_ID = 'report-1'
27
+ const INNER_ITER_ID = INNER_ID + '_iter'
28
+ const RUNS_KEY = '__serverNestedLoopRuns'
29
+ const MADE_KEY = '__serverNestedLoopMade'
30
+
31
+ type GraphNode = Record<string, unknown> & { id: string }
32
+ type GraphEdge = Record<string, unknown> & { id: string; source: string; target: string }
33
+ interface Graph {
34
+ nodes: GraphNode[]
35
+ edges: GraphEdge[]
36
+ }
37
+ interface Run {
38
+ status: number
39
+ loopResult: (loopId: string) => unknown
40
+ }
41
+
42
+ const runs = (): unknown[] => (globalThis as Record<string, any>)[RUNS_KEY] || []
43
+
44
+ const loopNode = (id: string, stepNumber: number, config: Record<string, unknown>): GraphNode => ({
45
+ id,
46
+ type: 'general-loop',
47
+ config,
48
+ stepNumber,
49
+ label: id,
50
+ })
51
+
52
+ const recordingNode = (id: string, stepNumber: number): GraphNode => ({
53
+ id,
54
+ type: 'general-custom-js',
55
+ config: {
56
+ code: [
57
+ 'function customHandler() {',
58
+ ` globalThis.${RUNS_KEY} = (globalThis.${RUNS_KEY} || []).concat('${id}');`,
59
+ ` return { n: globalThis.${RUNS_KEY}.length };`,
60
+ '}',
61
+ ].join('\n'),
62
+ context: 'server',
63
+ },
64
+ stepNumber,
65
+ label: id,
66
+ })
67
+
68
+ const bodyEntry = (id: string, loopId: string, target: string): GraphEdge => ({
69
+ id,
70
+ source: loopId,
71
+ target,
72
+ sourceHandle: 'loop',
73
+ targetHandle: 'loop-body-in',
74
+ })
75
+
76
+ const loopBack = (id: string, source: string, loopId: string): GraphEdge => ({
77
+ id,
78
+ source,
79
+ target: loopId,
80
+ sourceHandle: 'loop-body-out',
81
+ targetHandle: 'loop-back',
82
+ })
83
+
84
+ const exitTo = (id: string, loopId: string, target: string): GraphEdge => ({
85
+ id,
86
+ source: loopId,
87
+ target,
88
+ sourceHandle: 'exit',
89
+ })
90
+
91
+ const forLoopInForLoop = (): Graph => ({
92
+ nodes: [
93
+ loopNode(OUTER_ID, 1, { loopType: 'for', endIndex: 2 }),
94
+ loopNode(INNER_ID, 2, { loopType: 'for', endIndex: 3 }),
95
+ recordingNode(BODY_ID, 3),
96
+ recordingNode(AFTER_ID, 4),
97
+ ],
98
+ edges: [
99
+ bodyEntry('e1', OUTER_ID, INNER_ID),
100
+ bodyEntry('e2', INNER_ID, BODY_ID),
101
+ loopBack('e3', BODY_ID, INNER_ID),
102
+ loopBack('e4', INNER_ID, OUTER_ID),
103
+ exitTo('e5', OUTER_ID, AFTER_ID),
104
+ ],
105
+ })
106
+
107
+ const threeLoopsDeep = (): Graph => ({
108
+ nodes: [
109
+ loopNode(OUTER_ID, 1, { loopType: 'for', endIndex: 2 }),
110
+ loopNode(MIDDLE_ID, 2, { loopType: 'forEach', collection: ['a', 'b'] }),
111
+ loopNode(INNER_ID, 3, { loopType: 'map', collection: ['x', 'y', 'z'] }),
112
+ recordingNode(BODY_ID, 4),
113
+ recordingNode(AFTER_ID, 5),
114
+ ],
115
+ edges: [
116
+ bodyEntry('e1', OUTER_ID, MIDDLE_ID),
117
+ bodyEntry('e2', MIDDLE_ID, INNER_ID),
118
+ bodyEntry('e3', INNER_ID, BODY_ID),
119
+ loopBack('e4', BODY_ID, INNER_ID),
120
+ loopBack('e5', INNER_ID, MIDDLE_ID),
121
+ loopBack('e6', MIDDLE_ID, OUTER_ID),
122
+ exitTo('e7', OUTER_ID, AFTER_ID),
123
+ ],
124
+ })
125
+
126
+ /**
127
+ * The outer body first makes a collection (one item on the first outer pass,
128
+ * two on the second), then walks it with the inner loop, whose body records
129
+ * the item it was handed.
130
+ */
131
+ const forEachOverWhatTheOuterPassMade = (): Graph => ({
132
+ nodes: [
133
+ loopNode(OUTER_ID, 1, { loopType: 'for', endIndex: 2 }),
134
+ {
135
+ id: MAKE_ID,
136
+ type: 'general-custom-js',
137
+ config: {
138
+ code: [
139
+ 'function customHandler() {',
140
+ ` globalThis.${MADE_KEY} = (globalThis.${MADE_KEY} || 0) + 1;`,
141
+ ` return { items: globalThis.${MADE_KEY} === 1 ? ['a'] : ['b', 'c'] };`,
142
+ '}',
143
+ ].join('\n'),
144
+ context: 'server',
145
+ },
146
+ stepNumber: 2,
147
+ label: 'Make The Items',
148
+ },
149
+ loopNode(INNER_ID, 3, {
150
+ loopType: 'forEach',
151
+ collection: { type: 'workflowContext', nodeId: MAKE_ID, path: [MAKE_ID, 'items'] },
152
+ }),
153
+ {
154
+ id: BODY_ID,
155
+ type: 'general-custom-js',
156
+ config: {
157
+ code: [
158
+ 'function customHandler(params) {',
159
+ ` globalThis.${RUNS_KEY} = (globalThis.${RUNS_KEY} || []).concat(params.item);`,
160
+ ' return { ok: true };',
161
+ '}',
162
+ ].join('\n'),
163
+ params: {
164
+ item: { type: 'workflowContext', nodeId: INNER_ID, path: [INNER_ID, 'currentItem'] },
165
+ },
166
+ context: 'server',
167
+ },
168
+ stepNumber: 4,
169
+ label: 'Record The Item',
170
+ },
171
+ ],
172
+ edges: [
173
+ bodyEntry('e1', OUTER_ID, MAKE_ID),
174
+ { id: 'e2', source: MAKE_ID, target: INNER_ID },
175
+ bodyEntry('e3', INNER_ID, BODY_ID),
176
+ loopBack('e4', BODY_ID, INNER_ID),
177
+ loopBack('e5', INNER_ID, OUTER_ID),
178
+ ],
179
+ })
180
+
181
+ const branchInTheInnerBody = (): Graph => ({
182
+ nodes: [
183
+ loopNode(OUTER_ID, 1, { loopType: 'for', endIndex: 2 }),
184
+ loopNode(INNER_ID, 2, { loopType: 'for', endIndex: 4 }),
185
+ {
186
+ id: IF_ID,
187
+ type: 'general-if-statement',
188
+ config: {
189
+ conditionType: 'simple-comparison',
190
+ leftValue: {
191
+ type: 'workflowContext',
192
+ nodeId: INNER_ITER_ID,
193
+ path: [INNER_ITER_ID, 'index'],
194
+ },
195
+ operator: '>=',
196
+ rightValue: 2,
197
+ },
198
+ stepNumber: 3,
199
+ label: 'Index Is High',
200
+ },
201
+ recordingNode(HIGH_ID, 4),
202
+ recordingNode(LOW_ID, 5),
203
+ recordingNode(AFTER_ID, 6),
204
+ ],
205
+ edges: [
206
+ bodyEntry('e1', OUTER_ID, INNER_ID),
207
+ bodyEntry('e2', INNER_ID, IF_ID),
208
+ { id: 'e3', source: IF_ID, target: HIGH_ID, sourceHandle: 'true' },
209
+ { id: 'e4', source: IF_ID, target: LOW_ID, sourceHandle: 'false' },
210
+ loopBack('e5', HIGH_ID, INNER_ID),
211
+ loopBack('e6', LOW_ID, INNER_ID),
212
+ loopBack('e7', INNER_ID, OUTER_ID),
213
+ exitTo('e8', OUTER_ID, AFTER_ID),
214
+ ],
215
+ })
216
+
217
+ const requireRuntime = (extra: Record<string, unknown> = {}) => {
218
+ const runtime = loadServerRuntime()
219
+ return (id: string): unknown => {
220
+ if (id.endsWith('/utils/workflows/server-runtime')) {
221
+ return runtime
222
+ }
223
+ const known = Object.keys(extra).find((suffix) => id.endsWith(suffix))
224
+ if (known) {
225
+ return extra[known]
226
+ }
227
+ throw new Error('Unexpected require: ' + id)
228
+ }
229
+ }
230
+
231
+ const bootRoute = (source: string, requireFn: (id: string) => unknown) => {
232
+ const routeModule: { exports: any } = { exports: {} }
233
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
234
+ new Function('module', 'exports', 'require', source)(routeModule, routeModule.exports, requireFn)
235
+ return routeModule.exports as (req: unknown, res: unknown) => Promise<void>
236
+ }
237
+
238
+ const jsonReply = () => {
239
+ const reply = { status: 0, body: undefined as any }
240
+ const res = {
241
+ status(code: number) {
242
+ reply.status = code
243
+ return this
244
+ },
245
+ json(payload: unknown) {
246
+ reply.body = payload
247
+ return this
248
+ },
249
+ setHeader: (): void => undefined,
250
+ }
251
+ return { reply, res }
252
+ }
253
+
254
+ const runSegmentRoute =
255
+ (generate: (segment: WorkflowSegment) => string) =>
256
+ async (graph: Graph): Promise<Run> => {
257
+ const segment = {
258
+ id: 'seg-nested-loops',
259
+ env: 'server',
260
+ nodeIds: graph.nodes.map((node) => node.id),
261
+ nodes: graph.nodes,
262
+ edges: graph.edges,
263
+ } as unknown as WorkflowSegment
264
+ const handler = bootRoute(generate(segment), requireRuntime())
265
+ const { reply, res } = jsonReply()
266
+ await handler({ method: 'POST', body: { context: {} }, headers: { host: 'site.example' } }, res)
267
+ return { status: reply.status, loopResult: (loopId) => reply.body.results[loopId] }
268
+ }
269
+
270
+ /**
271
+ * A scheduled route replies with no results, so its last step is a custom node
272
+ * that is handed the result of every loop of the graph.
273
+ */
274
+ const runScheduledRoute = async (graph: Graph): Promise<Run> => {
275
+ const loopIds = graph.nodes.filter((node) => node.type === 'general-loop').map((node) => node.id)
276
+ const parameters: Record<string, unknown> = {}
277
+ loopIds.forEach((loopId) => {
278
+ parameters[loopId] = { type: 'workflowContext', nodeId: loopId, path: [loopId] }
279
+ })
280
+ const reportNode = {
281
+ id: REPORT_ID,
282
+ type: 'general-custom-node',
283
+ config: { customNodeId: 'cn-report', parameters },
284
+ stepNumber: graph.nodes.length + 1,
285
+ label: 'Report The Loops',
286
+ }
287
+ const workflow: any = {
288
+ id: 'wf-scheduled-nested-loops',
289
+ name: 'Scheduled Nested Loops',
290
+ trigger: {
291
+ type: 'event-cron-triggered',
292
+ nodeId: 't',
293
+ scope: 'global',
294
+ config: { schedule: '5 * * * *', urlPath: 'cron_nested_loops' },
295
+ },
296
+ nodes: [...graph.nodes, reportNode],
297
+ edges: [
298
+ { id: 'e0', source: 't', target: OUTER_ID },
299
+ ...graph.edges,
300
+ exitTo('e-report', OUTER_ID, REPORT_ID),
301
+ ],
302
+ }
303
+ const customNodes: Record<string, unknown> = {
304
+ 'cn-report': { id: 'cn-report', name: 'Report', nodes: [], edges: [] },
305
+ }
306
+ let reported: Record<string, unknown> = {}
307
+ const customNodeModule = {
308
+ 'cn-report': async (_context: unknown, handed: Record<string, unknown>) => {
309
+ reported = handed
310
+ return { ok: true }
311
+ },
312
+ }
313
+ const handler = bootRoute(
314
+ generateCronAPIRoute(workflow, customNodes as never),
315
+ requireRuntime({ '/utils/workflows/custom-nodes': customNodeModule })
316
+ )
317
+ const { reply, res } = jsonReply()
318
+ const req = {
319
+ method: 'POST',
320
+ url: '/api/workflows/cron_nested_loops',
321
+ headers: { host: 'site.example', 'x-forwarded-proto': 'https' },
322
+ body: {},
323
+ }
324
+ await withEnv({ TELEPORT_CRON_ALLOW_UNSIGNED: 'true', TELEPORT_CRON_SECRET: undefined }, () =>
325
+ handler(req, res)
326
+ )
327
+ return { status: reply.status, loopResult: (loopId) => reported[loopId] }
328
+ }
329
+
330
+ const clearRecordings = () => {
331
+ delete (globalThis as Record<string, any>)[RUNS_KEY]
332
+ delete (globalThis as Record<string, any>)[MADE_KEY]
333
+ }
334
+
335
+ beforeEach(clearRecordings)
336
+ afterAll(clearRecordings)
337
+
338
+ describe.each<[string, (graph: Graph) => Promise<Run>]>([
339
+ ['a server segment route', runSegmentRoute(generateServerSegmentAPIRoute)],
340
+ ['a streaming server segment route', runSegmentRoute(generateStreamingServerSegmentAPIRoute)],
341
+ ['a scheduled route', runScheduledRoute],
342
+ ])('%s runs a loop inside a loop', (_route, run) => {
343
+ it('runs every pass of the inner loop on every pass of the outer loop', async () => {
344
+ const result = await run(forLoopInForLoop())
345
+
346
+ expect(result.status).toBe(200)
347
+ expect(runs()).toEqual([BODY_ID, BODY_ID, BODY_ID, BODY_ID, BODY_ID, BODY_ID, AFTER_ID])
348
+ expect(result.loopResult(OUTER_ID)).toEqual({ completed: true, iterations: 2, results: [] })
349
+ expect(result.loopResult(INNER_ID)).toEqual({ completed: true, iterations: 3, results: [] })
350
+ })
351
+
352
+ it('runs a loop in a loop in a loop', async () => {
353
+ const result = await run(threeLoopsDeep())
354
+
355
+ expect(result.status).toBe(200)
356
+ expect(runs()).toEqual([...Array(12).fill(BODY_ID), AFTER_ID])
357
+ expect(result.loopResult(OUTER_ID)).toEqual({ completed: true, iterations: 2, results: [] })
358
+ expect(result.loopResult(MIDDLE_ID)).toEqual({ completed: true, iterations: 2, results: [] })
359
+ expect(result.loopResult(INNER_ID)).toEqual({
360
+ completed: true,
361
+ iterations: 3,
362
+ results: [{ n: 10 }, { n: 11 }, { n: 12 }],
363
+ })
364
+ })
365
+
366
+ it('walks the collection the current outer pass made', async () => {
367
+ const result = await run(forEachOverWhatTheOuterPassMade())
368
+
369
+ expect(result.status).toBe(200)
370
+ expect(runs()).toEqual(['a', 'b', 'c'])
371
+ expect(result.loopResult(OUTER_ID)).toEqual({ completed: true, iterations: 2, results: [] })
372
+ expect(result.loopResult(INNER_ID)).toEqual({ completed: true, iterations: 2, results: [] })
373
+ })
374
+
375
+ it('takes one branch of the inner body per inner pass', async () => {
376
+ const result = await run(branchInTheInnerBody())
377
+
378
+ expect(result.status).toBe(200)
379
+ expect(runs()).toEqual([
380
+ LOW_ID,
381
+ LOW_ID,
382
+ HIGH_ID,
383
+ HIGH_ID,
384
+ LOW_ID,
385
+ LOW_ID,
386
+ HIGH_ID,
387
+ HIGH_ID,
388
+ AFTER_ID,
389
+ ])
390
+ expect(result.loopResult(INNER_ID)).toEqual({ completed: true, iterations: 4, results: [] })
391
+ })
392
+ })
@@ -0,0 +1,107 @@
1
+ import { generateStreamingServerSegmentAPIRoute } from '../src/api-route-generator'
2
+ import type { WorkflowSegment } from '../src/types'
3
+ import { loadServerRuntime } from './_helpers/load-server-runtime'
4
+
5
+ /**
6
+ * A streaming segment route evaluated an if-statement and then ran both of its
7
+ * branches: it never recorded the branch not taken, and never read the record
8
+ * a switch made of its unmatched cases.
9
+ */
10
+
11
+ const RUNS_KEY = '__streamingIfBranchRuns'
12
+
13
+ const runs = (): string[] => (globalThis as Record<string, any>)[RUNS_KEY] || []
14
+
15
+ const recordingNode = (id: string, stepNumber: number) => ({
16
+ id,
17
+ type: 'general-custom-js',
18
+ config: {
19
+ code: [
20
+ 'function customHandler() {',
21
+ ` globalThis.${RUNS_KEY} = (globalThis.${RUNS_KEY} || []).concat('${id}');`,
22
+ ' return { ok: true };',
23
+ '}',
24
+ ].join('\n'),
25
+ context: 'server',
26
+ },
27
+ stepNumber,
28
+ label: id,
29
+ })
30
+
31
+ const segmentWhere = (leftValue: number): WorkflowSegment =>
32
+ ({
33
+ id: 'seg-if',
34
+ env: 'server',
35
+ nodeIds: ['if-1', 'yes-1', 'no-1'],
36
+ nodes: [
37
+ {
38
+ id: 'if-1',
39
+ type: 'general-if-statement',
40
+ config: { conditionType: 'simple-comparison', leftValue, operator: '===', rightValue: 1 },
41
+ stepNumber: 1,
42
+ label: 'Is One',
43
+ },
44
+ recordingNode('yes-1', 2),
45
+ recordingNode('no-1', 3),
46
+ ],
47
+ edges: [
48
+ { id: 'e1', source: 'if-1', target: 'yes-1', sourceHandle: 'true' },
49
+ { id: 'e2', source: 'if-1', target: 'no-1', sourceHandle: 'false' },
50
+ ],
51
+ } as unknown as WorkflowSegment)
52
+
53
+ const run = async (segment: WorkflowSegment) => {
54
+ const runtime = loadServerRuntime()
55
+ const routeModule: { exports: any } = { exports: {} }
56
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
57
+ new Function('module', 'exports', 'require', generateStreamingServerSegmentAPIRoute(segment))(
58
+ routeModule,
59
+ routeModule.exports,
60
+ (id: string): unknown => {
61
+ if (id.endsWith('/utils/workflows/server-runtime')) {
62
+ return runtime
63
+ }
64
+ throw new Error('Unexpected require: ' + id)
65
+ }
66
+ )
67
+ const reply = { status: 0 }
68
+ const res = {
69
+ status(code: number) {
70
+ reply.status = code
71
+ return this
72
+ },
73
+ json() {
74
+ return this
75
+ },
76
+ setHeader: (): void => undefined,
77
+ }
78
+ await routeModule.exports(
79
+ { method: 'POST', body: { context: {} }, headers: { host: 'site.example' } },
80
+ res
81
+ )
82
+ return reply
83
+ }
84
+
85
+ beforeEach(() => {
86
+ delete (globalThis as Record<string, any>)[RUNS_KEY]
87
+ })
88
+
89
+ afterAll(() => {
90
+ delete (globalThis as Record<string, any>)[RUNS_KEY]
91
+ })
92
+
93
+ describe('a streaming server segment route runs one branch of an if-statement', () => {
94
+ it('runs only the true branch when the condition holds', async () => {
95
+ const reply = await run(segmentWhere(1))
96
+
97
+ expect(reply.status).toBe(200)
98
+ expect(runs()).toEqual(['yes-1'])
99
+ })
100
+
101
+ it('runs only the false branch when it does not', async () => {
102
+ const reply = await run(segmentWhere(2))
103
+
104
+ expect(reply.status).toBe(200)
105
+ expect(runs()).toEqual(['no-1'])
106
+ })
107
+ })
@@ -1 +1 @@
1
- {"version":3,"file":"api-route-generator.d.ts","sourceRoot":"","sources":["../../src/api-route-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EAGb,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAuEvE,MAAM,WAAW,yBAAyB;IACxC,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;;OAIG;IACH,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;CACrD;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAA;AAEhC,wEAAwE;AACxE,eAAO,MAAM,wBAAwB;;;CAAiC,CAAA;AAEtE,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,4CAA4C,CAAA;AA+O7E,eAAO,MAAM,6BAA6B,YAC/B,eAAe,iBACT,MAAM,eACR,sBAAsB,YAC1B,yBAAyB,KACjC,MAyXF,CAAA;AAED,eAAO,MAAM,kBAAkB,YAAa,eAAe,KAAG,OAE7D,CAAA;AAED,eAAO,MAAM,sCAAsC,YACxC,eAAe,iBACT,MAAM,eACR,sBAAsB,YAC1B,yBAAyB,KACjC,MAycF,CAAA;AA6ID;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,aA4D5B,CAAA;AAEF,qDAAqD;AACrD,MAAM,WAAW,0BAA0B;IACzC,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAqBD,eAAO,MAAM,oBAAoB,aACrB,YAAY,gBACR,OAAO,MAAM,EAAE,sBAAsB,CAAC,YAC3C,0BAA0B,KAClC,MA0HF,CAAA;AAED,eAAO,MAAM,mBAAmB,eAClB,MAAM,aACP,MAAM,iBACF,MAAM,KACpB,MA4BF,CAAA;AAED,eAAO,MAAM,oBAAoB,aAAc,YAAY,KAAG,MAa7D,CAAA;AAsTD,uHAAuH;AACvH,eAAO,MAAM,uBAAuB,kBAAmB,iBAAiB,KAAG,OAES,CAAA;AAEpF,eAAO,MAAM,+BAA+B,aAChC,YAAY,gBACR,OAAO,MAAM,EAAE,sBAAsB,CAAC,YAC3C,0BAA0B,KAClC,MAkOF,CAAA;AAkED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,uBAAuB,aACxB,YAAY,gBACR,OAAO,MAAM,EAAE,sBAAsB,CAAC,KACnD,MA8KF,CAAA;AAED,eAAO,MAAM,uBAAuB,aAAc,YAAY,KAAG,MAiBhE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,cAC1B,aAAa,GAAG,SAAS,cACxB,MAAM,KACjB,MAAM,GAAG,IAYX,CAAA;AAED,eAAO,MAAM,mBAAmB,aAAc,YAAY,KAAG,MAAM,EAqBlE,CAAA"}
1
+ {"version":3,"file":"api-route-generator.d.ts","sourceRoot":"","sources":["../../src/api-route-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EAGb,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAuEvE,MAAM,WAAW,yBAAyB;IACxC,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;;OAIG;IACH,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;CACrD;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAA;AAEhC,wEAAwE;AACxE,eAAO,MAAM,wBAAwB;;;CAAiC,CAAA;AAEtE,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,4CAA4C,CAAA;AA+O7E,eAAO,MAAM,6BAA6B,YAC/B,eAAe,iBACT,MAAM,eACR,sBAAsB,YAC1B,yBAAyB,KACjC,MAuSF,CAAA;AAED,eAAO,MAAM,kBAAkB,YAAa,eAAe,KAAG,OAE7D,CAAA;AAED,eAAO,MAAM,sCAAsC,YACxC,eAAe,iBACT,MAAM,eACR,sBAAsB,YAC1B,yBAAyB,KACjC,MA+ZF,CAAA;AA6ID;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,aA4D5B,CAAA;AAEF,qDAAqD;AACrD,MAAM,WAAW,0BAA0B;IACzC,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAqBD,eAAO,MAAM,oBAAoB,aACrB,YAAY,gBACR,OAAO,MAAM,EAAE,sBAAsB,CAAC,YAC3C,0BAA0B,KAClC,MA0HF,CAAA;AAED,eAAO,MAAM,mBAAmB,eAClB,MAAM,aACP,MAAM,iBACF,MAAM,KACpB,MA4BF,CAAA;AAED,eAAO,MAAM,oBAAoB,aAAc,YAAY,KAAG,MAa7D,CAAA;AAmPD,uHAAuH;AACvH,eAAO,MAAM,uBAAuB,kBAAmB,iBAAiB,KAAG,OAES,CAAA;AAEpF,eAAO,MAAM,+BAA+B,aAChC,YAAY,gBACR,OAAO,MAAM,EAAE,sBAAsB,CAAC,YAC3C,0BAA0B,KAClC,MAkOF,CAAA;AAkED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,uBAAuB,aACxB,YAAY,gBACR,OAAO,MAAM,EAAE,sBAAsB,CAAC,KACnD,MA8KF,CAAA;AAED,eAAO,MAAM,uBAAuB,aAAc,YAAY,KAAG,MAiBhE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,cAC1B,aAAa,GAAG,SAAS,cACxB,MAAM,KACjB,MAAM,GAAG,IAYX,CAAA;AAED,eAAO,MAAM,mBAAmB,aAAc,YAAY,KAAG,MAAM,EAqBlE,CAAA"}