@teleporthq/teleport-plugin-next-workflows 0.43.53 → 0.43.55

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 (174) hide show
  1. package/__tests__/ai-chat-rag-sql-parameterization.test.ts +237 -0
  2. package/__tests__/ai-embedding-optional.test.ts +77 -0
  3. package/__tests__/ai-model-capabilities.test.ts +234 -0
  4. package/__tests__/ai-provider-coverage.test.ts +183 -0
  5. package/__tests__/cart-clear-db-mirror.test.ts +45 -0
  6. package/__tests__/cart-get-total-storefront-tax.test.ts +165 -0
  7. package/__tests__/cron-route-loop-templateparams.test.ts +15 -6
  8. package/__tests__/data-create-item-order-notification.test.ts +33 -0
  9. package/__tests__/ecommerce-customhandler-rewriter.test.ts +1 -1
  10. package/__tests__/internal-request-headers.test.ts +159 -0
  11. package/__tests__/order-details-route.test.ts +238 -0
  12. package/__tests__/resolve-config-template-params.test.ts +174 -0
  13. package/__tests__/utility-nodes.test.ts +27 -11
  14. package/dist/cjs/api-route-generator.d.ts.map +1 -1
  15. package/dist/cjs/api-route-generator.js +27 -15
  16. package/dist/cjs/api-route-generator.js.map +1 -1
  17. package/dist/cjs/ecommerce/order-details-route.d.ts +18 -0
  18. package/dist/cjs/ecommerce/order-details-route.d.ts.map +1 -0
  19. package/dist/cjs/ecommerce/order-details-route.js +172 -0
  20. package/dist/cjs/ecommerce/order-details-route.js.map +1 -0
  21. package/dist/cjs/ecommerce-customhandler-rewriter.d.ts +1 -1
  22. package/dist/cjs/ecommerce-customhandler-rewriter.d.ts.map +1 -1
  23. package/dist/cjs/ecommerce-customhandler-rewriter.js +20 -4
  24. package/dist/cjs/ecommerce-customhandler-rewriter.js.map +1 -1
  25. package/dist/cjs/executor-generator.d.ts.map +1 -1
  26. package/dist/cjs/executor-generator.js +69 -11
  27. package/dist/cjs/executor-generator.js.map +1 -1
  28. package/dist/cjs/nodes/ai/ai-custom-prompt.js +1 -1
  29. package/dist/cjs/nodes/ai/ai-custom-prompt.js.map +1 -1
  30. package/dist/cjs/nodes/ai/ai-detect-language.js +1 -1
  31. package/dist/cjs/nodes/ai/ai-detect-language.js.map +1 -1
  32. package/dist/cjs/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
  33. package/dist/cjs/nodes/ai/ai-generate-text-embedding.js +47 -4
  34. package/dist/cjs/nodes/ai/ai-generate-text-embedding.js.map +1 -1
  35. package/dist/cjs/nodes/ai/ai-provider-utils.d.ts +2 -0
  36. package/dist/cjs/nodes/ai/ai-provider-utils.d.ts.map +1 -1
  37. package/dist/cjs/nodes/ai/ai-provider-utils.js +195 -106
  38. package/dist/cjs/nodes/ai/ai-provider-utils.js.map +1 -1
  39. package/dist/cjs/nodes/ai/ai-sentiment-analysis.js +1 -1
  40. package/dist/cjs/nodes/ai/ai-sentiment-analysis.js.map +1 -1
  41. package/dist/cjs/nodes/ai/ai-summarization.js +1 -1
  42. package/dist/cjs/nodes/ai/ai-summarization.js.map +1 -1
  43. package/dist/cjs/nodes/ai/ai-text-classifier.js +1 -1
  44. package/dist/cjs/nodes/ai/ai-text-classifier.js.map +1 -1
  45. package/dist/cjs/nodes/ai/ai-text-transform.js +1 -1
  46. package/dist/cjs/nodes/ai/ai-text-transform.js.map +1 -1
  47. package/dist/cjs/nodes/cart/cart-clear.d.ts.map +1 -1
  48. package/dist/cjs/nodes/cart/cart-clear.js +40 -0
  49. package/dist/cjs/nodes/cart/cart-clear.js.map +1 -1
  50. package/dist/cjs/nodes/cart/cart-get-total.d.ts.map +1 -1
  51. package/dist/cjs/nodes/cart/cart-get-total.js +56 -15
  52. package/dist/cjs/nodes/cart/cart-get-total.js.map +1 -1
  53. package/dist/cjs/nodes/data/data-count.d.ts.map +1 -1
  54. package/dist/cjs/nodes/data/data-count.js +6 -1
  55. package/dist/cjs/nodes/data/data-count.js.map +1 -1
  56. package/dist/cjs/nodes/data/data-create-item.d.ts.map +1 -1
  57. package/dist/cjs/nodes/data/data-create-item.js +45 -9
  58. package/dist/cjs/nodes/data/data-create-item.js.map +1 -1
  59. package/dist/cjs/nodes/data/data-delete-item.d.ts.map +1 -1
  60. package/dist/cjs/nodes/data/data-delete-item.js +7 -4
  61. package/dist/cjs/nodes/data/data-delete-item.js.map +1 -1
  62. package/dist/cjs/nodes/data/data-raw-query.d.ts.map +1 -1
  63. package/dist/cjs/nodes/data/data-raw-query.js +7 -1
  64. package/dist/cjs/nodes/data/data-raw-query.js.map +1 -1
  65. package/dist/cjs/nodes/data/data-select.d.ts.map +1 -1
  66. package/dist/cjs/nodes/data/data-select.js +6 -1
  67. package/dist/cjs/nodes/data/data-select.js.map +1 -1
  68. package/dist/cjs/nodes/data/data-update-item.d.ts.map +1 -1
  69. package/dist/cjs/nodes/data/data-update-item.js +7 -4
  70. package/dist/cjs/nodes/data/data-update-item.js.map +1 -1
  71. package/dist/cjs/nodes/utility/utility-hybrid-search.js +2 -2
  72. package/dist/cjs/nodes/utility/utility-hybrid-search.js.map +1 -1
  73. package/dist/cjs/nodes/utility/utility-semantic-search.js +1 -1
  74. package/dist/cjs/nodes/utility/utility-semantic-search.js.map +1 -1
  75. package/dist/cjs/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
  76. package/dist/cjs/nodes/utility/utility-similarity-scoring.js +49 -3
  77. package/dist/cjs/nodes/utility/utility-similarity-scoring.js.map +1 -1
  78. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  79. package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
  80. package/dist/cjs/workflow-project-plugin.js +10 -4
  81. package/dist/cjs/workflow-project-plugin.js.map +1 -1
  82. package/dist/esm/api-route-generator.d.ts.map +1 -1
  83. package/dist/esm/api-route-generator.js +27 -15
  84. package/dist/esm/api-route-generator.js.map +1 -1
  85. package/dist/esm/ecommerce/order-details-route.d.ts +18 -0
  86. package/dist/esm/ecommerce/order-details-route.d.ts.map +1 -0
  87. package/dist/esm/ecommerce/order-details-route.js +167 -0
  88. package/dist/esm/ecommerce/order-details-route.js.map +1 -0
  89. package/dist/esm/ecommerce-customhandler-rewriter.d.ts +1 -1
  90. package/dist/esm/ecommerce-customhandler-rewriter.d.ts.map +1 -1
  91. package/dist/esm/ecommerce-customhandler-rewriter.js +20 -4
  92. package/dist/esm/ecommerce-customhandler-rewriter.js.map +1 -1
  93. package/dist/esm/executor-generator.d.ts.map +1 -1
  94. package/dist/esm/executor-generator.js +69 -11
  95. package/dist/esm/executor-generator.js.map +1 -1
  96. package/dist/esm/nodes/ai/ai-custom-prompt.js +1 -1
  97. package/dist/esm/nodes/ai/ai-custom-prompt.js.map +1 -1
  98. package/dist/esm/nodes/ai/ai-detect-language.js +1 -1
  99. package/dist/esm/nodes/ai/ai-detect-language.js.map +1 -1
  100. package/dist/esm/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
  101. package/dist/esm/nodes/ai/ai-generate-text-embedding.js +47 -4
  102. package/dist/esm/nodes/ai/ai-generate-text-embedding.js.map +1 -1
  103. package/dist/esm/nodes/ai/ai-provider-utils.d.ts +2 -0
  104. package/dist/esm/nodes/ai/ai-provider-utils.d.ts.map +1 -1
  105. package/dist/esm/nodes/ai/ai-provider-utils.js +194 -105
  106. package/dist/esm/nodes/ai/ai-provider-utils.js.map +1 -1
  107. package/dist/esm/nodes/ai/ai-sentiment-analysis.js +1 -1
  108. package/dist/esm/nodes/ai/ai-sentiment-analysis.js.map +1 -1
  109. package/dist/esm/nodes/ai/ai-summarization.js +1 -1
  110. package/dist/esm/nodes/ai/ai-summarization.js.map +1 -1
  111. package/dist/esm/nodes/ai/ai-text-classifier.js +1 -1
  112. package/dist/esm/nodes/ai/ai-text-classifier.js.map +1 -1
  113. package/dist/esm/nodes/ai/ai-text-transform.js +1 -1
  114. package/dist/esm/nodes/ai/ai-text-transform.js.map +1 -1
  115. package/dist/esm/nodes/cart/cart-clear.d.ts.map +1 -1
  116. package/dist/esm/nodes/cart/cart-clear.js +40 -0
  117. package/dist/esm/nodes/cart/cart-clear.js.map +1 -1
  118. package/dist/esm/nodes/cart/cart-get-total.d.ts.map +1 -1
  119. package/dist/esm/nodes/cart/cart-get-total.js +56 -15
  120. package/dist/esm/nodes/cart/cart-get-total.js.map +1 -1
  121. package/dist/esm/nodes/data/data-count.d.ts.map +1 -1
  122. package/dist/esm/nodes/data/data-count.js +6 -1
  123. package/dist/esm/nodes/data/data-count.js.map +1 -1
  124. package/dist/esm/nodes/data/data-create-item.d.ts.map +1 -1
  125. package/dist/esm/nodes/data/data-create-item.js +45 -9
  126. package/dist/esm/nodes/data/data-create-item.js.map +1 -1
  127. package/dist/esm/nodes/data/data-delete-item.d.ts.map +1 -1
  128. package/dist/esm/nodes/data/data-delete-item.js +7 -4
  129. package/dist/esm/nodes/data/data-delete-item.js.map +1 -1
  130. package/dist/esm/nodes/data/data-raw-query.d.ts.map +1 -1
  131. package/dist/esm/nodes/data/data-raw-query.js +7 -1
  132. package/dist/esm/nodes/data/data-raw-query.js.map +1 -1
  133. package/dist/esm/nodes/data/data-select.d.ts.map +1 -1
  134. package/dist/esm/nodes/data/data-select.js +6 -1
  135. package/dist/esm/nodes/data/data-select.js.map +1 -1
  136. package/dist/esm/nodes/data/data-update-item.d.ts.map +1 -1
  137. package/dist/esm/nodes/data/data-update-item.js +7 -4
  138. package/dist/esm/nodes/data/data-update-item.js.map +1 -1
  139. package/dist/esm/nodes/utility/utility-hybrid-search.js +2 -2
  140. package/dist/esm/nodes/utility/utility-hybrid-search.js.map +1 -1
  141. package/dist/esm/nodes/utility/utility-semantic-search.js +1 -1
  142. package/dist/esm/nodes/utility/utility-semantic-search.js.map +1 -1
  143. package/dist/esm/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
  144. package/dist/esm/nodes/utility/utility-similarity-scoring.js +49 -3
  145. package/dist/esm/nodes/utility/utility-similarity-scoring.js.map +1 -1
  146. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  147. package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
  148. package/dist/esm/workflow-project-plugin.js +10 -4
  149. package/dist/esm/workflow-project-plugin.js.map +1 -1
  150. package/package.json +4 -4
  151. package/src/api-route-generator.ts +27 -15
  152. package/src/ecommerce/order-details-route.ts +195 -0
  153. package/src/ecommerce-customhandler-rewriter.ts +24 -4
  154. package/src/executor-generator.ts +69 -11
  155. package/src/nodes/ai/ai-custom-prompt.ts +2 -2
  156. package/src/nodes/ai/ai-detect-language.ts +2 -2
  157. package/src/nodes/ai/ai-generate-text-embedding.ts +49 -4
  158. package/src/nodes/ai/ai-provider-utils.ts +216 -106
  159. package/src/nodes/ai/ai-sentiment-analysis.ts +2 -2
  160. package/src/nodes/ai/ai-summarization.ts +2 -2
  161. package/src/nodes/ai/ai-text-classifier.ts +2 -2
  162. package/src/nodes/ai/ai-text-transform.ts +2 -2
  163. package/src/nodes/cart/cart-clear.ts +40 -0
  164. package/src/nodes/cart/cart-get-total.ts +61 -17
  165. package/src/nodes/data/data-count.ts +6 -1
  166. package/src/nodes/data/data-create-item.ts +45 -9
  167. package/src/nodes/data/data-delete-item.ts +6 -0
  168. package/src/nodes/data/data-raw-query.ts +8 -1
  169. package/src/nodes/data/data-select.ts +6 -1
  170. package/src/nodes/data/data-update-item.ts +6 -0
  171. package/src/nodes/utility/utility-hybrid-search.ts +2 -2
  172. package/src/nodes/utility/utility-semantic-search.ts +1 -1
  173. package/src/nodes/utility/utility-similarity-scoring.ts +56 -3
  174. package/src/workflow-project-plugin.ts +10 -4
@@ -501,6 +501,35 @@ function resolveConfig(config, context) {
501
501
  resolved[key] = resolveScalarValue(val, context);
502
502
  }
503
503
  }
504
+ // Component-bodied email nodes carry their merge values as \`templateParams\`
505
+ // and their body/subject as \`{{token}}\` templates. Filling them HERE — the one
506
+ // function every execution path funnels a node config through — is what makes
507
+ // the fill unmissable.
508
+ //
509
+ // It used to be pasted at the individual call sites instead, and it was only
510
+ // ever pasted at three of the sixteen: the client executor, and the loop-body
511
+ // + main loops of the cron/webhook route. The MAIN loop of
512
+ // \`generateServerSegmentAPIRoute\` — which is where every ordinary page
513
+ // workflow's email node actually executes — never had it, so withdrawal
514
+ // confirmations, withdrawal owner notifications, review notifications,
515
+ // order notifications and the password-reset email all shipped with their
516
+ // tokens verbatim: literal "{{customerName}}" in the body, "{{orderNumber}}"
517
+ // in the subject, and \`href="{{resetUrl}}"\` on the reset button (an invalid
518
+ // relative URL, which mail clients drop — so the button had no link at all).
519
+ // The abandoned-cart reminder was the only one that worked, because its send
520
+ // node sits inside a loop body AND on a cron route: the two paths that had
521
+ // the paste.
522
+ //
523
+ // Runs after resolution on purpose: \`templateParams[].value\` is itself a
524
+ // workflow-context ref that the loop above has just resolved.
525
+ if (Array.isArray(resolved.templateParams)) {
526
+ if (typeof resolved.body === 'string') {
527
+ resolved.body = applyTemplateParams(resolved.body, resolved.templateParams);
528
+ }
529
+ if (typeof resolved.subject === 'string') {
530
+ resolved.subject = applyTemplateParams(resolved.subject, resolved.templateParams);
531
+ }
532
+ }
504
533
  return resolved;
505
534
  }
506
535
 
@@ -809,17 +838,9 @@ async function executeNodes(nodes, edges, context, nodeHandlers, workflowConfig,
809
838
  throw new Error(configError);
810
839
  }
811
840
 
812
- // Component-bodied send-email node: fill {{token}} merge fields in the
813
- // serialized template body/subject from the resolved templateParams
814
- // (resolveConfig already resolved each param value against context).
815
- if (resolvedConfig && Array.isArray(resolvedConfig.templateParams)) {
816
- if (typeof resolvedConfig.body === 'string') {
817
- resolvedConfig.body = applyTemplateParams(resolvedConfig.body, resolvedConfig.templateParams);
818
- }
819
- if (typeof resolvedConfig.subject === 'string') {
820
- resolvedConfig.subject = applyTemplateParams(resolvedConfig.subject, resolvedConfig.templateParams);
821
- }
822
- }
841
+ // NOTE: the component-bodied email fill used to live here. It now runs
842
+ // inside resolveConfig itself, so every execution path gets it exactly
843
+ // once — see the comment there.
823
844
 
824
845
  if (node.type === 'general-if-statement') {
825
846
  const condResult = evaluateCondition(resolvedConfig, context);
@@ -1217,7 +1238,44 @@ function collectBranchNodes(startId, allNodes, edges, excludeParentId) {
1217
1238
  return ids;
1218
1239
  }
1219
1240
 
1241
+ /**
1242
+ * Headers a server-side node must send when this deployment calls its OWN API
1243
+ * routes over HTTP (every data node does: \`fetch(__baseUrl + '/api/data/…')\`).
1244
+ *
1245
+ * ⛔ Without them, a deployment behind Vercel Deployment Protection answers its
1246
+ * own request with 401 "Protected deployment". The page renders — the visitor's
1247
+ * browser holds the bypass cookie — but every data node silently returns
1248
+ * \`{ rows: [] }\`, so the app looks alive while nothing reads or writes. On the
1249
+ * shipped AI-chat store this made the whole knowledge base invisible: the RAG
1250
+ * search returned zero rows for every question and the assistant answered "I
1251
+ * don't have enough information in my knowledge base" every single time.
1252
+ *
1253
+ * Two credentials, in order of what actually exists at the time:
1254
+ * - the visitor's own cookies, which already carried them past the protection
1255
+ * to reach this route. Forwarding them makes the self-call exactly as
1256
+ * authorized as the page load was, and nothing more.
1257
+ * - \`VERCEL_AUTOMATION_BYPASS_SECRET\`, the only thing that works when there is
1258
+ * no browser behind the request (a cron trigger, an inbound webhook).
1259
+ *
1260
+ * Same-origin only: these go to \`__baseUrl\`, which is derived from this
1261
+ * request's own host, so no credential is forwarded anywhere else.
1262
+ */
1263
+ function internalRequestHeaders(req) {
1264
+ const headers = {};
1265
+ if (req && req.headers && req.headers.cookie) {
1266
+ headers.cookie = req.headers.cookie;
1267
+ }
1268
+ const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
1269
+ if (bypassSecret) {
1270
+ headers['x-vercel-protection-bypass'] = bypassSecret;
1271
+ // Tells Vercel not to hand the bypass back to the caller as a cookie.
1272
+ headers['x-vercel-set-bypass-cookie'] = 'false';
1273
+ }
1274
+ return headers;
1275
+ }
1276
+
1220
1277
  module.exports = {
1278
+ internalRequestHeaders,
1221
1279
  resolveValue,
1222
1280
  resolveSecret,
1223
1281
  resolveConfig,
@@ -7,7 +7,7 @@ import {
7
7
 
8
8
  declare function __ai_resolveTextField(val: any): string
9
9
  declare function __ai_resolveToken(token: any): string
10
- declare function __ai_detectProvider(modelId: any): string
10
+ declare function __ai_resolveProvider(config: any): string
11
11
  declare function __ai_clampTemperature(temp: any, provider: string): number
12
12
  declare function __ai_callProvider(params: any): Promise<any>
13
13
  declare function __ai_handleStreamingCall(
@@ -40,7 +40,7 @@ async function ai_custom_prompt(
40
40
  return { error: true, message: err.message, code: 'authentication_error' }
41
41
  }
42
42
 
43
- const provider = __ai_detectProvider(model)
43
+ const provider = __ai_resolveProvider(config)
44
44
  temperature = __ai_clampTemperature(temperature, provider)
45
45
 
46
46
  let systemMessage = config.systemMessage ? __ai_resolveTextField(config.systemMessage) : undefined
@@ -7,7 +7,7 @@ import {
7
7
 
8
8
  declare function __ai_resolveTextField(val: any): string
9
9
  declare function __ai_resolveToken(token: any): string
10
- declare function __ai_detectProvider(modelId: any): string
10
+ declare function __ai_resolveProvider(config: any): string
11
11
  declare function __ai_clampTemperature(temp: any, provider: string): number
12
12
  declare function __ai_callProvider(params: any): Promise<any>
13
13
  declare function __ai_parseJSON(text: any): any
@@ -40,7 +40,7 @@ async function ai_detect_language(
40
40
  return { error: true, message: err.message, code: 'authentication_error' }
41
41
  }
42
42
 
43
- const provider = __ai_detectProvider(model)
43
+ const provider = __ai_resolveProvider(config)
44
44
  const temperature = __ai_clampTemperature(0, provider)
45
45
 
46
46
  let systemPrompt
@@ -4,17 +4,55 @@ import { generateAIProviderUtils, AI_PROVIDER_DEPENDENCIES } from './ai-provider
4
4
  declare function __ai_resolveTextField(val: any): string
5
5
  declare function __ai_resolveToken(token: any): string
6
6
 
7
+ /**
8
+ * Text embeddings, always through OpenAI's embeddings API.
9
+ *
10
+ * ## `config.optional`
11
+ *
12
+ * A node result carrying `error: true` is FATAL — `isFatalNodeResult` in the
13
+ * executor throws on it and the whole workflow stops. That is right for a
14
+ * pipeline whose output is the embedding, and wrong for one where the
15
+ * embedding only powers a nice-to-have branch.
16
+ *
17
+ * The AI Assistant Chat is the second case: its retrieval is a hybrid of a
18
+ * vector search and a keyword search running in parallel, and the keyword half
19
+ * answers perfectly well on its own. A chat whose provider is Anthropic or
20
+ * Google may legitimately have no OpenAI key at all (embeddings are OpenAI-only
21
+ * because that is what the knowledge base was indexed with), and that must
22
+ * degrade to keyword-only search rather than break every message.
23
+ *
24
+ * With `optional: true` the node reports failure as data — `skipped: true` plus
25
+ * an empty `embedding` — so downstream nodes can branch on it. Consumers must
26
+ * check `embedding.length` before using it, which the chat's semantic-query
27
+ * builder already does.
28
+ */
7
29
  async function ai_generate_text_embedding(config: any, context: Record<string, unknown>) {
30
+ const optional = config.optional === true
31
+
32
+ function fail(message: string, code: string) {
33
+ if (optional) {
34
+ return {
35
+ embedding: [],
36
+ vectorLiteral: '',
37
+ dimensions: 0,
38
+ skipped: true,
39
+ skipReason: message,
40
+ code,
41
+ }
42
+ }
43
+ return { error: true, message, code }
44
+ }
45
+
8
46
  const text = __ai_resolveTextField(config.text)
9
47
  if (!text) {
10
- return { error: true, message: 'Text to embed is required', code: 'missing_text' }
48
+ return fail('Text to embed is required', 'missing_text')
11
49
  }
12
50
 
13
51
  let token
14
52
  try {
15
53
  token = __ai_resolveToken(config.token)
16
54
  } catch (err: any) {
17
- return { error: true, message: err.message, code: 'authentication_error' }
55
+ return fail(err.message, 'authentication_error')
18
56
  }
19
57
 
20
58
  const model = config.model || 'text-embedding-3-small'
@@ -40,12 +78,19 @@ async function ai_generate_text_embedding(config: any, context: Record<string, u
40
78
 
41
79
  const embeddingData = response.data && response.data[0]
42
80
  if (!embeddingData || !embeddingData.embedding) {
43
- return { error: true, message: 'No embedding returned from API', code: 'empty_response' }
81
+ return fail('No embedding returned from API', 'empty_response')
44
82
  }
45
83
 
46
84
  const usage = response.usage || {}
47
85
  return {
48
86
  embedding: embeddingData.embedding,
87
+ // pgvector's literal form, ready to bind as a `$N` param and cast with
88
+ // `::vector`. The raw `embedding` array cannot do that job: a JS array
89
+ // bound as a query parameter is serialized as a Postgres ARRAY literal
90
+ // (`{0.1,0.2}`), which no cast turns into a vector. Without this field a
91
+ // vector search has to assemble its SQL in a general-custom-js node —
92
+ // whose output is relayed to the browser, leaking the schema.
93
+ vectorLiteral: '[' + embeddingData.embedding.join(',') + ']',
49
94
  model: response.model || model,
50
95
  dimensions: embeddingData.embedding.length,
51
96
  usage: {
@@ -54,7 +99,7 @@ async function ai_generate_text_embedding(config: any, context: Record<string, u
54
99
  },
55
100
  }
56
101
  } catch (err: any) {
57
- return { error: true, message: err.message || String(err), code: 'provider_error' }
102
+ return fail(err.message || String(err), 'provider_error')
58
103
  }
59
104
  }
60
105