@teleporthq/teleport-plugin-next-workflows 0.43.26 → 0.43.30

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 (79) hide show
  1. package/__tests__/_helpers/load-handler.ts +11 -1
  2. package/__tests__/file-storage-upload-picked-files.test.ts +135 -0
  3. package/__tests__/runtime-operator-aliases.test.ts +180 -0
  4. package/__tests__/runtime-template-token-resolution.test.ts +225 -0
  5. package/__tests__/salesforce-opportunity-id.test.ts +122 -0
  6. package/__tests__/state-update-array-type-guard.test.ts +172 -0
  7. package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
  8. package/dist/cjs/data-api-route-generator.js +10 -0
  9. package/dist/cjs/data-api-route-generator.js.map +1 -1
  10. package/dist/cjs/executor-generator.d.ts.map +1 -1
  11. package/dist/cjs/executor-generator.js +134 -5
  12. package/dist/cjs/executor-generator.js.map +1 -1
  13. package/dist/cjs/nodes/data/data-count.d.ts.map +1 -1
  14. package/dist/cjs/nodes/data/data-count.js +16 -0
  15. package/dist/cjs/nodes/data/data-count.js.map +1 -1
  16. package/dist/cjs/nodes/data/data-create-item.d.ts.map +1 -1
  17. package/dist/cjs/nodes/data/data-create-item.js +20 -0
  18. package/dist/cjs/nodes/data/data-create-item.js.map +1 -1
  19. package/dist/cjs/nodes/data/data-delete-item.d.ts.map +1 -1
  20. package/dist/cjs/nodes/data/data-delete-item.js +26 -1
  21. package/dist/cjs/nodes/data/data-delete-item.js.map +1 -1
  22. package/dist/cjs/nodes/data/data-select.d.ts.map +1 -1
  23. package/dist/cjs/nodes/data/data-select.js +18 -0
  24. package/dist/cjs/nodes/data/data-select.js.map +1 -1
  25. package/dist/cjs/nodes/data/data-update-item.d.ts.map +1 -1
  26. package/dist/cjs/nodes/data/data-update-item.js +43 -1
  27. package/dist/cjs/nodes/data/data-update-item.js.map +1 -1
  28. package/dist/cjs/nodes/integrations/integration-salesforce.d.ts.map +1 -1
  29. package/dist/cjs/nodes/integrations/integration-salesforce.js +3 -3
  30. package/dist/cjs/nodes/integrations/integration-salesforce.js.map +1 -1
  31. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  32. package/dist/cjs/workflow-component-plugin.d.ts.map +1 -1
  33. package/dist/cjs/workflow-component-plugin.js +56 -9
  34. package/dist/cjs/workflow-component-plugin.js.map +1 -1
  35. package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
  36. package/dist/cjs/workflow-project-plugin.js +34 -9
  37. package/dist/cjs/workflow-project-plugin.js.map +1 -1
  38. package/dist/esm/data-api-route-generator.d.ts.map +1 -1
  39. package/dist/esm/data-api-route-generator.js +10 -0
  40. package/dist/esm/data-api-route-generator.js.map +1 -1
  41. package/dist/esm/executor-generator.d.ts.map +1 -1
  42. package/dist/esm/executor-generator.js +134 -5
  43. package/dist/esm/executor-generator.js.map +1 -1
  44. package/dist/esm/nodes/data/data-count.d.ts.map +1 -1
  45. package/dist/esm/nodes/data/data-count.js +16 -0
  46. package/dist/esm/nodes/data/data-count.js.map +1 -1
  47. package/dist/esm/nodes/data/data-create-item.d.ts.map +1 -1
  48. package/dist/esm/nodes/data/data-create-item.js +20 -0
  49. package/dist/esm/nodes/data/data-create-item.js.map +1 -1
  50. package/dist/esm/nodes/data/data-delete-item.d.ts.map +1 -1
  51. package/dist/esm/nodes/data/data-delete-item.js +26 -1
  52. package/dist/esm/nodes/data/data-delete-item.js.map +1 -1
  53. package/dist/esm/nodes/data/data-select.d.ts.map +1 -1
  54. package/dist/esm/nodes/data/data-select.js +18 -0
  55. package/dist/esm/nodes/data/data-select.js.map +1 -1
  56. package/dist/esm/nodes/data/data-update-item.d.ts.map +1 -1
  57. package/dist/esm/nodes/data/data-update-item.js +43 -1
  58. package/dist/esm/nodes/data/data-update-item.js.map +1 -1
  59. package/dist/esm/nodes/integrations/integration-salesforce.d.ts.map +1 -1
  60. package/dist/esm/nodes/integrations/integration-salesforce.js +3 -3
  61. package/dist/esm/nodes/integrations/integration-salesforce.js.map +1 -1
  62. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  63. package/dist/esm/workflow-component-plugin.d.ts.map +1 -1
  64. package/dist/esm/workflow-component-plugin.js +56 -9
  65. package/dist/esm/workflow-component-plugin.js.map +1 -1
  66. package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
  67. package/dist/esm/workflow-project-plugin.js +34 -9
  68. package/dist/esm/workflow-project-plugin.js.map +1 -1
  69. package/package.json +2 -2
  70. package/src/data-api-route-generator.ts +10 -0
  71. package/src/executor-generator.ts +134 -5
  72. package/src/nodes/data/data-count.ts +20 -0
  73. package/src/nodes/data/data-create-item.ts +19 -0
  74. package/src/nodes/data/data-delete-item.ts +30 -1
  75. package/src/nodes/data/data-select.ts +22 -0
  76. package/src/nodes/data/data-update-item.ts +45 -1
  77. package/src/nodes/integrations/integration-salesforce.ts +22 -13
  78. package/src/workflow-component-plugin.ts +61 -3
  79. package/src/workflow-project-plugin.ts +29 -4
@@ -246,11 +246,14 @@ async function integration_salesforce(config: any, context: Record<string, unkno
246
246
  }
247
247
  case 'update-opportunity': {
248
248
  const body = config.fields || {}
249
- const response = await fetch(baseUrl + 'sobjects/Opportunity/' + config.oppId, {
250
- method: 'PATCH',
251
- headers,
252
- body: JSON.stringify(body),
253
- })
249
+ const response = await fetch(
250
+ baseUrl + 'sobjects/Opportunity/' + (config.opportunityId || config.oppId),
251
+ {
252
+ method: 'PATCH',
253
+ headers,
254
+ body: JSON.stringify(body),
255
+ }
256
+ )
254
257
  if (!response.ok) {
255
258
  const data = await __readJson(response)
256
259
  return {
@@ -261,10 +264,13 @@ async function integration_salesforce(config: any, context: Record<string, unkno
261
264
  return { success: true }
262
265
  }
263
266
  case 'get-opportunity': {
264
- const response = await fetch(baseUrl + 'sobjects/Opportunity/' + config.oppId, {
265
- method: 'GET',
266
- headers,
267
- })
267
+ const response = await fetch(
268
+ baseUrl + 'sobjects/Opportunity/' + (config.opportunityId || config.oppId),
269
+ {
270
+ method: 'GET',
271
+ headers,
272
+ }
273
+ )
268
274
  const data = await __readJson(response)
269
275
  if (!response.ok) {
270
276
  return {
@@ -275,10 +281,13 @@ async function integration_salesforce(config: any, context: Record<string, unkno
275
281
  return { success: true, opportunity: data }
276
282
  }
277
283
  case 'delete-opportunity': {
278
- const response = await fetch(baseUrl + 'sobjects/Opportunity/' + config.oppId, {
279
- method: 'DELETE',
280
- headers,
281
- })
284
+ const response = await fetch(
285
+ baseUrl + 'sobjects/Opportunity/' + (config.opportunityId || config.oppId),
286
+ {
287
+ method: 'DELETE',
288
+ headers,
289
+ }
290
+ )
282
291
  if (!response.ok) {
283
292
  const data = await __readJson(response)
284
293
  return {
@@ -327,7 +327,14 @@ export const createNextWorkflowPlugin: ComponentPluginFactory<WorkflowPluginConf
327
327
  const hasCurrentUserGlobalRefs = activeWorkflows.some((wf) =>
328
328
  hasGlobalContextStateRefTransitively(wf.nodes, workflows.customNodes, new Set<string>())
329
329
  )
330
- const needsGlobalContextBridge = hasAuthNodes || hasCurrentUserGlobalRefs
330
+ // Node configs may also reference the logged-in user via a literal
331
+ // {{Current User.id}} template token (resolved at runtime from the
332
+ // __stateValues.currentUser bridge) — those pages need the same
333
+ // GlobalContext plumbing even without a state-get/update node.
334
+ const hasCurrentUserToken = activeWorkflows.some((wf) =>
335
+ wf.nodes.some((n) => JSON.stringify(n.config || {}).includes('{{Current User.'))
336
+ )
337
+ const needsGlobalContextBridge = hasAuthNodes || hasCurrentUserGlobalRefs || hasCurrentUserToken
331
338
 
332
339
  const hasAudioNodes = activeWorkflows.some((wf) =>
333
340
  wf.nodes.some((n) => n.type === 'audio-play' || n.type === 'audio-stop')
@@ -399,6 +406,15 @@ export const createNextWorkflowPlugin: ComponentPluginFactory<WorkflowPluginConf
399
406
  (!pageProtection.allowedRoles || pageProtection.allowedRoles.length === 0)
400
407
  )
401
408
 
409
+ const dynamicRouteAttributeRaw = (uidl as any).outputOptions?.dynamicRouteAttribute as
410
+ | string
411
+ | undefined
412
+ const dynamicRouteAttribute =
413
+ typeof dynamicRouteAttributeRaw === 'string' &&
414
+ /^[A-Za-z_][A-Za-z0-9_-]*$/.test(dynamicRouteAttributeRaw)
415
+ ? dynamicRouteAttributeRaw
416
+ : undefined
417
+
402
418
  const moduleCode = generateModuleLevelCode(
403
419
  activeWorkflows,
404
420
  matchedElementTriggers,
@@ -408,7 +424,8 @@ export const createNextWorkflowPlugin: ComponentPluginFactory<WorkflowPluginConf
408
424
  globalStateChangeWorkflows,
409
425
  hasAudioNodes,
410
426
  needsAdminFormHydration,
411
- isRowOwnedSelfGuardedPage
427
+ isRowOwnedSelfGuardedPage,
428
+ dynamicRouteAttribute
412
429
  )
413
430
 
414
431
  if (moduleCode) {
@@ -558,6 +575,14 @@ export const createNextWorkflowPlugin: ComponentPluginFactory<WorkflowPluginConf
558
575
  path: `${pathPrefix}utils/workflows/runtime`,
559
576
  }
560
577
 
578
+ // Router singleton for {{urlDifferentiator}}-style token resolution in
579
+ // __execWf (route params are only reachable client-side at call time).
580
+ dependencies.Router = {
581
+ type: 'library',
582
+ path: 'next/router',
583
+ version: '12.1.0',
584
+ }
585
+
561
586
  dependencies.workflowClientHandlers = {
562
587
  type: 'local',
563
588
  path: `${pathPrefix}utils/workflows/node-handlers-client`,
@@ -1160,7 +1185,8 @@ const generateModuleLevelCode = (
1160
1185
  globalStateChangeWorkflows: UIDLWorkflow[],
1161
1186
  hasAudioNodes?: boolean,
1162
1187
  includeAdminFormHydrationHelper?: boolean,
1163
- isRowOwnedSelfGuardedPage?: boolean
1188
+ isRowOwnedSelfGuardedPage?: boolean,
1189
+ dynamicRouteAttribute?: string
1164
1190
  ): string => {
1165
1191
  if (allWorkflows.length === 0) {
1166
1192
  return ''
@@ -1451,6 +1477,26 @@ function __createWorkflowHandlers(stateSetters, stateTypes, stateValuesRef) {
1451
1477
  ) {
1452
1478
  value = value.value;
1453
1479
  }
1480
+ // Array-typed states must never receive a non-array payload — one
1481
+ // poisoned write (e.g. a ref resolving to a custom-js node's whole
1482
+ // { result: [...] } return object instead of its array property)
1483
+ // bricks every downstream consumer: the mapper renders nothing and
1484
+ // the next add-row spread throws "is not iterable". Mirrors the
1485
+ // GUI-side guard: unwrap an object with a single array-valued
1486
+ // property, otherwise fall back to an empty array.
1487
+ if (type === 'array' && !Array.isArray(value)) {
1488
+ console.warn(
1489
+ '[workflow] non-array value written to array state "' + property + '"; coercing',
1490
+ value
1491
+ );
1492
+ if (value && typeof value === 'object') {
1493
+ var arrayKeys = Object.keys(value);
1494
+ if (arrayKeys.length === 1 && Array.isArray(value[arrayKeys[0]])) {
1495
+ return value[arrayKeys[0]];
1496
+ }
1497
+ }
1498
+ return [];
1499
+ }
1454
1500
  if (type === 'boolean') return value === 'true' || value === true;
1455
1501
  if (type === 'number' && typeof value === 'string') {
1456
1502
  const parsed = Number(value);
@@ -1552,6 +1598,18 @@ function __createWorkflowHandlers(stateSetters, stateTypes, stateValuesRef) {
1552
1598
 
1553
1599
  function __execWf(config, triggerContext, serverUrls) {
1554
1600
  triggerContext.__stateValues = Object.assign({}, stateValuesRef.current);
1601
+ // Route context for {{urlDifferentiator}} / {{Current Page Entity.id}}
1602
+ // template tokens in node configs — resolved by the shared runtime's
1603
+ // resolveTemplateTokenString. Read at call time (not render time) so the
1604
+ // handlers survive client-side navigation between dynamic routes.
1605
+ if (typeof window !== 'undefined' && Router && Router.router && Router.router.query) {
1606
+ triggerContext.__routeParams = Object.assign({}, Router.router.query);
1607
+ }
1608
+ ${
1609
+ dynamicRouteAttribute
1610
+ ? ` triggerContext.__dynamicRouteParam = '${dynamicRouteAttribute}';\n`
1611
+ : ''
1612
+ }
1555
1613
  var fullConfig = typeof workflowCustomNodes !== 'undefined'
1556
1614
  ? Object.assign({}, config, { customNodes: workflowCustomNodes })
1557
1615
  : config;
@@ -413,10 +413,35 @@ export class NextWorkflowProjectPlugin implements ProjectPlugin {
413
413
  }
414
414
 
415
415
  if (needsDataAPIRoute(usedNodeTypes)) {
416
- const authUsersTableName =
417
- uidl.authentication?.enabled && uidl.authentication?.tables
418
- ? Object.keys(uidl.authentication.tables)[0] || 'users'
419
- : undefined
416
+ // Resolve the actual IDENTITY (users) table, not just the first auth-table
417
+ // key. Getting this wrong is a security hole: the /api/data guard only
418
+ // protects AUTH_USERS_TABLE, so if it points at an auxiliary table like
419
+ // `password_reset_tokens`, the real `users` table is left mutable
420
+ // unauthenticated. The identity table is the one storing credentials
421
+ // (an email/login column AND a password column).
422
+ const authUsersTableName = ((): string | undefined => {
423
+ if (!uidl.authentication?.enabled || !uidl.authentication?.tables) {
424
+ return undefined
425
+ }
426
+ const tables = uidl.authentication.tables
427
+ const names = Object.keys(tables)
428
+ if (names.length === 0) return 'users'
429
+ const cols = (n: string) => (tables[n] || []).map((c) => (c.name || '').toLowerCase())
430
+ const has = (n: string, re: RegExp) => cols(n).some((c) => re.test(c))
431
+ const identity = names.find(
432
+ (n) =>
433
+ has(n, /^(email|e_mail|username|user_name|login|user_email)$/) &&
434
+ has(n, /pass(word)?|pwd|password_hash|hashed_password/)
435
+ )
436
+ if (identity) return identity
437
+ const named = names.find((n) =>
438
+ /^(app_)?users?$|^members?$|^customers?$|^accounts?$/i.test(n)
439
+ )
440
+ if (named) return named
441
+ const AUX = /token|session|verification|reset|oauth|provider|magic|otp|account_link/i
442
+ const nonAux = names.find((n) => !AUX.test(n))
443
+ return nonAux || names[0]
444
+ })()
420
445
  // Low-stock auto-fire: the data-api wakes up the
421
446
  // /api/ecommerce/low-stock-alert endpoint on the place-order
422
447
  // workflow's stock-check SELECT. Both flags are sourced from