@teleporthq/teleport-plugin-next-workflows 0.43.34 → 0.43.36
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__/ai-error-contract.test.ts +149 -0
- package/__tests__/data-api-safe-query.test.ts +16 -16
- package/__tests__/global-workflows-handler-map-integrity.test.ts +85 -0
- package/__tests__/node-handler-file-inline-map.test.ts +114 -0
- package/__tests__/raw-query-param-binding.test.ts +18 -17
- package/__tests__/streaming-on-end-env-filter.test.ts +405 -0
- package/dist/cjs/api-route-generator.d.ts.map +1 -1
- package/dist/cjs/api-route-generator.js +14 -8
- package/dist/cjs/api-route-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 +13 -2
- package/dist/cjs/data-api-route-generator.js.map +1 -1
- package/dist/cjs/executor-generator.d.ts.map +1 -1
- package/dist/cjs/executor-generator.js +47 -5
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/nodes/general/general-custom-js.d.ts.map +1 -1
- package/dist/cjs/nodes/general/general-custom-js.js +7 -0
- package/dist/cjs/nodes/general/general-custom-js.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/workflow-component-plugin.js +9 -3
- package/dist/cjs/workflow-component-plugin.js.map +1 -1
- package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-project-plugin.js +61 -6
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/esm/api-route-generator.d.ts.map +1 -1
- package/dist/esm/api-route-generator.js +14 -8
- package/dist/esm/api-route-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 +13 -2
- package/dist/esm/data-api-route-generator.js.map +1 -1
- package/dist/esm/executor-generator.d.ts.map +1 -1
- package/dist/esm/executor-generator.js +47 -5
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/nodes/general/general-custom-js.d.ts.map +1 -1
- package/dist/esm/nodes/general/general-custom-js.js +7 -0
- package/dist/esm/nodes/general/general-custom-js.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/workflow-component-plugin.js +9 -3
- package/dist/esm/workflow-component-plugin.js.map +1 -1
- package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-project-plugin.js +61 -6
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/package.json +2 -2
- package/src/api-route-generator.ts +14 -8
- package/src/data-api-route-generator.ts +13 -2
- package/src/executor-generator.ts +47 -5
- package/src/nodes/general/general-custom-js.ts +8 -0
- package/src/workflow-component-plugin.ts +15 -10
- package/src/workflow-project-plugin.ts +60 -5
|
@@ -331,8 +331,8 @@ module.exports = async function handler(req, res) {
|
|
|
331
331
|
res.status(earlyRes.status || 500).json(earlyRes.body || {});
|
|
332
332
|
return;
|
|
333
333
|
}
|
|
334
|
-
if (
|
|
335
|
-
throw new Error(result
|
|
334
|
+
if (utils.isFatalNodeResult(result)) {
|
|
335
|
+
throw new Error(utils.fatalNodeResultMessage(result));
|
|
336
336
|
}
|
|
337
337
|
context[node.id] = result;
|
|
338
338
|
if (result && result.__terminal) break;
|
|
@@ -680,6 +680,12 @@ module.exports = async function handler(req, res) {
|
|
|
680
680
|
res.write('data: ' + JSON.stringify({ type: 'node-result', nodeId: sn.id, result: snResult }) + '\\n\\n');
|
|
681
681
|
}
|
|
682
682
|
});
|
|
683
|
+
// A provider/auth failure surfaces as { error: true, message, code }.
|
|
684
|
+
// Without this gate the on-end branch would run against a failed AI
|
|
685
|
+
// result (e.g. persist a NULL chat answer → NOT NULL 500 downstream).
|
|
686
|
+
if (utils.isFatalNodeResult(result)) {
|
|
687
|
+
throw new Error(utils.fatalNodeResultMessage(result));
|
|
688
|
+
}
|
|
683
689
|
context[node.id] = result;
|
|
684
690
|
res.write('data: ' + JSON.stringify({ type: 'node-result', nodeId: node.id, result: result }) + '\\n\\n');
|
|
685
691
|
|
|
@@ -712,8 +718,8 @@ module.exports = async function handler(req, res) {
|
|
|
712
718
|
}
|
|
713
719
|
return;
|
|
714
720
|
}
|
|
715
|
-
if (
|
|
716
|
-
throw new Error(result
|
|
721
|
+
if (utils.isFatalNodeResult(result)) {
|
|
722
|
+
throw new Error(utils.fatalNodeResultMessage(result));
|
|
717
723
|
}
|
|
718
724
|
context[node.id] = result;
|
|
719
725
|
if (streamStarted) {
|
|
@@ -925,8 +931,8 @@ module.exports = async function handler(req, res) {
|
|
|
925
931
|
res.status(earlyRes.status || 500).json(earlyRes.body || {});
|
|
926
932
|
return;
|
|
927
933
|
}
|
|
928
|
-
if (
|
|
929
|
-
throw new Error(result
|
|
934
|
+
if (utils.isFatalNodeResult(result)) {
|
|
935
|
+
throw new Error(utils.fatalNodeResultMessage(result));
|
|
930
936
|
}
|
|
931
937
|
context[node.id] = result;
|
|
932
938
|
if (result && result.__terminal) break;
|
|
@@ -1225,8 +1231,8 @@ const generateNodeExecutionLoop = (
|
|
|
1225
1231
|
res.status(earlyRes.status || 500).json(earlyRes.body || {});
|
|
1226
1232
|
return;
|
|
1227
1233
|
}${customNodeBlock}
|
|
1228
|
-
if (
|
|
1229
|
-
throw new Error(result
|
|
1234
|
+
if (utils.isFatalNodeResult(result)) {
|
|
1235
|
+
throw new Error(utils.fatalNodeResultMessage(result));
|
|
1230
1236
|
}
|
|
1231
1237
|
context[node.id] = result;
|
|
1232
1238
|
if (result && result.__terminal) break;
|
|
@@ -159,12 +159,23 @@ function validateFilters(filters) {
|
|
|
159
159
|
// 22003 (numeric value out of range), 22023 (invalid parameter value).
|
|
160
160
|
// We pass the original query / params back to the caller as a debug
|
|
161
161
|
// label so log output stays diagnosable.
|
|
162
|
-
|
|
162
|
+
// Also covers 22007 (invalid_datetime_format — an empty "Filter by date" value
|
|
163
|
+
// hitting a date column: invalid input syntax for type date). Beyond the code
|
|
164
|
+
// list we ALSO suppress ANY "invalid input syntax for type" message: every one
|
|
165
|
+
// means the bound value could never coerce to the column type, so no row can
|
|
166
|
+
// match and an empty result is the correct semantics — never a 500 the user sees
|
|
167
|
+
// as "Failed to update. Please try again".
|
|
168
|
+
var SAFE_COERCION_ERROR_CODES = { '22P02': 1, '22007': 1, '22008': 1, '22003': 1, '22023': 1 };
|
|
169
|
+
function isSafeCoercionError(err) {
|
|
170
|
+
if (!err) return false;
|
|
171
|
+
if (SAFE_COERCION_ERROR_CODES[err.code]) return true;
|
|
172
|
+
return typeof err.message === 'string' && /invalid input syntax for type/i.test(err.message);
|
|
173
|
+
}
|
|
163
174
|
async function safeQuery(client, sql, params, mode) {
|
|
164
175
|
try {
|
|
165
176
|
return await client.query(sql, params);
|
|
166
177
|
} catch (err) {
|
|
167
|
-
if (err
|
|
178
|
+
if (isSafeCoercionError(err)) {
|
|
168
179
|
console.warn('[data-api] suppressed Postgres coercion error (' + err.code + '): ' + (err.message || err) +
|
|
169
180
|
' — returning empty result for ' + (mode || 'query') + '. SQL=' + sql + ' params=' + JSON.stringify(params));
|
|
170
181
|
if (mode === 'count') {
|
|
@@ -586,6 +586,24 @@ function topoSortNodes(nodes, edges) {
|
|
|
586
586
|
return sorted;
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
+
// A node result signals failure either through the legacy string contract
|
|
590
|
+
// ({ error: '...' } / { success: false }) or through the AI-node contract
|
|
591
|
+
// ({ error: true, message, code } — provider/auth failures). Both must halt
|
|
592
|
+
// the workflow; treating error:true as success used to let the pipeline limp
|
|
593
|
+
// into downstream NOT NULL violations.
|
|
594
|
+
function isFatalNodeResult(result) {
|
|
595
|
+
if (!result) return false;
|
|
596
|
+
return result.success === false ||
|
|
597
|
+
(typeof result.error === 'string' && result.error) ||
|
|
598
|
+
result.error === true;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function fatalNodeResultMessage(result) {
|
|
602
|
+
if (typeof result.error === 'string' && result.error) return result.error;
|
|
603
|
+
if (typeof result.message === 'string' && result.message) return result.message;
|
|
604
|
+
return 'Node execution failed';
|
|
605
|
+
}
|
|
606
|
+
|
|
589
607
|
async function executeNodes(nodes, edges, context, nodeHandlers, workflowConfig, callServerSegment, executionId) {
|
|
590
608
|
const executed = {};
|
|
591
609
|
const sortedNodes = topoSortNodes(nodes, edges);
|
|
@@ -684,6 +702,9 @@ async function executeNodes(nodes, edges, context, nodeHandlers, workflowConfig,
|
|
|
684
702
|
await executeNodes(onStreamNodes, edges, context, nodeHandlers, workflowConfig, callServerSegment, executionId);
|
|
685
703
|
}
|
|
686
704
|
});
|
|
705
|
+
if (isFatalNodeResult(streamResult)) {
|
|
706
|
+
throw new Error(fatalNodeResultMessage(streamResult));
|
|
707
|
+
}
|
|
687
708
|
context[node.id] = streamResult;
|
|
688
709
|
|
|
689
710
|
if (onEndNodes.length > 0) {
|
|
@@ -726,8 +747,8 @@ async function executeNodes(nodes, edges, context, nodeHandlers, workflowConfig,
|
|
|
726
747
|
throw earlyErr;
|
|
727
748
|
}
|
|
728
749
|
|
|
729
|
-
if (
|
|
730
|
-
throw new Error(result
|
|
750
|
+
if (isFatalNodeResult(result)) {
|
|
751
|
+
throw new Error(fatalNodeResultMessage(result));
|
|
731
752
|
}
|
|
732
753
|
|
|
733
754
|
context[node.id] = result;
|
|
@@ -1006,7 +1027,9 @@ module.exports = {
|
|
|
1006
1027
|
executeParallel,
|
|
1007
1028
|
collectBranchNodes,
|
|
1008
1029
|
markAllBranchNodes,
|
|
1009
|
-
isStreamingAINode
|
|
1030
|
+
isStreamingAINode,
|
|
1031
|
+
isFatalNodeResult,
|
|
1032
|
+
fatalNodeResultMessage
|
|
1010
1033
|
};
|
|
1011
1034
|
`
|
|
1012
1035
|
}
|
|
@@ -1200,6 +1223,19 @@ function findStreamingAINodes(allNodes, allEdges) {
|
|
|
1200
1223
|
return map;
|
|
1201
1224
|
}
|
|
1202
1225
|
|
|
1226
|
+
// A streaming AI node's on-stream / on-end branches are collected from the
|
|
1227
|
+
// FULL workflow node list, so they may contain server nodes (e.g. the SQL
|
|
1228
|
+
// insert persisting a chat answer). Those already execute inside their own
|
|
1229
|
+
// server segments with full configs; the browser bundle only ships their
|
|
1230
|
+
// config redacted down to the client-safe whitelist (segment-splitter's
|
|
1231
|
+
// redactServerNodeConfig), so executing them here with CLIENT handlers both
|
|
1232
|
+
// double-executes them and crashes on the missing config. Emitted nodes carry
|
|
1233
|
+
// executionEnv for exactly this filter; nodes without the marker (older
|
|
1234
|
+
// bundles) keep executing client-side as before.
|
|
1235
|
+
function clientExecutableBranchNodes(branchNodes) {
|
|
1236
|
+
return branchNodes.filter(function(n) { return !n || n.executionEnv !== 'server'; });
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1203
1239
|
async function callStreamingServerSegment(segmentUrl, context, streamingInfo, allNodes, allEdges, clientHandlers, workflowConfig, executionId) {
|
|
1204
1240
|
const prunedContext = pruneContext(context);
|
|
1205
1241
|
const handledNodeIds = {};
|
|
@@ -1254,7 +1290,10 @@ async function callStreamingServerSegment(segmentUrl, context, streamingInfo, al
|
|
|
1254
1290
|
context[data.nodeId] = { chunk: data.chunk, fullResponse: data.fullResponse, model: data.model };
|
|
1255
1291
|
const info = streamingInfo[data.nodeId];
|
|
1256
1292
|
if (info && info.onStreamNodes.length > 0) {
|
|
1257
|
-
|
|
1293
|
+
const runnableStreamNodes = clientExecutableBranchNodes(info.onStreamNodes);
|
|
1294
|
+
if (runnableStreamNodes.length > 0) {
|
|
1295
|
+
await utils.executeNodes(runnableStreamNodes, allEdges, context, clientHandlers, workflowConfig, null, executionId);
|
|
1296
|
+
}
|
|
1258
1297
|
for (let sni = 0; sni < info.onStreamNodes.length; sni++) {
|
|
1259
1298
|
handledNodeIds[info.onStreamNodes[sni].id] = true;
|
|
1260
1299
|
}
|
|
@@ -1269,7 +1308,10 @@ async function callStreamingServerSegment(segmentUrl, context, streamingInfo, al
|
|
|
1269
1308
|
for (let sk = 0; sk < streamedKeys.length; sk++) {
|
|
1270
1309
|
const endInfo = streamingInfo[streamedKeys[sk]];
|
|
1271
1310
|
if (endInfo && endInfo.onEndNodes.length > 0) {
|
|
1272
|
-
|
|
1311
|
+
const runnableEndNodes = clientExecutableBranchNodes(endInfo.onEndNodes);
|
|
1312
|
+
if (runnableEndNodes.length > 0) {
|
|
1313
|
+
await utils.executeNodes(runnableEndNodes, allEdges, context, clientHandlers, workflowConfig, null, executionId);
|
|
1314
|
+
}
|
|
1273
1315
|
for (let eni = 0; eni < endInfo.onEndNodes.length; eni++) {
|
|
1274
1316
|
handledNodeIds[endInfo.onEndNodes[eni].id] = true;
|
|
1275
1317
|
}
|
|
@@ -23,6 +23,14 @@ import { NodeHandlerGenerator, handlerToString } from '../types'
|
|
|
23
23
|
async function general_custom_js(config: any, context: Record<string, unknown>) {
|
|
24
24
|
const code = config.code
|
|
25
25
|
|
|
26
|
+
// A server-classified custom-js node's config is redacted to the client-safe
|
|
27
|
+
// whitelist ({} here) before it ships to the browser. If such a node ever
|
|
28
|
+
// reaches a client handler (defense-in-depth — the runtime filters them),
|
|
29
|
+
// no-op cleanly instead of crashing the whole workflow on `code.length`.
|
|
30
|
+
if (typeof code !== 'string' || code.length === 0) {
|
|
31
|
+
return {}
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
// Reserved context keys that must never leak into params / innerParams.
|
|
27
35
|
// Anything starting with "__" is internal scaffolding; these named entries
|
|
28
36
|
// are existing well-known runtime keys.
|
|
@@ -1308,16 +1308,21 @@ function __normalizeAdminFormRow(row, defaults) {
|
|
|
1308
1308
|
}))
|
|
1309
1309
|
)
|
|
1310
1310
|
const nodesJson = JSON.stringify(
|
|
1311
|
-
wf.nodes.map((n: UIDLWorkflowNode) =>
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1311
|
+
wf.nodes.map((n: UIDLWorkflowNode) => {
|
|
1312
|
+
// Runtime marker consumed by clientExecutableBranchNodes (client
|
|
1313
|
+
// runtime): a streaming AI node's on-stream/on-end branches are
|
|
1314
|
+
// collected from this full node list, and server nodes in them must
|
|
1315
|
+
// never execute with client handlers (their config is redacted below).
|
|
1316
|
+
const env = nodeEnvById.get(n.id) ?? resolveNodeExecutionEnv(n)
|
|
1317
|
+
return {
|
|
1318
|
+
id: n.id,
|
|
1319
|
+
type: n.type,
|
|
1320
|
+
config: redactServerNodeConfig(n.config, env),
|
|
1321
|
+
stepNumber: n.stepNumber,
|
|
1322
|
+
label: n.label,
|
|
1323
|
+
executionEnv: env,
|
|
1324
|
+
}
|
|
1325
|
+
})
|
|
1321
1326
|
)
|
|
1322
1327
|
const edgesJson = JSON.stringify(
|
|
1323
1328
|
wf.edges.map((e: UIDLWorkflowEdge) => ({
|
|
@@ -887,14 +887,45 @@ export class NextWorkflowProjectPlugin implements ProjectPlugin {
|
|
|
887
887
|
return ''
|
|
888
888
|
}
|
|
889
889
|
|
|
890
|
-
|
|
890
|
+
// Inline each handler as its `module.exports` map value inside a
|
|
891
|
+
// self-invoking function that returns the handler's entry-point, rather
|
|
892
|
+
// than emitting separate top-level `async function <name>` declarations
|
|
893
|
+
// plus a map that references them by name. `handlers` and `exportNames`
|
|
894
|
+
// are populated together in the loop above, so `handlers[index]` is
|
|
895
|
+
// exactly the handler for `exportNames[index]`.
|
|
896
|
+
//
|
|
897
|
+
// Why the IIFE (not a bare inline expression): a handler is NOT always a
|
|
898
|
+
// single function expression. AI nodes emit shared provider utils
|
|
899
|
+
// (`var __ai_… = …`) BEFORE their entry function, and payment/rate-limiter
|
|
900
|
+
// nodes append helper functions AFTER it. Splicing such a multi-statement
|
|
901
|
+
// string directly as an object-literal value (`'ai-custom-prompt': var … `)
|
|
902
|
+
// is a SyntaxError. Wrapping in `(function () { <handler>; return <fn>; })()`
|
|
903
|
+
// runs every statement in an isolated scope and yields the entry function as
|
|
904
|
+
// the value — so single- AND multi-statement handlers are both valid.
|
|
905
|
+
//
|
|
906
|
+
// Why not top-level declarations + a name reference: that forward-reference
|
|
907
|
+
// shape is fragile in production. If a bundler/minifier drops a single-use
|
|
908
|
+
// declaration (or a handler's emitted name ever drifts from its
|
|
909
|
+
// `nodeType`-derived key), the map is left referencing an undefined
|
|
910
|
+
// identifier — `ReferenceError: <name> is not defined` at MODULE-EVAL time,
|
|
911
|
+
// which fails the Next.js/Vercel build during "Collecting page data". The
|
|
912
|
+
// returned identifier is derived from the same `t` that keys the map and is
|
|
913
|
+
// defined by the handler string right above the `return`, so there is no
|
|
914
|
+
// cross-statement forward reference to dangle. The entry-function naming
|
|
915
|
+
// contract (`handlerToString(fn)` preserves `fn.name`, and every handler
|
|
916
|
+
// names its entry `nodeType.replace(/-/g, '_')`) is enforced by
|
|
917
|
+
// node-handler-file-inline-map.test.ts across the whole node registry.
|
|
918
|
+
const entries = exportNames
|
|
919
|
+
.map((t, index) => {
|
|
920
|
+
const entryFn = t.replace(/-/g, '_')
|
|
921
|
+
return ` '${t}': (function () {\n${handlers[index].trim()}\nreturn ${entryFn};\n})()`
|
|
922
|
+
})
|
|
923
|
+
.join(',\n')
|
|
891
924
|
|
|
892
925
|
return `// Auto-generated workflow node handlers (${env})
|
|
893
926
|
|
|
894
|
-
${handlers.join('\n\n')}
|
|
895
|
-
|
|
896
927
|
module.exports = {
|
|
897
|
-
${
|
|
928
|
+
${entries}
|
|
898
929
|
};
|
|
899
930
|
`
|
|
900
931
|
}
|
|
@@ -972,6 +1003,10 @@ ${exports}
|
|
|
972
1003
|
(cn.nodes || []).map((n: any) => ({
|
|
973
1004
|
...n,
|
|
974
1005
|
config: redactServerNodeConfig(n.config, resolveNodeExecutionEnv(n)),
|
|
1006
|
+
// Runtime marker consumed by clientExecutableBranchNodes (client
|
|
1007
|
+
// runtime) so streaming on-stream/on-end branches never execute
|
|
1008
|
+
// server nodes (whose config was just redacted) client-side.
|
|
1009
|
+
executionEnv: resolveNodeExecutionEnv(n),
|
|
975
1010
|
}))
|
|
976
1011
|
)
|
|
977
1012
|
const edgesJson = JSON.stringify(cn.edges)
|
|
@@ -1467,15 +1502,35 @@ module.exports = __customNodeRegistry;
|
|
|
1467
1502
|
}
|
|
1468
1503
|
}
|
|
1469
1504
|
|
|
1505
|
+
// Emit a handler function AND a `clientNodeHandlers` map entry ONLY for node
|
|
1506
|
+
// types that actually have a registry generator. These two lists MUST stay
|
|
1507
|
+
// paired: previously `handlers` was gated on `if (gen)` while `handlerEntries`
|
|
1508
|
+
// mapped over EVERY handlerType, so a client-segment node whose type has no
|
|
1509
|
+
// generator (e.g. a `general-comment`, or a trigger/`event-*` node that got
|
|
1510
|
+
// collected into `handlerTypes`) produced a map entry `'x-y': x_y` with no
|
|
1511
|
+
// `x_y` defined anywhere in the file. That is a bare reference to an
|
|
1512
|
+
// undefined identifier, which throws `ReferenceError: x_y is not defined` at
|
|
1513
|
+
// MODULE-EVAL time — i.e. during Next's "Collecting page data" build step —
|
|
1514
|
+
// crashing the production build (Vercel). It is Vercel/production-only
|
|
1515
|
+
// because global-workflows.js is pulled into the global client bundle for
|
|
1516
|
+
// every page via `useGlobalWorkflows()` in _app, and chunk grouping decides
|
|
1517
|
+
// when the bad module is required. Pairing the lists keeps the map
|
|
1518
|
+
// referencing only functions that were emitted (this mirrors
|
|
1519
|
+
// node-handlers-client's loop above). Dropping a map entry is safe: the
|
|
1520
|
+
// runtime dispatch (`runtime-utils.js`) warns + `continue`s on an unknown
|
|
1521
|
+
// node type, and control-flow nodes (if/switch/loop/parallel) are handled by
|
|
1522
|
+
// the segment executor without ever looking up `clientNodeHandlers`.
|
|
1470
1523
|
const handlers: string[] = []
|
|
1524
|
+
const emittedHandlerTypes: string[] = []
|
|
1471
1525
|
handlerTypes.forEach((t) => {
|
|
1472
1526
|
const gen = nodeRegistry[t]
|
|
1473
1527
|
if (gen) {
|
|
1474
1528
|
handlers.push(gen.generateHandler())
|
|
1529
|
+
emittedHandlerTypes.push(t)
|
|
1475
1530
|
}
|
|
1476
1531
|
})
|
|
1477
1532
|
|
|
1478
|
-
const handlerEntries =
|
|
1533
|
+
const handlerEntries = emittedHandlerTypes
|
|
1479
1534
|
.map((t) => ` '${t}': ${t.replace(/-/g, '_')}`)
|
|
1480
1535
|
.join(',\n')
|
|
1481
1536
|
|