@teleporthq/teleport-plugin-next-workflows 0.43.65 → 0.43.67

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 (305) hide show
  1. package/__tests__/_helpers/bind-workflow-utils.ts +30 -0
  2. package/__tests__/_helpers/run-generated-middleware.ts +11 -2
  3. package/__tests__/admin-form-row-hydration.test.ts +55 -0
  4. package/__tests__/cart-clear-db-mirror.test.ts +12 -0
  5. package/__tests__/cart-get-total-regional-pricing.test.ts +166 -0
  6. package/__tests__/client-config-redaction.test.ts +53 -0
  7. package/__tests__/continue-on-error.test.ts +119 -0
  8. package/__tests__/email-locale-module.test.ts +323 -0
  9. package/__tests__/email-locale-senders.test.ts +268 -0
  10. package/__tests__/invoice-delivery-fee.test.ts +104 -0
  11. package/__tests__/invoice-regional-tax.test.ts +126 -0
  12. package/__tests__/locale-aware-redirects.test.ts +355 -0
  13. package/__tests__/navigation-go-to-page.test.ts +43 -0
  14. package/__tests__/node-handler-file-inline-map.test.ts +29 -3
  15. package/__tests__/payment-redirect-and-order-notification.test.ts +6 -0
  16. package/__tests__/paypal-webhook-order-notification.test.ts +41 -0
  17. package/__tests__/resolve-config-localized-templates.test.ts +262 -0
  18. package/__tests__/sent-email-log-module.test.ts +381 -0
  19. package/__tests__/sent-email-log-wiring.test.ts +267 -0
  20. package/dist/cjs/account-delete-route-generator.d.ts +20 -0
  21. package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
  22. package/dist/cjs/account-delete-route-generator.js +29 -26
  23. package/dist/cjs/account-delete-route-generator.js.map +1 -1
  24. package/dist/cjs/api-route-generator.d.ts.map +1 -1
  25. package/dist/cjs/api-route-generator.js +57 -11
  26. package/dist/cjs/api-route-generator.js.map +1 -1
  27. package/dist/cjs/auth-generator.d.ts +2 -1
  28. package/dist/cjs/auth-generator.d.ts.map +1 -1
  29. package/dist/cjs/auth-generator.js +55 -18
  30. package/dist/cjs/auth-generator.js.map +1 -1
  31. package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
  32. package/dist/cjs/data-api-route-generator.js +19 -0
  33. package/dist/cjs/data-api-route-generator.js.map +1 -1
  34. package/dist/cjs/email-locale/email-locale-code.d.ts +25 -0
  35. package/dist/cjs/email-locale/email-locale-code.d.ts.map +1 -0
  36. package/dist/cjs/email-locale/email-locale-code.js +228 -0
  37. package/dist/cjs/email-locale/email-locale-code.js.map +1 -0
  38. package/dist/cjs/email-locale/email-locale-scope.d.ts +46 -0
  39. package/dist/cjs/email-locale/email-locale-scope.d.ts.map +1 -0
  40. package/dist/cjs/email-locale/email-locale-scope.js +51 -0
  41. package/dist/cjs/email-locale/email-locale-scope.js.map +1 -0
  42. package/dist/cjs/email-locale/index.d.ts +11 -0
  43. package/dist/cjs/email-locale/index.d.ts.map +1 -0
  44. package/dist/cjs/email-locale/index.js +40 -0
  45. package/dist/cjs/email-locale/index.js.map +1 -0
  46. package/dist/cjs/executor-generator.d.ts +11 -1
  47. package/dist/cjs/executor-generator.d.ts.map +1 -1
  48. package/dist/cjs/executor-generator.js +49 -7
  49. package/dist/cjs/executor-generator.js.map +1 -1
  50. package/dist/cjs/index.d.ts +2 -0
  51. package/dist/cjs/index.d.ts.map +1 -1
  52. package/dist/cjs/index.js +9 -1
  53. package/dist/cjs/index.js.map +1 -1
  54. package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
  55. package/dist/cjs/invoice/api-routes-code.js +55 -6
  56. package/dist/cjs/invoice/api-routes-code.js.map +1 -1
  57. package/dist/cjs/invoice/email-sender-code.d.ts.map +1 -1
  58. package/dist/cjs/invoice/email-sender-code.js +72 -31
  59. package/dist/cjs/invoice/email-sender-code.js.map +1 -1
  60. package/dist/cjs/invoice/index.d.ts +1 -4
  61. package/dist/cjs/invoice/index.d.ts.map +1 -1
  62. package/dist/cjs/invoice/index.js +8 -19
  63. package/dist/cjs/invoice/index.js.map +1 -1
  64. package/dist/cjs/invoice/invoice-html-code.d.ts.map +1 -1
  65. package/dist/cjs/invoice/invoice-html-code.js +31 -8
  66. package/dist/cjs/invoice/invoice-html-code.js.map +1 -1
  67. package/dist/cjs/invoice/regional-invoice-tax-code.d.ts +25 -0
  68. package/dist/cjs/invoice/regional-invoice-tax-code.d.ts.map +1 -0
  69. package/dist/cjs/invoice/regional-invoice-tax-code.js +116 -0
  70. package/dist/cjs/invoice/regional-invoice-tax-code.js.map +1 -0
  71. package/dist/cjs/invoice/resolve-data-source.d.ts +6 -0
  72. package/dist/cjs/invoice/resolve-data-source.d.ts.map +1 -0
  73. package/dist/cjs/invoice/resolve-data-source.js +23 -0
  74. package/dist/cjs/invoice/resolve-data-source.js.map +1 -0
  75. package/dist/cjs/nodes/account/account-delete-current.d.ts.map +1 -1
  76. package/dist/cjs/nodes/account/account-delete-current.js +10 -3
  77. package/dist/cjs/nodes/account/account-delete-current.js.map +1 -1
  78. package/dist/cjs/nodes/account/account-login.d.ts.map +1 -1
  79. package/dist/cjs/nodes/account/account-login.js +3 -1
  80. package/dist/cjs/nodes/account/account-login.js.map +1 -1
  81. package/dist/cjs/nodes/account/account-logout.d.ts.map +1 -1
  82. package/dist/cjs/nodes/account/account-logout.js +4 -2
  83. package/dist/cjs/nodes/account/account-logout.js.map +1 -1
  84. package/dist/cjs/nodes/account/account-signup.d.ts.map +1 -1
  85. package/dist/cjs/nodes/account/account-signup.js +12 -2
  86. package/dist/cjs/nodes/account/account-signup.js.map +1 -1
  87. package/dist/cjs/nodes/account/account-social-login.d.ts.map +1 -1
  88. package/dist/cjs/nodes/account/account-social-login.js +4 -2
  89. package/dist/cjs/nodes/account/account-social-login.js.map +1 -1
  90. package/dist/cjs/nodes/cart/cart-clear.d.ts.map +1 -1
  91. package/dist/cjs/nodes/cart/cart-clear.js +6 -0
  92. package/dist/cjs/nodes/cart/cart-clear.js.map +1 -1
  93. package/dist/cjs/nodes/cart/cart-get-total.d.ts.map +1 -1
  94. package/dist/cjs/nodes/cart/cart-get-total.js +81 -5
  95. package/dist/cjs/nodes/cart/cart-get-total.js.map +1 -1
  96. package/dist/cjs/nodes/data/data-create-item.d.ts.map +1 -1
  97. package/dist/cjs/nodes/data/data-create-item.js +16 -0
  98. package/dist/cjs/nodes/data/data-create-item.js.map +1 -1
  99. package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.d.ts.map +1 -1
  100. package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.js +6 -0
  101. package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.js.map +1 -1
  102. package/dist/cjs/nodes/navigation/navigation-go-to-page.d.ts.map +1 -1
  103. package/dist/cjs/nodes/navigation/navigation-go-to-page.js +4 -1
  104. package/dist/cjs/nodes/navigation/navigation-go-to-page.js.map +1 -1
  105. package/dist/cjs/nodes/navigation/navigation-navigate-to-url.d.ts.map +1 -1
  106. package/dist/cjs/nodes/navigation/navigation-navigate-to-url.js +5 -2
  107. package/dist/cjs/nodes/navigation/navigation-navigate-to-url.js.map +1 -1
  108. package/dist/cjs/nodes/payment/payment-charge-user.d.ts.map +1 -1
  109. package/dist/cjs/nodes/payment/payment-charge-user.js +7 -2
  110. package/dist/cjs/nodes/payment/payment-charge-user.js.map +1 -1
  111. package/dist/cjs/segment-splitter.d.ts +1 -1
  112. package/dist/cjs/segment-splitter.d.ts.map +1 -1
  113. package/dist/cjs/segment-splitter.js +29 -2
  114. package/dist/cjs/segment-splitter.js.map +1 -1
  115. package/dist/cjs/sent-email-log/index.d.ts +16 -0
  116. package/dist/cjs/sent-email-log/index.d.ts.map +1 -0
  117. package/dist/cjs/sent-email-log/index.js +53 -0
  118. package/dist/cjs/sent-email-log/index.js.map +1 -0
  119. package/dist/cjs/sent-email-log/sent-email-log-code.d.ts +4 -0
  120. package/dist/cjs/sent-email-log/sent-email-log-code.d.ts.map +1 -0
  121. package/dist/cjs/sent-email-log/sent-email-log-code.js +415 -0
  122. package/dist/cjs/sent-email-log/sent-email-log-code.js.map +1 -0
  123. package/dist/cjs/sent-email-log/sent-email-log-scope.d.ts +21 -0
  124. package/dist/cjs/sent-email-log/sent-email-log-scope.d.ts.map +1 -0
  125. package/dist/cjs/sent-email-log/sent-email-log-scope.js +36 -0
  126. package/dist/cjs/sent-email-log/sent-email-log-scope.js.map +1 -0
  127. package/dist/cjs/transactional-email-code.d.ts +39 -1
  128. package/dist/cjs/transactional-email-code.d.ts.map +1 -1
  129. package/dist/cjs/transactional-email-code.js +86 -12
  130. package/dist/cjs/transactional-email-code.js.map +1 -1
  131. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  132. package/dist/cjs/webhook-generator.d.ts.map +1 -1
  133. package/dist/cjs/webhook-generator.js +9 -2
  134. package/dist/cjs/webhook-generator.js.map +1 -1
  135. package/dist/cjs/workflow-component-plugin.js +4 -3
  136. package/dist/cjs/workflow-component-plugin.js.map +1 -1
  137. package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
  138. package/dist/cjs/workflow-project-plugin.js +31 -3
  139. package/dist/cjs/workflow-project-plugin.js.map +1 -1
  140. package/dist/cjs/workflow-utils-alias.d.ts +21 -0
  141. package/dist/cjs/workflow-utils-alias.d.ts.map +1 -0
  142. package/dist/cjs/workflow-utils-alias.js +27 -0
  143. package/dist/cjs/workflow-utils-alias.js.map +1 -0
  144. package/dist/esm/account-delete-route-generator.d.ts +20 -0
  145. package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
  146. package/dist/esm/account-delete-route-generator.js +30 -27
  147. package/dist/esm/account-delete-route-generator.js.map +1 -1
  148. package/dist/esm/api-route-generator.d.ts.map +1 -1
  149. package/dist/esm/api-route-generator.js +57 -11
  150. package/dist/esm/api-route-generator.js.map +1 -1
  151. package/dist/esm/auth-generator.d.ts +2 -1
  152. package/dist/esm/auth-generator.d.ts.map +1 -1
  153. package/dist/esm/auth-generator.js +56 -19
  154. package/dist/esm/auth-generator.js.map +1 -1
  155. package/dist/esm/data-api-route-generator.d.ts.map +1 -1
  156. package/dist/esm/data-api-route-generator.js +19 -0
  157. package/dist/esm/data-api-route-generator.js.map +1 -1
  158. package/dist/esm/email-locale/email-locale-code.d.ts +25 -0
  159. package/dist/esm/email-locale/email-locale-code.d.ts.map +1 -0
  160. package/dist/esm/email-locale/email-locale-code.js +222 -0
  161. package/dist/esm/email-locale/email-locale-code.js.map +1 -0
  162. package/dist/esm/email-locale/email-locale-scope.d.ts +46 -0
  163. package/dist/esm/email-locale/email-locale-scope.d.ts.map +1 -0
  164. package/dist/esm/email-locale/email-locale-scope.js +47 -0
  165. package/dist/esm/email-locale/email-locale-scope.js.map +1 -0
  166. package/dist/esm/email-locale/index.d.ts +11 -0
  167. package/dist/esm/email-locale/index.d.ts.map +1 -0
  168. package/dist/esm/email-locale/index.js +28 -0
  169. package/dist/esm/email-locale/index.js.map +1 -0
  170. package/dist/esm/executor-generator.d.ts +11 -1
  171. package/dist/esm/executor-generator.d.ts.map +1 -1
  172. package/dist/esm/executor-generator.js +49 -7
  173. package/dist/esm/executor-generator.js.map +1 -1
  174. package/dist/esm/index.d.ts +2 -0
  175. package/dist/esm/index.d.ts.map +1 -1
  176. package/dist/esm/index.js +2 -0
  177. package/dist/esm/index.js.map +1 -1
  178. package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
  179. package/dist/esm/invoice/api-routes-code.js +55 -6
  180. package/dist/esm/invoice/api-routes-code.js.map +1 -1
  181. package/dist/esm/invoice/email-sender-code.d.ts.map +1 -1
  182. package/dist/esm/invoice/email-sender-code.js +72 -31
  183. package/dist/esm/invoice/email-sender-code.js.map +1 -1
  184. package/dist/esm/invoice/index.d.ts +1 -4
  185. package/dist/esm/invoice/index.d.ts.map +1 -1
  186. package/dist/esm/invoice/index.js +7 -18
  187. package/dist/esm/invoice/index.js.map +1 -1
  188. package/dist/esm/invoice/invoice-html-code.d.ts.map +1 -1
  189. package/dist/esm/invoice/invoice-html-code.js +31 -8
  190. package/dist/esm/invoice/invoice-html-code.js.map +1 -1
  191. package/dist/esm/invoice/regional-invoice-tax-code.d.ts +25 -0
  192. package/dist/esm/invoice/regional-invoice-tax-code.d.ts.map +1 -0
  193. package/dist/esm/invoice/regional-invoice-tax-code.js +113 -0
  194. package/dist/esm/invoice/regional-invoice-tax-code.js.map +1 -0
  195. package/dist/esm/invoice/resolve-data-source.d.ts +6 -0
  196. package/dist/esm/invoice/resolve-data-source.d.ts.map +1 -0
  197. package/dist/esm/invoice/resolve-data-source.js +19 -0
  198. package/dist/esm/invoice/resolve-data-source.js.map +1 -0
  199. package/dist/esm/nodes/account/account-delete-current.d.ts.map +1 -1
  200. package/dist/esm/nodes/account/account-delete-current.js +10 -3
  201. package/dist/esm/nodes/account/account-delete-current.js.map +1 -1
  202. package/dist/esm/nodes/account/account-login.d.ts.map +1 -1
  203. package/dist/esm/nodes/account/account-login.js +3 -1
  204. package/dist/esm/nodes/account/account-login.js.map +1 -1
  205. package/dist/esm/nodes/account/account-logout.d.ts.map +1 -1
  206. package/dist/esm/nodes/account/account-logout.js +4 -2
  207. package/dist/esm/nodes/account/account-logout.js.map +1 -1
  208. package/dist/esm/nodes/account/account-signup.d.ts.map +1 -1
  209. package/dist/esm/nodes/account/account-signup.js +12 -2
  210. package/dist/esm/nodes/account/account-signup.js.map +1 -1
  211. package/dist/esm/nodes/account/account-social-login.d.ts.map +1 -1
  212. package/dist/esm/nodes/account/account-social-login.js +4 -2
  213. package/dist/esm/nodes/account/account-social-login.js.map +1 -1
  214. package/dist/esm/nodes/cart/cart-clear.d.ts.map +1 -1
  215. package/dist/esm/nodes/cart/cart-clear.js +6 -0
  216. package/dist/esm/nodes/cart/cart-clear.js.map +1 -1
  217. package/dist/esm/nodes/cart/cart-get-total.d.ts.map +1 -1
  218. package/dist/esm/nodes/cart/cart-get-total.js +81 -5
  219. package/dist/esm/nodes/cart/cart-get-total.js.map +1 -1
  220. package/dist/esm/nodes/data/data-create-item.d.ts.map +1 -1
  221. package/dist/esm/nodes/data/data-create-item.js +16 -0
  222. package/dist/esm/nodes/data/data-create-item.js.map +1 -1
  223. package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.d.ts.map +1 -1
  224. package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.js +6 -0
  225. package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.js.map +1 -1
  226. package/dist/esm/nodes/navigation/navigation-go-to-page.d.ts.map +1 -1
  227. package/dist/esm/nodes/navigation/navigation-go-to-page.js +4 -1
  228. package/dist/esm/nodes/navigation/navigation-go-to-page.js.map +1 -1
  229. package/dist/esm/nodes/navigation/navigation-navigate-to-url.d.ts.map +1 -1
  230. package/dist/esm/nodes/navigation/navigation-navigate-to-url.js +5 -2
  231. package/dist/esm/nodes/navigation/navigation-navigate-to-url.js.map +1 -1
  232. package/dist/esm/nodes/payment/payment-charge-user.d.ts.map +1 -1
  233. package/dist/esm/nodes/payment/payment-charge-user.js +7 -2
  234. package/dist/esm/nodes/payment/payment-charge-user.js.map +1 -1
  235. package/dist/esm/segment-splitter.d.ts +1 -1
  236. package/dist/esm/segment-splitter.d.ts.map +1 -1
  237. package/dist/esm/segment-splitter.js +29 -2
  238. package/dist/esm/segment-splitter.js.map +1 -1
  239. package/dist/esm/sent-email-log/index.d.ts +16 -0
  240. package/dist/esm/sent-email-log/index.d.ts.map +1 -0
  241. package/dist/esm/sent-email-log/index.js +45 -0
  242. package/dist/esm/sent-email-log/index.js.map +1 -0
  243. package/dist/esm/sent-email-log/sent-email-log-code.d.ts +4 -0
  244. package/dist/esm/sent-email-log/sent-email-log-code.d.ts.map +1 -0
  245. package/dist/esm/sent-email-log/sent-email-log-code.js +411 -0
  246. package/dist/esm/sent-email-log/sent-email-log-code.js.map +1 -0
  247. package/dist/esm/sent-email-log/sent-email-log-scope.d.ts +21 -0
  248. package/dist/esm/sent-email-log/sent-email-log-scope.d.ts.map +1 -0
  249. package/dist/esm/sent-email-log/sent-email-log-scope.js +31 -0
  250. package/dist/esm/sent-email-log/sent-email-log-scope.js.map +1 -0
  251. package/dist/esm/transactional-email-code.d.ts +39 -1
  252. package/dist/esm/transactional-email-code.d.ts.map +1 -1
  253. package/dist/esm/transactional-email-code.js +81 -10
  254. package/dist/esm/transactional-email-code.js.map +1 -1
  255. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  256. package/dist/esm/webhook-generator.d.ts.map +1 -1
  257. package/dist/esm/webhook-generator.js +9 -2
  258. package/dist/esm/webhook-generator.js.map +1 -1
  259. package/dist/esm/workflow-component-plugin.js +4 -3
  260. package/dist/esm/workflow-component-plugin.js.map +1 -1
  261. package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
  262. package/dist/esm/workflow-project-plugin.js +32 -4
  263. package/dist/esm/workflow-project-plugin.js.map +1 -1
  264. package/dist/esm/workflow-utils-alias.d.ts +21 -0
  265. package/dist/esm/workflow-utils-alias.d.ts.map +1 -0
  266. package/dist/esm/workflow-utils-alias.js +21 -0
  267. package/dist/esm/workflow-utils-alias.js.map +1 -0
  268. package/package.json +4 -4
  269. package/src/account-delete-route-generator.ts +36 -7
  270. package/src/api-route-generator.ts +64 -11
  271. package/src/auth-generator.ts +63 -18
  272. package/src/data-api-route-generator.ts +19 -0
  273. package/src/email-locale/email-locale-code.ts +239 -0
  274. package/src/email-locale/email-locale-scope.ts +65 -0
  275. package/src/email-locale/index.ts +46 -0
  276. package/src/executor-generator.ts +65 -7
  277. package/src/index.ts +8 -0
  278. package/src/invoice/api-routes-code.ts +65 -6
  279. package/src/invoice/email-sender-code.ts +72 -31
  280. package/src/invoice/index.ts +7 -23
  281. package/src/invoice/invoice-html-code.ts +31 -8
  282. package/src/invoice/regional-invoice-tax-code.ts +112 -0
  283. package/src/invoice/resolve-data-source.ts +25 -0
  284. package/src/nodes/account/account-delete-current.ts +10 -3
  285. package/src/nodes/account/account-login.ts +3 -1
  286. package/src/nodes/account/account-logout.ts +4 -2
  287. package/src/nodes/account/account-signup.ts +12 -2
  288. package/src/nodes/account/account-social-login.ts +7 -2
  289. package/src/nodes/cart/cart-clear.ts +6 -0
  290. package/src/nodes/cart/cart-get-total.ts +94 -5
  291. package/src/nodes/data/data-create-item.ts +16 -0
  292. package/src/nodes/ecommerce/ecommerce-generate-invoice.ts +6 -0
  293. package/src/nodes/navigation/navigation-go-to-page.ts +5 -1
  294. package/src/nodes/navigation/navigation-navigate-to-url.ts +6 -2
  295. package/src/nodes/payment/payment-charge-user.ts +13 -2
  296. package/src/nodes/workflow-utils-global.d.ts +12 -0
  297. package/src/segment-splitter.ts +33 -2
  298. package/src/sent-email-log/index.ts +57 -0
  299. package/src/sent-email-log/sent-email-log-code.ts +419 -0
  300. package/src/sent-email-log/sent-email-log-scope.ts +36 -0
  301. package/src/transactional-email-code.ts +112 -4
  302. package/src/webhook-generator.ts +11 -2
  303. package/src/workflow-component-plugin.ts +4 -3
  304. package/src/workflow-project-plugin.ts +36 -4
  305. package/src/workflow-utils-alias.ts +26 -0
@@ -0,0 +1,323 @@
1
+ import {
2
+ generateEmailLocaleModuleCode,
3
+ resolveEmailLocaleConfig,
4
+ EMAIL_LOCALE_HEADER,
5
+ } from '../src/email-locale'
6
+
7
+ /**
8
+ * The shared locale module decides which language a customer email goes out
9
+ * in and which path a navigation lands on. It is EXECUTED here rather than
10
+ * grepped: every helper must be total (an unknown locale can never select a
11
+ * template that does not exist, nor send a visitor to a locale the app does
12
+ * not serve), and the precedence between the explicit header, the referring
13
+ * page and the Next.js cookie is what keeps a request without the header from
14
+ * silently falling back to the main language.
15
+ */
16
+
17
+ interface EmailLocaleModule {
18
+ EMAIL_LOCALES: string[]
19
+ DEFAULT_EMAIL_LOCALE: string
20
+ normalizeEmailLocale: (value: unknown) => string | null
21
+ resolveRequestLocale: (req: unknown) => string
22
+ getClientLocale: () => string | null
23
+ localizeHref: (href: unknown, locale: unknown) => unknown
24
+ pickLocalizedTemplate: (
25
+ base: { subject?: string; body?: string },
26
+ localized: unknown,
27
+ locale: unknown
28
+ ) => { subject?: string; body?: string; locale: string }
29
+ }
30
+
31
+ const loadModule = (config: { locales: string[]; defaultLocale: string }): EmailLocaleModule => {
32
+ const code = generateEmailLocaleModuleCode(config)
33
+ const moduleShim = { exports: {} as EmailLocaleModule }
34
+ // eslint-disable-next-line no-new-func
35
+ new Function('module', 'exports', 'require', code)(moduleShim, moduleShim.exports, () => ({}))
36
+ return moduleShim.exports
37
+ }
38
+
39
+ const request = (headers: Record<string, string | string[]>) => ({ headers })
40
+
41
+ describe('resolveEmailLocaleConfig', () => {
42
+ it('reads the project languages and the main locale off the UIDL', () => {
43
+ const uidl = {
44
+ internationalization: {
45
+ main: { name: 'English', locale: 'en' },
46
+ languages: { en: 'English', es: 'Spanish' },
47
+ translations: {},
48
+ },
49
+ } as any
50
+ expect(resolveEmailLocaleConfig(uidl)).toEqual({ locales: ['en', 'es'], defaultLocale: 'en' })
51
+ })
52
+
53
+ it('always lists the main locale, even when the language map omits it', () => {
54
+ const uidl = {
55
+ internationalization: {
56
+ main: { name: 'French', locale: 'fr' },
57
+ languages: { es: 'Spanish' },
58
+ translations: {},
59
+ },
60
+ } as any
61
+ expect(resolveEmailLocaleConfig(uidl)).toEqual({ locales: ['fr', 'es'], defaultLocale: 'fr' })
62
+ })
63
+
64
+ it('has no locales at all for a project without internationalization', () => {
65
+ expect(resolveEmailLocaleConfig({} as any)).toEqual({ locales: [], defaultLocale: '' })
66
+ })
67
+ })
68
+
69
+ describe('email-locale module', () => {
70
+ const locales = loadModule({ locales: ['en', 'es', 'pt-BR'], defaultLocale: 'en' })
71
+
72
+ describe('normalizeEmailLocale', () => {
73
+ it('answers the canonical code, case-insensitively', () => {
74
+ expect(locales.normalizeEmailLocale('es')).toBe('es')
75
+ expect(locales.normalizeEmailLocale(' ES ')).toBe('es')
76
+ expect(locales.normalizeEmailLocale('pt-br')).toBe('pt-BR')
77
+ })
78
+
79
+ it('rejects anything that is not a project locale', () => {
80
+ expect(locales.normalizeEmailLocale('de')).toBeNull()
81
+ expect(locales.normalizeEmailLocale('')).toBeNull()
82
+ expect(locales.normalizeEmailLocale(null)).toBeNull()
83
+ expect(locales.normalizeEmailLocale(42)).toBeNull()
84
+ expect(locales.normalizeEmailLocale({ locale: 'es' })).toBeNull()
85
+ })
86
+ })
87
+
88
+ describe('resolveRequestLocale', () => {
89
+ it('prefers the explicit header the client runtime sends', () => {
90
+ expect(
91
+ locales.resolveRequestLocale(
92
+ request({
93
+ [EMAIL_LOCALE_HEADER]: 'es',
94
+ cookie: 'NEXT_LOCALE=pt-BR',
95
+ referer: 'https://shop.example/pt-BR/checkout',
96
+ })
97
+ )
98
+ ).toBe('es')
99
+ })
100
+
101
+ it('takes the first value of a repeated header', () => {
102
+ expect(locales.resolveRequestLocale(request({ [EMAIL_LOCALE_HEADER]: ['es', 'en'] }))).toBe(
103
+ 'es'
104
+ )
105
+ })
106
+
107
+ it('falls back to the locale prefix of the referring page', () => {
108
+ expect(
109
+ locales.resolveRequestLocale(request({ referer: 'https://shop.example/es/cart' }))
110
+ ).toBe('es')
111
+ })
112
+
113
+ it('trusts the page the request came from over a stored locale cookie', () => {
114
+ expect(
115
+ locales.resolveRequestLocale(
116
+ request({ cookie: 'session=abc; NEXT_LOCALE=pt-BR; other=1', referer: 'https://x/es/' })
117
+ )
118
+ ).toBe('es')
119
+ })
120
+
121
+ it('falls back to the Next.js locale cookie when nothing names the page', () => {
122
+ expect(
123
+ locales.resolveRequestLocale(request({ cookie: 'session=abc; NEXT_LOCALE=pt-BR; other=1' }))
124
+ ).toBe('pt-BR')
125
+ })
126
+
127
+ it('reads an unprefixed referring page as the default language', () => {
128
+ expect(locales.resolveRequestLocale(request({ referer: 'https://shop.example/cart' }))).toBe(
129
+ 'en'
130
+ )
131
+ })
132
+
133
+ it('ignores values that are not project locales and lands on the default', () => {
134
+ expect(
135
+ locales.resolveRequestLocale(
136
+ request({
137
+ [EMAIL_LOCALE_HEADER]: 'de',
138
+ cookie: 'NEXT_LOCALE=fr',
139
+ referer: 'not a url',
140
+ })
141
+ )
142
+ ).toBe('en')
143
+ })
144
+
145
+ it('answers the default language for a request without headers', () => {
146
+ expect(locales.resolveRequestLocale(null)).toBe('en')
147
+ expect(locales.resolveRequestLocale({})).toBe('en')
148
+ })
149
+ })
150
+
151
+ describe('pickLocalizedTemplate', () => {
152
+ const base = { subject: 'Hello {{name}}', body: '<p>Hi {{name}}</p>' }
153
+ const localized = {
154
+ es: { subject: 'Hola {{name}}', body: '<p>Hola {{name}}</p>' },
155
+ 'pt-BR': { body: '<p>Olá {{name}}</p>' },
156
+ }
157
+
158
+ it('returns the copy of the requested language', () => {
159
+ expect(locales.pickLocalizedTemplate(base, localized, 'es')).toEqual({
160
+ subject: 'Hola {{name}}',
161
+ body: '<p>Hola {{name}}</p>',
162
+ locale: 'es',
163
+ })
164
+ })
165
+
166
+ it('keeps the base subject when the language has no subject of its own', () => {
167
+ expect(locales.pickLocalizedTemplate(base, localized, 'pt-br')).toEqual({
168
+ subject: 'Hello {{name}}',
169
+ body: '<p>Olá {{name}}</p>',
170
+ locale: 'pt-BR',
171
+ })
172
+ })
173
+
174
+ it('returns the base copy for the default language', () => {
175
+ expect(locales.pickLocalizedTemplate(base, localized, 'en')).toEqual({
176
+ ...base,
177
+ locale: 'en',
178
+ })
179
+ })
180
+
181
+ it('returns the base copy for a language without a copy, an unknown one, or none', () => {
182
+ const expected = { ...base, locale: 'en' }
183
+ expect(locales.pickLocalizedTemplate(base, { es: localized.es }, 'pt-BR')).toEqual(expected)
184
+ expect(locales.pickLocalizedTemplate(base, localized, 'de')).toEqual(expected)
185
+ expect(locales.pickLocalizedTemplate(base, localized, undefined)).toEqual(expected)
186
+ expect(locales.pickLocalizedTemplate(base, null, 'es')).toEqual(expected)
187
+ })
188
+
189
+ it('never selects a copy with an empty body', () => {
190
+ expect(
191
+ locales.pickLocalizedTemplate(base, { es: { subject: 'Hola', body: '' } }, 'es')
192
+ ).toEqual({ ...base, locale: 'en' })
193
+ })
194
+ })
195
+
196
+ describe('getClientLocale', () => {
197
+ const globalRef = global as unknown as Record<string, unknown>
198
+
199
+ const withBrowser = <T>(browser: Record<string, unknown>, run: () => T): T => {
200
+ globalRef.window = browser.window
201
+ globalRef.document = browser.document
202
+ try {
203
+ return run()
204
+ } finally {
205
+ delete globalRef.window
206
+ delete globalRef.document
207
+ }
208
+ }
209
+
210
+ it('is inert outside a browser', () => {
211
+ expect(locales.getClientLocale()).toBeNull()
212
+ })
213
+
214
+ it('reads the router live, so a client-side language switch is not lost', () => {
215
+ // After `router.push(..., { locale: 'es' })` Next.js updates the router
216
+ // and <html lang>, but the page data keeps the locale the document was
217
+ // served in.
218
+ expect(
219
+ withBrowser(
220
+ {
221
+ window: { next: { router: { locale: 'es' } }, __NEXT_DATA__: { locale: 'en' } },
222
+ document: { documentElement: { lang: 'es' } },
223
+ },
224
+ () => locales.getClientLocale()
225
+ )
226
+ ).toBe('es')
227
+ })
228
+
229
+ it('falls back to <html lang>, then to the page data', () => {
230
+ expect(
231
+ withBrowser(
232
+ {
233
+ window: { __NEXT_DATA__: { locale: 'en' } },
234
+ document: { documentElement: { lang: 'es' } },
235
+ },
236
+ () => locales.getClientLocale()
237
+ )
238
+ ).toBe('es')
239
+ expect(
240
+ withBrowser({ window: { __NEXT_DATA__: { locale: 'pt-br' } }, document: {} }, () =>
241
+ locales.getClientLocale()
242
+ )
243
+ ).toBe('pt-BR')
244
+ })
245
+
246
+ it('ignores a candidate that is not a project locale', () => {
247
+ expect(
248
+ withBrowser(
249
+ {
250
+ window: { next: { router: { locale: 'de' } } },
251
+ document: { documentElement: { lang: 'x' } },
252
+ },
253
+ () => locales.getClientLocale()
254
+ )
255
+ ).toBeNull()
256
+ })
257
+ })
258
+
259
+ describe('localizeHref', () => {
260
+ it('prefixes a site-relative page path with a non-default locale', () => {
261
+ expect(locales.localizeHref('/', 'es')).toBe('/es')
262
+ expect(locales.localizeHref('/sign-in', 'es')).toBe('/es/sign-in')
263
+ expect(locales.localizeHref('/orders/ORD-42?payment=success', 'pt-br')).toBe(
264
+ '/pt-BR/orders/ORD-42?payment=success'
265
+ )
266
+ expect(locales.localizeHref('/?ref=1#top', 'es')).toBe('/es?ref=1#top')
267
+ expect(locales.localizeHref('/products/', 'es')).toBe('/es/products/')
268
+ })
269
+
270
+ it('keeps the bare path for the default language, an unknown locale and no locale', () => {
271
+ expect(locales.localizeHref('/sign-in', 'en')).toBe('/sign-in')
272
+ expect(locales.localizeHref('/sign-in', 'de')).toBe('/sign-in')
273
+ expect(locales.localizeHref('/sign-in', undefined)).toBe('/sign-in')
274
+ expect(locales.localizeHref('/sign-in', null)).toBe('/sign-in')
275
+ })
276
+
277
+ it('never touches a path that already names a locale', () => {
278
+ expect(locales.localizeHref('/es/cart', 'es')).toBe('/es/cart')
279
+ expect(locales.localizeHref('/es', 'es')).toBe('/es')
280
+ expect(locales.localizeHref('/en/cart', 'es')).toBe('/en/cart')
281
+ })
282
+
283
+ it('never touches an API route, a Next.js internal path or a file', () => {
284
+ expect(locales.localizeHref('/api/invoices/download?id=1', 'es')).toBe(
285
+ '/api/invoices/download?id=1'
286
+ )
287
+ expect(locales.localizeHref('/api', 'es')).toBe('/api')
288
+ expect(locales.localizeHref('/_next/static/x.js', 'es')).toBe('/_next/static/x.js')
289
+ expect(locales.localizeHref('/brochure.pdf', 'es')).toBe('/brochure.pdf')
290
+ expect(locales.localizeHref('/sitemap.xml?v=2', 'es')).toBe('/sitemap.xml?v=2')
291
+ })
292
+
293
+ it('never touches anything that is not a site-relative path', () => {
294
+ expect(locales.localizeHref('https://shop.example/cart', 'es')).toBe(
295
+ 'https://shop.example/cart'
296
+ )
297
+ expect(locales.localizeHref('//cdn.example/x', 'es')).toBe('//cdn.example/x')
298
+ expect(locales.localizeHref('#top', 'es')).toBe('#top')
299
+ expect(locales.localizeHref('mailto:a@b.c', 'es')).toBe('mailto:a@b.c')
300
+ expect(locales.localizeHref('products', 'es')).toBe('products')
301
+ expect(locales.localizeHref('', 'es')).toBe('')
302
+ expect(locales.localizeHref(undefined, 'es')).toBeUndefined()
303
+ expect(locales.localizeHref(42, 'es')).toBe(42)
304
+ })
305
+ })
306
+ })
307
+
308
+ describe('email-locale module without internationalization', () => {
309
+ const none = loadModule({ locales: [], defaultLocale: '' })
310
+
311
+ it('recognises no locale and keeps the single template', () => {
312
+ expect(none.normalizeEmailLocale('en')).toBeNull()
313
+ expect(none.resolveRequestLocale(request({ [EMAIL_LOCALE_HEADER]: 'en' }))).toBe('')
314
+ expect(
315
+ none.pickLocalizedTemplate({ subject: 'S', body: 'B' }, { en: { body: 'X' } }, 'en')
316
+ ).toEqual({ subject: 'S', body: 'B', locale: '' })
317
+ })
318
+
319
+ it('never prefixes a path', () => {
320
+ expect(none.localizeHref('/sign-in', 'en')).toBe('/sign-in')
321
+ expect(none.localizeHref('/', 'es')).toBe('/')
322
+ })
323
+ })
@@ -0,0 +1,268 @@
1
+ import type { UIDLInvoiceEmailDelivery, UIDLInvoiceSettings } from '@teleporthq/teleport-types'
2
+ import { generateSignupRouteFile } from '../src/auth-generator'
3
+ import { generateAccountDeleteRoute } from '../src/account-delete-route-generator'
4
+ import { generateEmailSenderCode } from '../src/invoice/email-sender-code'
5
+ import { generateInvoiceGenerateRouteCode } from '../src/invoice/api-routes-code'
6
+ import { generateDataAPIRoute } from '../src/data-api-route-generator'
7
+ import { generateEmailLocaleModuleCode } from '../src/email-locale'
8
+ import { readLocalizedEmailTemplates } from '../src/transactional-email-code'
9
+ import { nodeRegistry } from '../src'
10
+
11
+ /**
12
+ * The email senders that live OUTSIDE the workflow runtime — the welcome and
13
+ * farewell routes, the invoice sender, the data-api that stamps an order's
14
+ * language — each read the shared locale module. These tests pin that every
15
+ * one of them selects the copy of the language it resolved, and that the
16
+ * order row keeps the storefront language it was written from.
17
+ */
18
+
19
+ const LOCALIZED = {
20
+ es: { subject: 'Bienvenido {{userName}}', body: '<p>Hola {{userName}}</p>' },
21
+ }
22
+
23
+ const extractFunctionSource = (haystack: string, funcDecl: string): string => {
24
+ const startIdx = haystack.indexOf(funcDecl)
25
+ if (startIdx === -1) {
26
+ throw new Error('Helper not found: ' + funcDecl)
27
+ }
28
+ let depth = 0
29
+ let i = haystack.indexOf('{', startIdx)
30
+ for (; i < haystack.length; i++) {
31
+ const ch = haystack.charAt(i)
32
+ if (ch === '{') {
33
+ depth++
34
+ } else if (ch === '}') {
35
+ depth--
36
+ if (depth === 0) {
37
+ return haystack.slice(startIdx, i + 1)
38
+ }
39
+ }
40
+ }
41
+ throw new Error('Unbalanced braces for ' + funcDecl)
42
+ }
43
+
44
+ const loadLocaleModule = () => {
45
+ const moduleShim = { exports: {} as Record<string, unknown> }
46
+ // eslint-disable-next-line no-new-func
47
+ new Function(
48
+ 'module',
49
+ 'exports',
50
+ generateEmailLocaleModuleCode({ locales: ['en', 'es'], defaultLocale: 'en' })
51
+ )(moduleShim, moduleShim.exports)
52
+ return moduleShim.exports
53
+ }
54
+
55
+ describe('readLocalizedEmailTemplates', () => {
56
+ it('keeps only well-formed copies', () => {
57
+ expect(
58
+ readLocalizedEmailTemplates({
59
+ es: { subject: 'S', body: 'B' },
60
+ fr: { body: 'B' },
61
+ de: { subject: 'only a subject' },
62
+ it: { subject: '', body: '' },
63
+ pt: 'B',
64
+ })
65
+ ).toEqual({ es: { subject: 'S', body: 'B' }, fr: { body: 'B' } })
66
+ })
67
+
68
+ it('answers no copies for anything that is not a map', () => {
69
+ expect(readLocalizedEmailTemplates(undefined)).toEqual({})
70
+ expect(readLocalizedEmailTemplates([{ body: 'B' }])).toEqual({})
71
+ expect(readLocalizedEmailTemplates('es')).toEqual({})
72
+ })
73
+ })
74
+
75
+ describe('welcome and farewell routes', () => {
76
+ const auth = { enabled: true, dataSourceType: 'postgresql' } as any
77
+ const signup = generateSignupRouteFile(auth, {
78
+ emailProvider: 'resend',
79
+ emailSubject: 'Welcome {{userName}}',
80
+ emailBodyHtml: '<p>Hi {{userName}}</p>',
81
+ localizedTemplates: LOCALIZED,
82
+ })
83
+ const del = generateAccountDeleteRoute({
84
+ emailProvider: 'resend',
85
+ emailSubject: 'Goodbye {{userName}}',
86
+ emailBodyHtml: '<p>Bye {{userName}}</p>',
87
+ localizedTemplates: LOCALIZED,
88
+ })
89
+
90
+ it('bake the per-language copies and require the locale module', () => {
91
+ expect(signup).toContain(`const WELCOME_EMAIL_LOCALIZED = ${JSON.stringify(LOCALIZED)};`)
92
+ expect(signup).toContain("var __emailLocale = require('../../../utils/email/email-locale');")
93
+ expect(del).toContain(`const EMAIL_LOCALIZED = ${JSON.stringify(LOCALIZED)};`)
94
+ expect(del).toContain("var __emailLocale = require('../../../utils/email/email-locale');")
95
+ })
96
+
97
+ it('send the copy of the request language', () => {
98
+ expect(signup).toContain('var copy = resolveWelcomeEmailCopy(locale);')
99
+ expect(signup).toContain('var subject = fillTemplate(copy.subject, tokenValues);')
100
+ expect(signup).toContain('var html = fillTemplate(copy.body, tokenValues);')
101
+ expect(del).toContain('var copy = resolveFarewellEmailCopy(locale);')
102
+ expect(del).toContain('var subject = fillTemplate(copy.subject, tokenValues);')
103
+ expect(del).toContain('var html = fillTemplate(copy.body, tokenValues);')
104
+ })
105
+
106
+ it('resolve the language off the request at the call site', () => {
107
+ expect(signup).toContain('newUser && newUser.id, __emailLocale.resolveRequestLocale(req));')
108
+ expect(del).toContain('}, userId, __emailLocale.resolveRequestLocale(req));')
109
+ })
110
+
111
+ it('the copy selector honours the locale module rules', () => {
112
+ const locale = loadLocaleModule()
113
+ const selector = extractFunctionSource(signup, 'function resolveWelcomeEmailCopy(')
114
+ // eslint-disable-next-line no-new-func
115
+ const resolveWelcomeEmailCopy = new Function(
116
+ '__emailLocale',
117
+ 'WELCOME_EMAIL_SUBJECT',
118
+ 'WELCOME_EMAIL_BODY_HTML',
119
+ 'WELCOME_EMAIL_LOCALIZED',
120
+ `${selector}; return resolveWelcomeEmailCopy;`
121
+ )(locale, 'Welcome {{userName}}', '<p>Hi {{userName}}</p>', LOCALIZED)
122
+ expect(resolveWelcomeEmailCopy('es')).toEqual({
123
+ subject: 'Bienvenido {{userName}}',
124
+ body: '<p>Hola {{userName}}</p>',
125
+ locale: 'es',
126
+ })
127
+ expect(resolveWelcomeEmailCopy('en')).toEqual({
128
+ subject: 'Welcome {{userName}}',
129
+ body: '<p>Hi {{userName}}</p>',
130
+ locale: 'en',
131
+ })
132
+ })
133
+
134
+ it('the signup route never inserts the copies as a user column', () => {
135
+ expect(signup).toContain('"localizedTemplates":1')
136
+ })
137
+ })
138
+
139
+ describe('invoice email', () => {
140
+ const delivery: UIDLInvoiceEmailDelivery = {
141
+ enabled: true,
142
+ provider: 'resend',
143
+ fromEmail: 'billing@example.com',
144
+ fromName: 'Billing',
145
+ subject: 'Invoice {{invoiceNumber}}',
146
+ body: '<p>Invoice {{invoiceNumber}}</p>',
147
+ secretKeys: {},
148
+ localizedTemplates: {
149
+ es: { subject: 'Factura {{invoiceNumber}}', body: '<p>Factura {{invoiceNumber}}</p>' },
150
+ },
151
+ }
152
+
153
+ it('the sender picks the copy of the invoice locale', () => {
154
+ const sender = generateEmailSenderCode(delivery)
155
+ expect(sender).toContain("var emailLocale = require('../email/email-locale');")
156
+ expect(sender).toContain(
157
+ `var LOCALIZED_TEMPLATES = ${JSON.stringify(delivery.localizedTemplates)};`
158
+ )
159
+
160
+ const locale = loadLocaleModule()
161
+ const buildEmailData = extractFunctionSource(sender, 'function buildEmailData(')
162
+ const pdfGenerator = {
163
+ buildDataContext: (data: { invoiceNumber: string }) => ({
164
+ invoiceNumber: data.invoiceNumber,
165
+ }),
166
+ }
167
+ const replacePlaceholders = (template: string, data: Record<string, string>) =>
168
+ template.replace(/\{\{(\w+)\}\}/g, (_m, key) => data[key] || '')
169
+ // eslint-disable-next-line no-new-func
170
+ const build = new Function(
171
+ 'emailLocale',
172
+ 'pdfGenerator',
173
+ 'replacePlaceholders',
174
+ 'SUBJECT_TEMPLATE',
175
+ 'BODY_TEMPLATE',
176
+ 'LOCALIZED_TEMPLATES',
177
+ `${buildEmailData}; return buildEmailData;`
178
+ )(
179
+ locale,
180
+ pdfGenerator,
181
+ replacePlaceholders,
182
+ delivery.subject,
183
+ delivery.body,
184
+ delivery.localizedTemplates
185
+ )
186
+ expect(build({ invoiceNumber: 'INV-7', locale: 'es', customerEmail: 'a@b.c' })).toMatchObject({
187
+ subject: 'Factura INV-7',
188
+ body: '<p>Factura INV-7</p>',
189
+ })
190
+ expect(build({ invoiceNumber: 'INV-7', customerEmail: 'a@b.c' })).toMatchObject({
191
+ subject: 'Invoice INV-7',
192
+ body: '<p>Invoice INV-7</p>',
193
+ })
194
+ })
195
+
196
+ it('the generate route resolves the locale: order row, then caller, then request', () => {
197
+ const settings = {
198
+ invoicePrefix: 'INV-',
199
+ defaultTaxRate: 0,
200
+ showDiscount: false,
201
+ template: { document: null as unknown },
202
+ tables: { invoicesTable: 'teleport_invoices', invoiceItemsTable: 'teleport_invoice_items' },
203
+ emailDelivery: delivery,
204
+ } as unknown as UIDLInvoiceSettings
205
+ const route = generateInvoiceGenerateRouteCode(settings)
206
+ expect(route).toContain("var emailLocale = require('../../../utils/email/email-locale');")
207
+ expect(route).toContain('var invoiceLocale = emailLocale.normalizeEmailLocale(orderRow.locale)')
208
+ expect(route).toContain('|| emailLocale.normalizeEmailLocale(body.locale)')
209
+ expect(route).toContain('|| emailLocale.resolveRequestLocale(req);')
210
+ expect(route).toContain('locale: invoiceLocale,')
211
+ })
212
+
213
+ it('a project without email delivery needs no locale module', () => {
214
+ const route = generateInvoiceGenerateRouteCode({
215
+ invoicePrefix: 'INV-',
216
+ emailDelivery: { enabled: false },
217
+ } as unknown as UIDLInvoiceSettings)
218
+ expect(route).not.toContain('email-locale')
219
+ expect(route).not.toContain('invoiceLocale')
220
+ })
221
+
222
+ it('the generate-invoice node forwards the run locale as a hint', () => {
223
+ const source = nodeRegistry['ecommerce-generate-invoice'].generateHandler()
224
+ expect(source).toContain('payload.locale = runLocale')
225
+ })
226
+ })
227
+
228
+ describe('data-api stamps the storefront language on an order', () => {
229
+ const code = generateDataAPIRoute()
230
+ const stamp = extractFunctionSource(code, 'function stampRequestLocale(')
231
+ // eslint-disable-next-line no-new-func
232
+ const stampRequestLocale = new Function(
233
+ 'LOCALE_STAMPED_TABLES',
234
+ 'LOCALE_COLUMN',
235
+ `${stamp}; return stampRequestLocale;`
236
+ )({ teleport_orders: 1 }, 'locale')
237
+
238
+ it('adds the locale to an orders insert when the table has the column', () => {
239
+ const entries = [['status', 'pending']]
240
+ expect(
241
+ stampRequestLocale('teleport_orders', entries, { locale: 'character varying' }, 'es')
242
+ ).toEqual([
243
+ ['status', 'pending'],
244
+ ['locale', 'es'],
245
+ ])
246
+ })
247
+
248
+ it('leaves the insert alone when the column, the locale or the table does not apply', () => {
249
+ const entries = [['status', 'pending']]
250
+ expect(stampRequestLocale('teleport_orders', entries, {}, 'es')).toBe(entries)
251
+ expect(stampRequestLocale('teleport_orders', entries, { locale: 'text' }, '')).toBe(entries)
252
+ expect(stampRequestLocale('teleport_products', entries, { locale: 'text' }, 'es')).toBe(entries)
253
+ })
254
+
255
+ it('never overrides a locale the workflow mapped itself', () => {
256
+ const entries = [['locale', 'fr']]
257
+ expect(stampRequestLocale('teleport_orders', entries, { locale: 'text' }, 'es')).toBe(entries)
258
+ })
259
+
260
+ it('is wired into handleCreate from the request body', () => {
261
+ expect(code).toContain(
262
+ 'entries = stampRequestLocale(tableName, entries, colTypes, body.__requestLocale);'
263
+ )
264
+ expect(nodeRegistry['data-create-item'].generateHandler()).toContain(
265
+ 'reqBody.__requestLocale = __runLocale'
266
+ )
267
+ })
268
+ })