@caoscompanybr/merlin 3.5.0

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 (762) hide show
  1. package/.claude/CLAUDE.md +216 -0
  2. package/.claude/hooks/README-license-gate.md +45 -0
  3. package/.claude/hooks/auto-summarize.js +47 -0
  4. package/.claude/hooks/context-monitor.js +60 -0
  5. package/.claude/hooks/doc-sync.js +111 -0
  6. package/.claude/hooks/license-gate.cjs +59 -0
  7. package/.claude/hooks/session-reset.js +27 -0
  8. package/.claude/hooks/thoughts-indexer.js +80 -0
  9. package/.claude/rules/merlin-constitution.md +27 -0
  10. package/.merlin-core/commands/README.md +19 -0
  11. package/.merlin-core/commands/founder-mode.md +51 -0
  12. package/.merlin-core/commands/git/commit.md +35 -0
  13. package/.merlin-core/commands/git/describe-pr.md +43 -0
  14. package/.merlin-core/commands/git/safe-commit.md +182 -0
  15. package/.merlin-core/commands/implementation/implement-plan.md +129 -0
  16. package/.merlin-core/commands/implementation/oneshot.md +63 -0
  17. package/.merlin-core/commands/implementation/tdd.md +152 -0
  18. package/.merlin-core/commands/planning/create-plan.md +184 -0
  19. package/.merlin-core/commands/planning/iterate-plan.md +45 -0
  20. package/.merlin-core/commands/planning/validate-plan.md +48 -0
  21. package/.merlin-core/commands/research/analyze-issue.md +155 -0
  22. package/.merlin-core/commands/research/research-codebase.md +157 -0
  23. package/.merlin-core/commands/review/adversarial-review.md +112 -0
  24. package/.merlin-core/commands/review/check.md +91 -0
  25. package/.merlin-core/commands/review/debug.md +135 -0
  26. package/.merlin-core/commands/review/doubts.md +178 -0
  27. package/.merlin-core/commands/review/engineering-audit.md +87 -0
  28. package/.merlin-core/commands/review/local-review.md +48 -0
  29. package/.merlin-core/commands/review/verify-goals.md +83 -0
  30. package/.merlin-core/commands/session/capture-feedback.md +74 -0
  31. package/.merlin-core/commands/session/capture-learning.md +155 -0
  32. package/.merlin-core/commands/session/check-objectives.md +85 -0
  33. package/.merlin-core/commands/session/conclude.md +125 -0
  34. package/.merlin-core/commands/session/create-handoff.md +88 -0
  35. package/.merlin-core/commands/session/create-objective.md +111 -0
  36. package/.merlin-core/commands/session/create-process.md +105 -0
  37. package/.merlin-core/commands/session/create-reminder.md +86 -0
  38. package/.merlin-core/commands/session/fast-start.md +261 -0
  39. package/.merlin-core/commands/session/recall-learnings.md +79 -0
  40. package/.merlin-core/commands/session/recall-processes.md +74 -0
  41. package/.merlin-core/commands/session/resume-handoff.md +51 -0
  42. package/.merlin-core/commands/session/run-process.md +53 -0
  43. package/.merlin-core/commands/special/beauty.md +89 -0
  44. package/.merlin-core/commands/special/common-ground.md +114 -0
  45. package/.merlin-core/commands/special/elicit.md +98 -0
  46. package/.merlin-core/commands/special/party.md +66 -0
  47. package/.merlin-core/commands/special/scrape.md +78 -0
  48. package/.merlin-core/commands/special/skill-audit.md +128 -0
  49. package/.merlin-core/commands/special/start-here.md +132 -0
  50. package/.merlin-core/constitution.md +442 -0
  51. package/.merlin-core/core/README.md +19 -0
  52. package/.merlin-core/core/alkimia/README.md +20 -0
  53. package/.merlin-core/core/alkimia/context/context-tracker.js +209 -0
  54. package/.merlin-core/core/alkimia/domain/domain-loader.js +215 -0
  55. package/.merlin-core/core/alkimia/engine.js +284 -0
  56. package/.merlin-core/core/alkimia/layers/l0-constitution.js +47 -0
  57. package/.merlin-core/core/alkimia/layers/l1-global.js +58 -0
  58. package/.merlin-core/core/alkimia/layers/l2-agent.js +58 -0
  59. package/.merlin-core/core/alkimia/layers/l3-workflow.js +54 -0
  60. package/.merlin-core/core/alkimia/layers/l4-task.js +45 -0
  61. package/.merlin-core/core/alkimia/layers/l5-squad.js +161 -0
  62. package/.merlin-core/core/alkimia/layers/l6-skill.js +520 -0
  63. package/.merlin-core/core/alkimia/layers/l7-star-command.js +87 -0
  64. package/.merlin-core/core/alkimia/layers/layer-processor.js +78 -0
  65. package/.merlin-core/core/alkimia/mandate.js +46 -0
  66. package/.merlin-core/core/alkimia/memory/doc-sync.js +201 -0
  67. package/.merlin-core/core/alkimia/memory/document-sharder.js +272 -0
  68. package/.merlin-core/core/alkimia/memory/git-history-retriever.js +225 -0
  69. package/.merlin-core/core/alkimia/memory/memory-bridge.js +97 -0
  70. package/.merlin-core/core/alkimia/memory/session-analyzer.js +400 -0
  71. package/.merlin-core/core/alkimia/memory/thoughts-indexer.js +477 -0
  72. package/.merlin-core/core/alkimia/memory/thoughts-provider.js +603 -0
  73. package/.merlin-core/core/alkimia/output/formatter.js +464 -0
  74. package/.merlin-core/core/alkimia/security/content-sanitizer.js +140 -0
  75. package/.merlin-core/core/alkimia/skill-importer.js +440 -0
  76. package/.merlin-core/core/alkimia/squads/default/.synapse/manifest +17 -0
  77. package/.merlin-core/core/alkimia/utils/frontmatter.js +321 -0
  78. package/.merlin-core/core/alkimia/utils/tokens.js +24 -0
  79. package/.merlin-core/core/approval/README.md +16 -0
  80. package/.merlin-core/core/approval/approval-engine.js +380 -0
  81. package/.merlin-core/core/approval/channels/cli-channel.js +50 -0
  82. package/.merlin-core/core/config/README.md +17 -0
  83. package/.merlin-core/core/config/config-cache.js +182 -0
  84. package/.merlin-core/core/config/config-loader.js +279 -0
  85. package/.merlin-core/core/config/config-resolver.js +411 -0
  86. package/.merlin-core/core/config/env-interpolator.js +123 -0
  87. package/.merlin-core/core/config/merge-utils.js +102 -0
  88. package/.merlin-core/core/config/schemas/core-config.schema.json +41 -0
  89. package/.merlin-core/core/config/schemas/framework-config.schema.json +24 -0
  90. package/.merlin-core/core/config/schemas/local-config.schema.json +23 -0
  91. package/.merlin-core/core/config/schemas/project-config.schema.json +189 -0
  92. package/.merlin-core/core/docs-consistency.js +140 -0
  93. package/.merlin-core/core/events/event-bus.js +344 -0
  94. package/.merlin-core/core/events/hook-handler.js +419 -0
  95. package/.merlin-core/core/execution/README.md +17 -0
  96. package/.merlin-core/core/execution/attempt-journal.js +380 -0
  97. package/.merlin-core/core/execution/autonomous-build-loop.js +637 -0
  98. package/.merlin-core/core/execution/build-orchestrator.js +296 -0
  99. package/.merlin-core/core/execution/build-state-manager.js +196 -0
  100. package/.merlin-core/core/execution/context-injector.js +204 -0
  101. package/.merlin-core/core/execution/cron-engine.js +247 -0
  102. package/.merlin-core/core/execution/cron-expression.js +148 -0
  103. package/.merlin-core/core/execution/env-preflight.js +423 -0
  104. package/.merlin-core/core/execution/guardrail-engine.js +745 -0
  105. package/.merlin-core/core/execution/heartbeat-engine.js +198 -0
  106. package/.merlin-core/core/execution/model-router.js +282 -0
  107. package/.merlin-core/core/execution/parallel-executor.js +378 -0
  108. package/.merlin-core/core/execution/parallel-monitor.js +201 -0
  109. package/.merlin-core/core/execution/party-session.js +311 -0
  110. package/.merlin-core/core/execution/rate-limit-manager.js +152 -0
  111. package/.merlin-core/core/execution/result-aggregator.js +215 -0
  112. package/.merlin-core/core/execution/semantic-merge-engine.js +320 -0
  113. package/.merlin-core/core/execution/subagent-dispatcher.js +721 -0
  114. package/.merlin-core/core/execution/success-verifier.js +227 -0
  115. package/.merlin-core/core/execution/task-metadata.js +105 -0
  116. package/.merlin-core/core/execution/team-executor.js +195 -0
  117. package/.merlin-core/core/execution/two-tier-editor.js +290 -0
  118. package/.merlin-core/core/execution/version-snapshot.js +294 -0
  119. package/.merlin-core/core/execution/wave-executor.js +224 -0
  120. package/.merlin-core/core/health-check/health-engine.js +415 -0
  121. package/.merlin-core/core/licensing/activation.js +281 -0
  122. package/.merlin-core/core/licensing/crc.js +103 -0
  123. package/.merlin-core/core/licensing/entitlement.js +99 -0
  124. package/.merlin-core/core/licensing/fingerprint.js +104 -0
  125. package/.merlin-core/core/licensing/gate.js +133 -0
  126. package/.merlin-core/core/licensing/hmac.js +42 -0
  127. package/.merlin-core/core/licensing/key.js +144 -0
  128. package/.merlin-core/core/licensing/license.js +212 -0
  129. package/.merlin-core/core/mcp/README.md +16 -0
  130. package/.merlin-core/core/mcp/browser-capability.js +191 -0
  131. package/.merlin-core/core/mcp/capability-mapper.js +92 -0
  132. package/.merlin-core/core/mcp/mcp-connector.js +278 -0
  133. package/.merlin-core/core/mcp/mcp-registry.js +101 -0
  134. package/.merlin-core/core/orchestration/README.md +17 -0
  135. package/.merlin-core/core/orchestration/agent-invoker.js +456 -0
  136. package/.merlin-core/core/orchestration/condition-evaluator.js +250 -0
  137. package/.merlin-core/core/orchestration/decision-tree.js +192 -0
  138. package/.merlin-core/core/orchestration/executor-assignment.js +372 -0
  139. package/.merlin-core/core/orchestration/gate-evaluator.js +653 -0
  140. package/.merlin-core/core/orchestration/intent-classifier.js +579 -0
  141. package/.merlin-core/core/orchestration/lock-manager.js +308 -0
  142. package/.merlin-core/core/orchestration/master-orchestrator.js +363 -0
  143. package/.merlin-core/core/orchestration/phase-tool-masks.js +194 -0
  144. package/.merlin-core/core/orchestration/recovery-handler.js +402 -0
  145. package/.merlin-core/core/orchestration/reflect-checkpoint.js +431 -0
  146. package/.merlin-core/core/orchestration/session-state.js +430 -0
  147. package/.merlin-core/core/orchestration/skill-dispatcher.js +255 -0
  148. package/.merlin-core/core/orchestration/step-loader.js +226 -0
  149. package/.merlin-core/core/orchestration/workflow-executor.js +864 -0
  150. package/.merlin-core/core/process/executor.js +231 -0
  151. package/.merlin-core/core/process/process-file.js +50 -0
  152. package/.merlin-core/core/process/secret-scan.js +86 -0
  153. package/.merlin-core/core/process/signature.js +77 -0
  154. package/.merlin-core/core/quality-gates/README.md +17 -0
  155. package/.merlin-core/core/quality-gates/layer1-precommit.js +110 -0
  156. package/.merlin-core/core/quality-gates/layer2-pr-automation.js +116 -0
  157. package/.merlin-core/core/quality-gates/layer3-human-review.js +133 -0
  158. package/.merlin-core/core/registry/service-registry.js +140 -0
  159. package/.merlin-core/core-config.yaml +159 -0
  160. package/.merlin-core/development/README.md +17 -0
  161. package/.merlin-core/development/agents/README.md +16 -0
  162. package/.merlin-core/development/agents/analyst.md +214 -0
  163. package/.merlin-core/development/agents/architect.md +166 -0
  164. package/.merlin-core/development/agents/data-engineer.md +154 -0
  165. package/.merlin-core/development/agents/dev.md +203 -0
  166. package/.merlin-core/development/agents/devops.md +236 -0
  167. package/.merlin-core/development/agents/grimorio.md +125 -0
  168. package/.merlin-core/development/agents/merlin-master.md +173 -0
  169. package/.merlin-core/development/agents/meta.md +190 -0
  170. package/.merlin-core/development/agents/pm.md +145 -0
  171. package/.merlin-core/development/agents/po.md +172 -0
  172. package/.merlin-core/development/agents/qa.md +275 -0
  173. package/.merlin-core/development/agents/researcher.md +218 -0
  174. package/.merlin-core/development/agents/scout.md +179 -0
  175. package/.merlin-core/development/agents/sm.md +148 -0
  176. package/.merlin-core/development/agents/ux.md +169 -0
  177. package/.merlin-core/development/agents/web-researcher.md +203 -0
  178. package/.merlin-core/development/checklists/adversarial-review-checklist.md +70 -0
  179. package/.merlin-core/development/checklists/operations-ci-checklist.md +40 -0
  180. package/.merlin-core/development/checklists/operations-deploy-checklist.md +54 -0
  181. package/.merlin-core/development/checklists/operations-publish-checklist.md +47 -0
  182. package/.merlin-core/development/checklists/source-verification-checklist.md +38 -0
  183. package/.merlin-core/development/templates/HEARTBEAT-template.md +46 -0
  184. package/.merlin-core/development/templates/ears-requirements-template.md +93 -0
  185. package/.merlin-core/development/templates/handoff-template.md +50 -0
  186. package/.merlin-core/development/templates/prd-template.md +62 -0
  187. package/.merlin-core/development/templates/research-template.md +53 -0
  188. package/.merlin-core/development/templates/spec-template.md +84 -0
  189. package/.merlin-core/development/workflows/brownfield-discovery.yaml +166 -0
  190. package/.merlin-core/development/workflows/brownfield-service.yaml +52 -0
  191. package/.merlin-core/development/workflows/development-cycle.yaml +57 -0
  192. package/.merlin-core/development/workflows/epic-orchestration.yaml +47 -0
  193. package/.merlin-core/development/workflows/folloni-funnel.yaml +177 -0
  194. package/.merlin-core/development/workflows/greenfield-fullstack.yaml +167 -0
  195. package/.merlin-core/development/workflows/greenfield-service.yaml +56 -0
  196. package/.merlin-core/development/workflows/qa-loop.yaml +115 -0
  197. package/.merlin-core/development/workflows/spec-pipeline.yaml +185 -0
  198. package/.merlin-core/development/workflows/steps/folloni-01-research.yaml +35 -0
  199. package/.merlin-core/development/workflows/steps/folloni-02-architecture.yaml +41 -0
  200. package/.merlin-core/development/workflows/steps/folloni-03-implementation.yaml +52 -0
  201. package/.merlin-core/development/workflows/story-development-cycle.yaml +67 -0
  202. package/.merlin-core/docs/GUIDE.md +413 -0
  203. package/.merlin-core/docs/merlin-commands-guide-pt.md +183 -0
  204. package/.merlin-core/framework-config.yaml +148 -0
  205. package/.merlin-core/hooks/README.md +16 -0
  206. package/.merlin-core/hooks/precompact-memory-flush.js +69 -0
  207. package/.merlin-core/hooks/pretooluse-remote-approve.js +113 -0
  208. package/.merlin-core/hooks/spikes/spike-b-hook.js +70 -0
  209. package/.merlin-core/hooks/spikes/spike-b-stub.js +70 -0
  210. package/.merlin-core/index.js +91 -0
  211. package/.merlin-core/local-config.yaml.template +31 -0
  212. package/.merlin-core/mcp-servers/lsp-bridge/index.js +397 -0
  213. package/.merlin-core/modules/scraping/module.json +23 -0
  214. package/.merlin-core/project-config.yaml +89 -0
  215. package/.merlin-core/schemas/README.md +18 -0
  216. package/.merlin-core/schemas/agent-hook-schema.json +152 -0
  217. package/.merlin-core/schemas/agent-schema.json +31 -0
  218. package/.merlin-core/schemas/command-schema.json +18 -0
  219. package/.merlin-core/schemas/feedback-schema.json +36 -0
  220. package/.merlin-core/schemas/handoff-schema.json +19 -0
  221. package/.merlin-core/schemas/learning-schema.json +51 -0
  222. package/.merlin-core/schemas/module.schema.json +124 -0
  223. package/.merlin-core/schemas/must-haves-schema.json +95 -0
  224. package/.merlin-core/schemas/objective-schema.json +23 -0
  225. package/.merlin-core/schemas/plan-schema.json +20 -0
  226. package/.merlin-core/schemas/process-schema.json +82 -0
  227. package/.merlin-core/schemas/reminder-schema.json +20 -0
  228. package/.merlin-core/schemas/skill-eval-schema.json +92 -0
  229. package/.merlin-core/schemas/skill-schema.json +77 -0
  230. package/.merlin-core/schemas/workflow-schema.json +38 -0
  231. package/.merlin-core/skills/README.md +16 -0
  232. package/.merlin-core/skills/domain/azure-cloud/SKILL.md +211 -0
  233. package/.merlin-core/skills/domain/azure-cloud/references/appinsights-instrumentation.md +63 -0
  234. package/.merlin-core/skills/domain/azure-cloud/references/azure-compliance.md +99 -0
  235. package/.merlin-core/skills/domain/azure-cloud/references/azure-cost-optimization.md +419 -0
  236. package/.merlin-core/skills/domain/azure-cloud/references/azure-deploy.md +82 -0
  237. package/.merlin-core/skills/domain/azure-cloud/references/azure-diagnostics.md +130 -0
  238. package/.merlin-core/skills/domain/azure-cloud/references/azure-prepare.md +134 -0
  239. package/.merlin-core/skills/domain/azure-cloud/references/azure-quotas.md +290 -0
  240. package/.merlin-core/skills/domain/azure-cloud/references/azure-rbac.md +11 -0
  241. package/.merlin-core/skills/domain/azure-cloud/references/azure-resource-lookup.md +97 -0
  242. package/.merlin-core/skills/domain/azure-cloud/references/azure-resource-visualizer.md +178 -0
  243. package/.merlin-core/skills/domain/azure-cloud/references/azure-storage.md +91 -0
  244. package/.merlin-core/skills/domain/azure-cloud/references/azure-validate.md +58 -0
  245. package/.merlin-core/skills/domain/azure-cloud/references/entra-app-registration.md +192 -0
  246. package/.merlin-core/skills/domain/browser-automation/SKILL.md +311 -0
  247. package/.merlin-core/skills/domain/browser-automation/references/agent-browser-skill.md +632 -0
  248. package/.merlin-core/skills/domain/browser-automation/references/authentication.md +308 -0
  249. package/.merlin-core/skills/domain/browser-automation/references/commands.md +266 -0
  250. package/.merlin-core/skills/domain/browser-automation/references/profiling.md +120 -0
  251. package/.merlin-core/skills/domain/browser-automation/references/proxy-support.md +194 -0
  252. package/.merlin-core/skills/domain/browser-automation/references/session-management.md +194 -0
  253. package/.merlin-core/skills/domain/browser-automation/references/snapshot-refs.md +196 -0
  254. package/.merlin-core/skills/domain/browser-automation/references/video-recording.md +173 -0
  255. package/.merlin-core/skills/domain/browser-automation/templates/authenticated-session.sh +105 -0
  256. package/.merlin-core/skills/domain/browser-automation/templates/capture-workflow.sh +69 -0
  257. package/.merlin-core/skills/domain/browser-automation/templates/form-automation.sh +62 -0
  258. package/.merlin-core/skills/domain/digital-marketing/SKILL.md +292 -0
  259. package/.merlin-core/skills/domain/digital-marketing/references/content-strategy.md +320 -0
  260. package/.merlin-core/skills/domain/digital-marketing/references/copy-formats.md +298 -0
  261. package/.merlin-core/skills/domain/digital-marketing/references/copy-methodology.md +180 -0
  262. package/.merlin-core/skills/domain/digital-marketing/references/email-sequences.md +135 -0
  263. package/.merlin-core/skills/domain/digital-marketing/references/launch-strategy.md +213 -0
  264. package/.merlin-core/skills/domain/digital-marketing/references/pricing-strategy.md +160 -0
  265. package/.merlin-core/skills/domain/digital-marketing/references/programmatic-seo.md +237 -0
  266. package/.merlin-core/skills/domain/digital-marketing/references/revops-lifecycle.md +170 -0
  267. package/.merlin-core/skills/domain/digital-marketing/references/revops-operations.md +167 -0
  268. package/.merlin-core/skills/domain/digital-marketing/references/schema-markup.md +190 -0
  269. package/.merlin-core/skills/domain/digital-marketing/references/strategy-frameworks.md +324 -0
  270. package/.merlin-core/skills/domain/digital-marketing/references/traffic-management.md +350 -0
  271. package/.merlin-core/skills/domain/expo-native-ui/SKILL.md +348 -0
  272. package/.merlin-core/skills/domain/expo-native-ui/references/animations.md +220 -0
  273. package/.merlin-core/skills/domain/expo-native-ui/references/api-routes.md +361 -0
  274. package/.merlin-core/skills/domain/expo-native-ui/references/cicd-workflows.md +84 -0
  275. package/.merlin-core/skills/domain/expo-native-ui/references/controls.md +266 -0
  276. package/.merlin-core/skills/domain/expo-native-ui/references/data-fetching.md +553 -0
  277. package/.merlin-core/skills/domain/expo-native-ui/references/deployment-stores.md +1353 -0
  278. package/.merlin-core/skills/domain/expo-native-ui/references/deployment.md +183 -0
  279. package/.merlin-core/skills/domain/expo-native-ui/references/dev-client.md +166 -0
  280. package/.merlin-core/skills/domain/expo-native-ui/references/dom-components.md +410 -0
  281. package/.merlin-core/skills/domain/expo-native-ui/references/form-sheet.md +253 -0
  282. package/.merlin-core/skills/domain/expo-native-ui/references/gradients.md +117 -0
  283. package/.merlin-core/skills/domain/expo-native-ui/references/icons.md +218 -0
  284. package/.merlin-core/skills/domain/expo-native-ui/references/media.md +245 -0
  285. package/.merlin-core/skills/domain/expo-native-ui/references/platform-native.md +75 -0
  286. package/.merlin-core/skills/domain/expo-native-ui/references/route-structure.md +229 -0
  287. package/.merlin-core/skills/domain/expo-native-ui/references/search.md +249 -0
  288. package/.merlin-core/skills/domain/expo-native-ui/references/storage.md +121 -0
  289. package/.merlin-core/skills/domain/expo-native-ui/references/tabs.md +433 -0
  290. package/.merlin-core/skills/domain/expo-native-ui/references/tailwind-native.md +473 -0
  291. package/.merlin-core/skills/domain/expo-native-ui/references/toolbar-and-headers.md +284 -0
  292. package/.merlin-core/skills/domain/expo-native-ui/references/upgrading-guides.md +674 -0
  293. package/.merlin-core/skills/domain/expo-native-ui/references/upgrading.md +127 -0
  294. package/.merlin-core/skills/domain/expo-native-ui/references/visual-effects.md +199 -0
  295. package/.merlin-core/skills/domain/expo-native-ui/references/webgpu-three.md +605 -0
  296. package/.merlin-core/skills/domain/expo-native-ui/references/zoom-transitions.md +161 -0
  297. package/.merlin-core/skills/domain/marketing-ops/SKILL.md +117 -0
  298. package/.merlin-core/skills/domain/marketing-ops/references/_index.md +78 -0
  299. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ad-creative/references/generative-tools.md +19 -0
  300. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ad-creative/references/platform-specs.md +19 -0
  301. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ad-creative.md +251 -0
  302. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/ad-copy-templates.md +19 -0
  303. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/audience-targeting.md +19 -0
  304. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/conversion-tracking.md +19 -0
  305. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/platform-setup-checklists.md +19 -0
  306. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads.md +322 -0
  307. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo/references/content-patterns.md +19 -0
  308. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo/references/content-types.md +19 -0
  309. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo/references/platform-ranking-factors.md +19 -0
  310. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo.md +388 -0
  311. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/apple-specs.md +19 -0
  312. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/benchmarks.md +19 -0
  313. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/google-play-specs.md +19 -0
  314. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/report-template.md +19 -0
  315. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/scoring-criteria.md +19 -0
  316. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso.md +316 -0
  317. package/.merlin-core/skills/domain/marketing-ops/references/acquire/co-marketing.md +305 -0
  318. package/.merlin-core/skills/domain/marketing-ops/references/acquire/community-marketing.md +169 -0
  319. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitor-profiling/references/templates.md +19 -0
  320. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitor-profiling/references/tool-reference.md +19 -0
  321. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitor-profiling.md +442 -0
  322. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitors/references/content-architecture.md +19 -0
  323. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitors/references/templates.md +19 -0
  324. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitors.md +281 -0
  325. package/.merlin-core/skills/domain/marketing-ops/references/acquire/content-strategy.md +16 -0
  326. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions/references/directory-list.md +19 -0
  327. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions/references/positioning-variations.md +19 -0
  328. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions/references/submission-tracker-template.md +19 -0
  329. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions.md +396 -0
  330. package/.merlin-core/skills/domain/marketing-ops/references/acquire/free-tools/references/tool-types.md +19 -0
  331. package/.merlin-core/skills/domain/marketing-ops/references/acquire/free-tools.md +196 -0
  332. package/.merlin-core/skills/domain/marketing-ops/references/acquire/image/references/ai-image-prompting.md +19 -0
  333. package/.merlin-core/skills/domain/marketing-ops/references/acquire/image.md +352 -0
  334. package/.merlin-core/skills/domain/marketing-ops/references/acquire/launch.md +18 -0
  335. package/.merlin-core/skills/domain/marketing-ops/references/acquire/lead-magnets/references/benchmarks.md +19 -0
  336. package/.merlin-core/skills/domain/marketing-ops/references/acquire/lead-magnets/references/format-guide.md +19 -0
  337. package/.merlin-core/skills/domain/marketing-ops/references/acquire/lead-magnets.md +333 -0
  338. package/.merlin-core/skills/domain/marketing-ops/references/acquire/programmatic-seo.md +16 -0
  339. package/.merlin-core/skills/domain/marketing-ops/references/acquire/schema.md +16 -0
  340. package/.merlin-core/skills/domain/marketing-ops/references/acquire/seo-audit/references/ai-writing-detection.md +19 -0
  341. package/.merlin-core/skills/domain/marketing-ops/references/acquire/seo-audit/references/international-seo.md +19 -0
  342. package/.merlin-core/skills/domain/marketing-ops/references/acquire/seo-audit.md +546 -0
  343. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture/references/mermaid-templates.md +19 -0
  344. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture/references/navigation-patterns.md +19 -0
  345. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture/references/site-type-templates.md +19 -0
  346. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture.md +371 -0
  347. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/platform-limits.md +19 -0
  348. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/platforms.md +19 -0
  349. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/post-templates.md +19 -0
  350. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/reverse-engineering.md +19 -0
  351. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/short-form-video.md +19 -0
  352. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social.md +431 -0
  353. package/.merlin-core/skills/domain/marketing-ops/references/acquire/video/references/ai-video-prompting.md +19 -0
  354. package/.merlin-core/skills/domain/marketing-ops/references/acquire/video.md +353 -0
  355. package/.merlin-core/skills/domain/marketing-ops/references/activate/ab-testing/references/sample-size-guide.md +19 -0
  356. package/.merlin-core/skills/domain/marketing-ops/references/activate/ab-testing/references/test-templates.md +19 -0
  357. package/.merlin-core/skills/domain/marketing-ops/references/activate/ab-testing.md +379 -0
  358. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics/references/event-library.md +19 -0
  359. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics/references/ga4-implementation.md +19 -0
  360. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics/references/gtm-implementation.md +19 -0
  361. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics.md +323 -0
  362. package/.merlin-core/skills/domain/marketing-ops/references/activate/copy-editing.md +18 -0
  363. package/.merlin-core/skills/domain/marketing-ops/references/activate/copywriting.md +18 -0
  364. package/.merlin-core/skills/domain/marketing-ops/references/activate/cro/references/experiments.md +19 -0
  365. package/.merlin-core/skills/domain/marketing-ops/references/activate/cro/references/form.md +19 -0
  366. package/.merlin-core/skills/domain/marketing-ops/references/activate/cro.md +211 -0
  367. package/.merlin-core/skills/domain/marketing-ops/references/activate/emails.md +18 -0
  368. package/.merlin-core/skills/domain/marketing-ops/references/activate/paywalls/references/experiments.md +19 -0
  369. package/.merlin-core/skills/domain/marketing-ops/references/activate/paywalls.md +255 -0
  370. package/.merlin-core/skills/domain/marketing-ops/references/activate/popups.md +518 -0
  371. package/.merlin-core/skills/domain/marketing-ops/references/activate/pricing.md +18 -0
  372. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/deck-frameworks.md +19 -0
  373. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/demo-scripts.md +19 -0
  374. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/objection-library.md +19 -0
  375. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/one-pager-templates.md +19 -0
  376. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement.md +371 -0
  377. package/.merlin-core/skills/domain/marketing-ops/references/activate/signup.md +406 -0
  378. package/.merlin-core/skills/domain/marketing-ops/references/expand/co-marketing.md +18 -0
  379. package/.merlin-core/skills/domain/marketing-ops/references/expand/community-marketing.md +18 -0
  380. package/.merlin-core/skills/domain/marketing-ops/references/expand/referrals/references/affiliate-programs.md +19 -0
  381. package/.merlin-core/skills/domain/marketing-ops/references/expand/referrals/references/program-examples.md +19 -0
  382. package/.merlin-core/skills/domain/marketing-ops/references/expand/referrals.md +278 -0
  383. package/.merlin-core/skills/domain/marketing-ops/references/foundation/customer-research/references/source-guides.md +425 -0
  384. package/.merlin-core/skills/domain/marketing-ops/references/foundation/customer-research.md +284 -0
  385. package/.merlin-core/skills/domain/marketing-ops/references/foundation/marketing-ideas/references/ideas-by-category.md +216 -0
  386. package/.merlin-core/skills/domain/marketing-ops/references/foundation/marketing-ideas.md +188 -0
  387. package/.merlin-core/skills/domain/marketing-ops/references/foundation/marketing-psychology.md +532 -0
  388. package/.merlin-core/skills/domain/marketing-ops/references/foundation/product-marketing.md +276 -0
  389. package/.merlin-core/skills/domain/marketing-ops/references/retain/churn-prevention/references/cancel-flow-patterns.md +19 -0
  390. package/.merlin-core/skills/domain/marketing-ops/references/retain/churn-prevention/references/dunning-playbook.md +19 -0
  391. package/.merlin-core/skills/domain/marketing-ops/references/retain/churn-prevention.md +442 -0
  392. package/.merlin-core/skills/domain/marketing-ops/references/retain/onboarding/references/experiments.md +19 -0
  393. package/.merlin-core/skills/domain/marketing-ops/references/retain/onboarding.md +243 -0
  394. package/.merlin-core/skills/domain/marketing-ops/references/retain/revops-lifecycle.md +18 -0
  395. package/.merlin-core/skills/domain/marketing-ops/references/retain/revops-operations.md +18 -0
  396. package/.merlin-core/skills/domain/n8n-automation/SKILL.md +149 -0
  397. package/.merlin-core/skills/domain/n8n-automation/references/code-javascript.md +3744 -0
  398. package/.merlin-core/skills/domain/n8n-automation/references/code-python.md +3293 -0
  399. package/.merlin-core/skills/domain/n8n-automation/references/expression-syntax.md +1662 -0
  400. package/.merlin-core/skills/domain/n8n-automation/references/mcp-tools-expert.md +2111 -0
  401. package/.merlin-core/skills/domain/n8n-automation/references/node-configuration.md +2523 -0
  402. package/.merlin-core/skills/domain/n8n-automation/references/validation-expert.md +2491 -0
  403. package/.merlin-core/skills/domain/n8n-automation/references/workflow-patterns.md +4624 -0
  404. package/.merlin-core/skills/domain/ops-manual/SKILL.md +225 -0
  405. package/.merlin-core/skills/domain/ops-manual/references/elicitation-questions.md +141 -0
  406. package/.merlin-core/skills/domain/ops-manual/references/external-skills-registry.md +63 -0
  407. package/.merlin-core/skills/domain/ops-manual/references/operations-template.yaml +132 -0
  408. package/.merlin-core/skills/domain/remotion-best-practices/SKILL.md +99 -0
  409. package/.merlin-core/skills/domain/remotion-best-practices/rules/3d.md +86 -0
  410. package/.merlin-core/skills/domain/remotion-best-practices/rules/animations.md +27 -0
  411. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  412. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  413. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  414. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets.md +78 -0
  415. package/.merlin-core/skills/domain/remotion-best-practices/rules/audio.md +172 -0
  416. package/.merlin-core/skills/domain/remotion-best-practices/rules/calculate-metadata.md +131 -0
  417. package/.merlin-core/skills/domain/remotion-best-practices/rules/can-decode.md +75 -0
  418. package/.merlin-core/skills/domain/remotion-best-practices/rules/charts.md +68 -0
  419. package/.merlin-core/skills/domain/remotion-best-practices/rules/compositions.md +154 -0
  420. package/.merlin-core/skills/domain/remotion-best-practices/rules/display-captions.md +126 -0
  421. package/.merlin-core/skills/domain/remotion-best-practices/rules/extract-frames.md +229 -0
  422. package/.merlin-core/skills/domain/remotion-best-practices/rules/fonts.md +152 -0
  423. package/.merlin-core/skills/domain/remotion-best-practices/rules/get-audio-duration.md +58 -0
  424. package/.merlin-core/skills/domain/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  425. package/.merlin-core/skills/domain/remotion-best-practices/rules/get-video-duration.md +58 -0
  426. package/.merlin-core/skills/domain/remotion-best-practices/rules/gifs.md +144 -0
  427. package/.merlin-core/skills/domain/remotion-best-practices/rules/images.md +134 -0
  428. package/.merlin-core/skills/domain/remotion-best-practices/rules/import-srt-captions.md +67 -0
  429. package/.merlin-core/skills/domain/remotion-best-practices/rules/lottie.md +70 -0
  430. package/.merlin-core/skills/domain/remotion-best-practices/rules/maps.md +414 -0
  431. package/.merlin-core/skills/domain/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
  432. package/.merlin-core/skills/domain/remotion-best-practices/rules/measuring-text.md +143 -0
  433. package/.merlin-core/skills/domain/remotion-best-practices/rules/parameters.md +109 -0
  434. package/.merlin-core/skills/domain/remotion-best-practices/rules/sequencing.md +118 -0
  435. package/.merlin-core/skills/domain/remotion-best-practices/rules/tailwind.md +11 -0
  436. package/.merlin-core/skills/domain/remotion-best-practices/rules/text-animations.md +20 -0
  437. package/.merlin-core/skills/domain/remotion-best-practices/rules/timing.md +179 -0
  438. package/.merlin-core/skills/domain/remotion-best-practices/rules/transcribe-captions.md +19 -0
  439. package/.merlin-core/skills/domain/remotion-best-practices/rules/transitions.md +137 -0
  440. package/.merlin-core/skills/domain/remotion-best-practices/rules/transparent-videos.md +106 -0
  441. package/.merlin-core/skills/domain/remotion-best-practices/rules/trimming.md +51 -0
  442. package/.merlin-core/skills/domain/remotion-best-practices/rules/videos.md +171 -0
  443. package/.merlin-core/skills/domain/resend-email/SKILL.md +377 -0
  444. package/.merlin-core/skills/general/adversarial-review/SKILL.md +144 -0
  445. package/.merlin-core/skills/general/api-design/SKILL.md +513 -0
  446. package/.merlin-core/skills/general/apify-scrape/SKILL.md +137 -0
  447. package/.merlin-core/skills/general/apify-scrape/scripts/apify-scrape.sh +68 -0
  448. package/.merlin-core/skills/general/backup/SKILL.md +87 -0
  449. package/.merlin-core/skills/general/blkskrn/SKILL.md +392 -0
  450. package/.merlin-core/skills/general/blkskrn/references/animation-patterns.md +521 -0
  451. package/.merlin-core/skills/general/blkskrn/references/design-system.md +637 -0
  452. package/.merlin-core/skills/general/blkskrn/references/html-templates.md +440 -0
  453. package/.merlin-core/skills/general/blkskrn/references/presenter-template.md +45 -0
  454. package/.merlin-core/skills/general/blkskrn/references/slide-types.md +424 -0
  455. package/.merlin-core/skills/general/blkskrn/scripts/canvas-manager.js +502 -0
  456. package/.merlin-core/skills/general/blkskrn/scripts/presenter.js +90 -0
  457. package/.merlin-core/skills/general/blkskrn/templates/presenter.html +273 -0
  458. package/.merlin-core/skills/general/blkskrn/templates/slide-base.html +277 -0
  459. package/.merlin-core/skills/general/blkskrn/templates/viewer.html +165 -0
  460. package/.merlin-core/skills/general/browser-takeover/SKILL.md +53 -0
  461. package/.merlin-core/skills/general/claude-api/SKILL.md +90 -0
  462. package/.merlin-core/skills/general/code-javascript/SKILL.md +268 -0
  463. package/.merlin-core/skills/general/code-python/SKILL.md +424 -0
  464. package/.merlin-core/skills/general/code-style/SKILL.md +97 -0
  465. package/.merlin-core/skills/general/code-typescript/SKILL.md +361 -0
  466. package/.merlin-core/skills/general/cold-email/SKILL.md +164 -0
  467. package/.merlin-core/skills/general/cold-email/references/benchmarks.md +18 -0
  468. package/.merlin-core/skills/general/cold-email/references/follow-up-sequences.md +18 -0
  469. package/.merlin-core/skills/general/cold-email/references/frameworks.md +18 -0
  470. package/.merlin-core/skills/general/cold-email/references/personalization.md +18 -0
  471. package/.merlin-core/skills/general/cold-email/references/subject-lines.md +18 -0
  472. package/.merlin-core/skills/general/container-security/SKILL.md +462 -0
  473. package/.merlin-core/skills/general/context-management/SKILL.md +79 -0
  474. package/.merlin-core/skills/general/copy-editing/SKILL.md +501 -0
  475. package/.merlin-core/skills/general/copy-editing/references/checklist.md +18 -0
  476. package/.merlin-core/skills/general/copy-editing/references/content-refresh.md +18 -0
  477. package/.merlin-core/skills/general/copy-editing/references/plain-english-alternatives.md +18 -0
  478. package/.merlin-core/skills/general/copywriting/SKILL.md +294 -0
  479. package/.merlin-core/skills/general/copywriting/references/copy-frameworks.md +392 -0
  480. package/.merlin-core/skills/general/copywriting/references/natural-transitions.md +276 -0
  481. package/.merlin-core/skills/general/database/SKILL.md +561 -0
  482. package/.merlin-core/skills/general/database/references/postgres-concurrency.md +182 -0
  483. package/.merlin-core/skills/general/database/references/postgres-connections.md +97 -0
  484. package/.merlin-core/skills/general/database/references/postgres-data-patterns.md +159 -0
  485. package/.merlin-core/skills/general/database/references/postgres-monitoring.md +136 -0
  486. package/.merlin-core/skills/general/database/references/postgres-rls.md +140 -0
  487. package/.merlin-core/skills/general/database-provision/SKILL.md +56 -0
  488. package/.merlin-core/skills/general/deploy/SKILL.md +65 -0
  489. package/.merlin-core/skills/general/design-inspiration/SKILL.md +146 -0
  490. package/.merlin-core/skills/general/design-palette/SKILL.md +99 -0
  491. package/.merlin-core/skills/general/design-palette/references/full-palettes.md +144 -0
  492. package/.merlin-core/skills/general/design-system/SKILL.md +94 -0
  493. package/.merlin-core/skills/general/design-typography/SKILL.md +115 -0
  494. package/.merlin-core/skills/general/design-typography/references/full-pairings.md +144 -0
  495. package/.merlin-core/skills/general/design-ux-patterns/SKILL.md +155 -0
  496. package/.merlin-core/skills/general/design-ux-patterns/references/charts-data-guidelines.md +197 -0
  497. package/.merlin-core/skills/general/design-ux-patterns/references/landing-patterns.md +199 -0
  498. package/.merlin-core/skills/general/design-ux-patterns/references/professional-ui-checklist.md +56 -0
  499. package/.merlin-core/skills/general/design-ux-patterns/references/style-catalog.md +89 -0
  500. package/.merlin-core/skills/general/design-ux-patterns/references/ux-guidelines.md +837 -0
  501. package/.merlin-core/skills/general/discover-cloud/SKILL.md +108 -0
  502. package/.merlin-core/skills/general/doc-sync/SKILL.md +52 -0
  503. package/.merlin-core/skills/general/document-sharding/SKILL.md +53 -0
  504. package/.merlin-core/skills/general/docx/SKILL.md +418 -0
  505. package/.merlin-core/skills/general/docx/references/windows-setup.md +27 -0
  506. package/.merlin-core/skills/general/docx/scripts/__init__.py +1 -0
  507. package/.merlin-core/skills/general/docx/scripts/accept_changes.py +135 -0
  508. package/.merlin-core/skills/general/docx/scripts/comment.py +318 -0
  509. package/.merlin-core/skills/general/docx/scripts/office/__init__.py +0 -0
  510. package/.merlin-core/skills/general/docx/scripts/office/helpers/__init__.py +0 -0
  511. package/.merlin-core/skills/general/docx/scripts/office/helpers/merge_runs.py +199 -0
  512. package/.merlin-core/skills/general/docx/scripts/office/helpers/simplify_redlines.py +197 -0
  513. package/.merlin-core/skills/general/docx/scripts/office/pack.py +159 -0
  514. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  515. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  516. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  517. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  518. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  519. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  520. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  521. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  522. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  523. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  524. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  525. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  526. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  527. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  528. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  529. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  530. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  531. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  532. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  533. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  534. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  535. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  536. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  537. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  538. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  539. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  540. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  541. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  542. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  543. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  544. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  545. package/.merlin-core/skills/general/docx/scripts/office/schemas/mce/mc.xsd +75 -0
  546. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  547. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  548. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  549. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  550. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  551. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  552. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  553. package/.merlin-core/skills/general/docx/scripts/office/soffice.py +183 -0
  554. package/.merlin-core/skills/general/docx/scripts/office/unpack.py +132 -0
  555. package/.merlin-core/skills/general/docx/scripts/office/validate.py +111 -0
  556. package/.merlin-core/skills/general/docx/scripts/office/validators/__init__.py +15 -0
  557. package/.merlin-core/skills/general/docx/scripts/office/validators/base.py +847 -0
  558. package/.merlin-core/skills/general/docx/scripts/office/validators/docx.py +446 -0
  559. package/.merlin-core/skills/general/docx/scripts/office/validators/pptx.py +275 -0
  560. package/.merlin-core/skills/general/docx/scripts/office/validators/redlining.py +247 -0
  561. package/.merlin-core/skills/general/docx/scripts/templates/comments.xml +3 -0
  562. package/.merlin-core/skills/general/docx/scripts/templates/commentsExtended.xml +3 -0
  563. package/.merlin-core/skills/general/docx/scripts/templates/commentsExtensible.xml +3 -0
  564. package/.merlin-core/skills/general/docx/scripts/templates/commentsIds.xml +3 -0
  565. package/.merlin-core/skills/general/docx/scripts/templates/people.xml +3 -0
  566. package/.merlin-core/skills/general/elicitation/SKILL.md +188 -0
  567. package/.merlin-core/skills/general/engineering-audit/SKILL.md +122 -0
  568. package/.merlin-core/skills/general/find-and-edit/SKILL.md +102 -0
  569. package/.merlin-core/skills/general/first-party-docs/SKILL.md +51 -0
  570. package/.merlin-core/skills/general/frontend-design/SKILL.md +204 -0
  571. package/.merlin-core/skills/general/guardrails/SKILL.md +144 -0
  572. package/.merlin-core/skills/general/image-gen/SKILL.md +49 -0
  573. package/.merlin-core/skills/general/learning-capture/SKILL.md +192 -0
  574. package/.merlin-core/skills/general/lgpd-compliance-audit/SKILL.md +448 -0
  575. package/.merlin-core/skills/general/load-testing/SKILL.md +114 -0
  576. package/.merlin-core/skills/general/load-testing/docker/Dockerfile.dashboard +21 -0
  577. package/.merlin-core/skills/general/load-testing/docker/docker-compose.locust.yml +39 -0
  578. package/.merlin-core/skills/general/load-testing/requirements.txt +1 -0
  579. package/.merlin-core/skills/general/load-testing/scripts/compare_baseline.py +172 -0
  580. package/.merlin-core/skills/general/load-testing/scripts/run_local.py +245 -0
  581. package/.merlin-core/skills/general/load-testing/templates/load_shape_stepped.py +35 -0
  582. package/.merlin-core/skills/general/load-testing/templates/locustfile_dashboard.py +47 -0
  583. package/.merlin-core/skills/general/load-testing/templates/threshold_hook.py +36 -0
  584. package/.merlin-core/skills/general/mage-beauty/SKILL.md +89 -0
  585. package/.merlin-core/skills/general/mage-beauty/references/anti-patterns.md +148 -0
  586. package/.merlin-core/skills/general/mage-beauty/references/color-and-contrast.md +87 -0
  587. package/.merlin-core/skills/general/mage-beauty/references/interaction-design.md +99 -0
  588. package/.merlin-core/skills/general/mage-beauty/references/motion-design.md +90 -0
  589. package/.merlin-core/skills/general/mage-beauty/references/remotion-bridge.md +187 -0
  590. package/.merlin-core/skills/general/mage-beauty/references/responsive-and-multi-format.md +98 -0
  591. package/.merlin-core/skills/general/mage-beauty/references/spatial-design.md +88 -0
  592. package/.merlin-core/skills/general/mage-beauty/references/typography.md +60 -0
  593. package/.merlin-core/skills/general/mage-beauty/references/verb-adapt.md +102 -0
  594. package/.merlin-core/skills/general/mage-beauty/references/verb-animate.md +97 -0
  595. package/.merlin-core/skills/general/mage-beauty/references/verb-audit.md +99 -0
  596. package/.merlin-core/skills/general/mage-beauty/references/verb-bolder.md +94 -0
  597. package/.merlin-core/skills/general/mage-beauty/references/verb-cinematic.md +128 -0
  598. package/.merlin-core/skills/general/mage-beauty/references/verb-clarify.md +107 -0
  599. package/.merlin-core/skills/general/mage-beauty/references/verb-colorize.md +106 -0
  600. package/.merlin-core/skills/general/mage-beauty/references/verb-critique.md +88 -0
  601. package/.merlin-core/skills/general/mage-beauty/references/verb-delight.md +98 -0
  602. package/.merlin-core/skills/general/mage-beauty/references/verb-distill.md +97 -0
  603. package/.merlin-core/skills/general/mage-beauty/references/verb-harden.md +79 -0
  604. package/.merlin-core/skills/general/mage-beauty/references/verb-layout.md +104 -0
  605. package/.merlin-core/skills/general/mage-beauty/references/verb-onboard.md +98 -0
  606. package/.merlin-core/skills/general/mage-beauty/references/verb-optimize.md +124 -0
  607. package/.merlin-core/skills/general/mage-beauty/references/verb-overdrive.md +105 -0
  608. package/.merlin-core/skills/general/mage-beauty/references/verb-polish.md +91 -0
  609. package/.merlin-core/skills/general/mage-beauty/references/verb-quieter.md +95 -0
  610. package/.merlin-core/skills/general/mage-beauty/references/verb-rebrand.md +127 -0
  611. package/.merlin-core/skills/general/mage-beauty/references/verb-shape.md +160 -0
  612. package/.merlin-core/skills/general/mage-beauty/references/verb-typeset.md +109 -0
  613. package/.merlin-core/skills/general/mage-beauty/references/voice-and-microcopy.md +137 -0
  614. package/.merlin-core/skills/general/mcp-builder/SKILL.md +92 -0
  615. package/.merlin-core/skills/general/network-debug/SKILL.md +51 -0
  616. package/.merlin-core/skills/general/next-best-practices/SKILL.md +177 -0
  617. package/.merlin-core/skills/general/next-best-practices/references/async-patterns.md +87 -0
  618. package/.merlin-core/skills/general/next-best-practices/references/bundling.md +182 -0
  619. package/.merlin-core/skills/general/next-best-practices/references/data-patterns.md +306 -0
  620. package/.merlin-core/skills/general/next-best-practices/references/debug-tricks.md +125 -0
  621. package/.merlin-core/skills/general/next-best-practices/references/directives.md +74 -0
  622. package/.merlin-core/skills/general/next-best-practices/references/error-handling.md +232 -0
  623. package/.merlin-core/skills/general/next-best-practices/references/file-conventions.md +141 -0
  624. package/.merlin-core/skills/general/next-best-practices/references/font.md +257 -0
  625. package/.merlin-core/skills/general/next-best-practices/references/functions.md +108 -0
  626. package/.merlin-core/skills/general/next-best-practices/references/hydration-error.md +88 -0
  627. package/.merlin-core/skills/general/next-best-practices/references/image.md +179 -0
  628. package/.merlin-core/skills/general/next-best-practices/references/metadata.md +296 -0
  629. package/.merlin-core/skills/general/next-best-practices/references/parallel-routes.md +298 -0
  630. package/.merlin-core/skills/general/next-best-practices/references/route-handlers.md +146 -0
  631. package/.merlin-core/skills/general/next-best-practices/references/rsc-boundaries.md +164 -0
  632. package/.merlin-core/skills/general/next-best-practices/references/runtime-selection.md +40 -0
  633. package/.merlin-core/skills/general/next-best-practices/references/scripts.md +141 -0
  634. package/.merlin-core/skills/general/next-best-practices/references/self-hosting.md +384 -0
  635. package/.merlin-core/skills/general/next-best-practices/references/suspense-boundaries.md +67 -0
  636. package/.merlin-core/skills/general/next-steps/SKILL.md +43 -0
  637. package/.merlin-core/skills/general/party-mode/SKILL.md +57 -0
  638. package/.merlin-core/skills/general/pdf/SKILL.md +298 -0
  639. package/.merlin-core/skills/general/pdf/references/forms.md +312 -0
  640. package/.merlin-core/skills/general/pdf/references/reference.md +640 -0
  641. package/.merlin-core/skills/general/pdf/references/windows-setup.md +40 -0
  642. package/.merlin-core/skills/general/pdf/scripts/check_bounding_boxes.py +65 -0
  643. package/.merlin-core/skills/general/pdf/scripts/check_fillable_fields.py +11 -0
  644. package/.merlin-core/skills/general/pdf/scripts/convert_pdf_to_images.py +33 -0
  645. package/.merlin-core/skills/general/pdf/scripts/create_validation_image.py +37 -0
  646. package/.merlin-core/skills/general/pdf/scripts/extract_form_field_info.py +122 -0
  647. package/.merlin-core/skills/general/pdf/scripts/extract_form_structure.py +115 -0
  648. package/.merlin-core/skills/general/pdf/scripts/fill_fillable_fields.py +98 -0
  649. package/.merlin-core/skills/general/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  650. package/.merlin-core/skills/general/pptx/SKILL.md +133 -0
  651. package/.merlin-core/skills/general/pptx/references/editing.md +213 -0
  652. package/.merlin-core/skills/general/pptx/references/pptxgenjs.md +581 -0
  653. package/.merlin-core/skills/general/pptx/references/windows-setup.md +27 -0
  654. package/.merlin-core/skills/general/pptx/scripts/__init__.py +0 -0
  655. package/.merlin-core/skills/general/pptx/scripts/add_slide.py +195 -0
  656. package/.merlin-core/skills/general/pptx/scripts/clean.py +286 -0
  657. package/.merlin-core/skills/general/pptx/scripts/thumbnail.py +289 -0
  658. package/.merlin-core/skills/general/property-testing/SKILL.md +214 -0
  659. package/.merlin-core/skills/general/purge-leaked-secret/SKILL.md +383 -0
  660. package/.merlin-core/skills/general/reflection/SKILL.md +100 -0
  661. package/.merlin-core/skills/general/secret-safe-commit/SKILL.md +246 -0
  662. package/.merlin-core/skills/general/secret-safe-commit/templates/.gitleaks.toml +91 -0
  663. package/.merlin-core/skills/general/secret-safe-commit/templates/.pre-commit-config.yaml +57 -0
  664. package/.merlin-core/skills/general/secret-safe-commit/templates/secret-scan.yml +48 -0
  665. package/.merlin-core/skills/general/semantic-search/SKILL.md +79 -0
  666. package/.merlin-core/skills/general/skill-creator/SKILL.md +342 -0
  667. package/.merlin-core/skills/general/skill-creator/agents/analyzer.md +283 -0
  668. package/.merlin-core/skills/general/skill-creator/agents/comparator.md +211 -0
  669. package/.merlin-core/skills/general/skill-creator/agents/grader.md +227 -0
  670. package/.merlin-core/skills/general/skill-creator/assets/eval_review.html +146 -0
  671. package/.merlin-core/skills/general/skill-creator/eval-viewer/generate_review.py +471 -0
  672. package/.merlin-core/skills/general/skill-creator/eval-viewer/viewer.html +1325 -0
  673. package/.merlin-core/skills/general/skill-creator/references/schemas.md +439 -0
  674. package/.merlin-core/skills/general/skill-creator/scripts/__init__.py +0 -0
  675. package/.merlin-core/skills/general/skill-creator/scripts/aggregate_benchmark.py +401 -0
  676. package/.merlin-core/skills/general/skill-creator/scripts/generate_report.py +326 -0
  677. package/.merlin-core/skills/general/skill-creator/scripts/improve_description.py +247 -0
  678. package/.merlin-core/skills/general/skill-creator/scripts/package_skill.py +136 -0
  679. package/.merlin-core/skills/general/skill-creator/scripts/quick_validate.py +103 -0
  680. package/.merlin-core/skills/general/skill-creator/scripts/run_eval.py +310 -0
  681. package/.merlin-core/skills/general/skill-creator/scripts/run_loop.py +328 -0
  682. package/.merlin-core/skills/general/skill-creator/scripts/utils.py +47 -0
  683. package/.merlin-core/skills/general/start-here/SKILL.md +63 -0
  684. package/.merlin-core/skills/general/start-here/recipes.json +758 -0
  685. package/.merlin-core/skills/general/start-here/recipes.schema.json +57 -0
  686. package/.merlin-core/skills/general/static-analysis/SKILL.md +151 -0
  687. package/.merlin-core/skills/general/tailwind-design-system/SKILL.md +201 -0
  688. package/.merlin-core/skills/general/tailwind-design-system/references/advanced-v4.md +152 -0
  689. package/.merlin-core/skills/general/tailwind-design-system/references/component-patterns.md +353 -0
  690. package/.merlin-core/skills/general/teach-method/SKILL.md +86 -0
  691. package/.merlin-core/skills/general/team-execution/SKILL.md +67 -0
  692. package/.merlin-core/skills/general/testing/SKILL.md +412 -0
  693. package/.merlin-core/skills/general/token-economy/SKILL.md +55 -0
  694. package/.merlin-core/skills/general/vps-security-hardening/SKILL.md +406 -0
  695. package/.merlin-core/skills/general/web-quality/SKILL.md +180 -0
  696. package/.merlin-core/skills/general/webapp-testing/SKILL.md +153 -0
  697. package/.merlin-core/skills/general/webapp-testing/scripts/screenshot_compare.py +72 -0
  698. package/.merlin-core/skills/general/webapp-testing/scripts/with_server.py +103 -0
  699. package/.merlin-core/skills/general/xlsx/SKILL.md +167 -0
  700. package/.merlin-core/skills/general/xlsx/references/nodejs-sheetjs-styled-reports.md +141 -0
  701. package/.merlin-core/skills/general/xlsx/references/windows-setup.md +17 -0
  702. package/.merlin-core/skills/general/xlsx/scripts/recalc.py +184 -0
  703. package/.merlin-core/skills/general/xlsx/scripts/styled-report.js +130 -0
  704. package/.merlin-core/skills/general/yolo-mode/SKILL.md +60 -0
  705. package/.merlin-core/skills/general/youtube-transcript/SKILL.md +177 -0
  706. package/.merlin-core/skills/general/youtube-transcript/scripts/fetch_transcript.py +188 -0
  707. package/.merlin-core/skills/general/youtube-transcript/scripts/gladia_transcribe.mjs +230 -0
  708. package/.merlin-core/tools/commands/activate.js +72 -0
  709. package/.merlin-core/tools/commands/archive-thoughts.js +181 -0
  710. package/.merlin-core/tools/commands/backup.js +156 -0
  711. package/.merlin-core/tools/commands/certify-process.js +196 -0
  712. package/.merlin-core/tools/commands/convert.js +87 -0
  713. package/.merlin-core/tools/commands/cron.js +147 -0
  714. package/.merlin-core/tools/commands/disable.js +73 -0
  715. package/.merlin-core/tools/commands/doc-sync.js +127 -0
  716. package/.merlin-core/tools/commands/eval-skill.js +193 -0
  717. package/.merlin-core/tools/commands/frontmatter.js +49 -0
  718. package/.merlin-core/tools/commands/heartbeat.js +43 -0
  719. package/.merlin-core/tools/commands/index-thoughts.js +35 -0
  720. package/.merlin-core/tools/commands/install-remote-approve.js +184 -0
  721. package/.merlin-core/tools/commands/install.js +81 -0
  722. package/.merlin-core/tools/commands/lib/__verify__/diff-reports.js +170 -0
  723. package/.merlin-core/tools/commands/lib/fs-safe.js +186 -0
  724. package/.merlin-core/tools/commands/lib/preflight.js +607 -0
  725. package/.merlin-core/tools/commands/lib/preserve.js +232 -0
  726. package/.merlin-core/tools/commands/lib/project-config.template.yaml +69 -0
  727. package/.merlin-core/tools/commands/lib/report.js +231 -0
  728. package/.merlin-core/tools/commands/lib/settings-merge.js +134 -0
  729. package/.merlin-core/tools/commands/license.js +52 -0
  730. package/.merlin-core/tools/commands/list.js +125 -0
  731. package/.merlin-core/tools/commands/migrate-alkimia.js +271 -0
  732. package/.merlin-core/tools/commands/modules.js +68 -0
  733. package/.merlin-core/tools/commands/provision.js +83 -0
  734. package/.merlin-core/tools/commands/prune-feedback.js +114 -0
  735. package/.merlin-core/tools/commands/run-process.js +28 -0
  736. package/.merlin-core/tools/commands/state.js +79 -0
  737. package/.merlin-core/tools/commands/sync-bridges.js +197 -0
  738. package/.merlin-core/tools/commands/upgrade.js +1135 -0
  739. package/.merlin-core/tools/commands/validate-recipes.js +218 -0
  740. package/.merlin-core/tools/commands/validate.js +159 -0
  741. package/.merlin-core/tools/commands/yolo.js +82 -0
  742. package/.merlin-core/tools/compose-rules.mjs +179 -0
  743. package/.merlin-core/tools/disable-module.mjs +150 -0
  744. package/.merlin-core/tools/lib/deployer.mjs +131 -0
  745. package/.merlin-core/tools/lib/modules-activation.mjs +225 -0
  746. package/.merlin-core/tools/merlin-tools.js +153 -0
  747. package/.merlin-core/tools/migrate-frontmatter-v3.js +192 -0
  748. package/.merlin-core/tools/modules-catalog.mjs +174 -0
  749. package/.merlin-core/tools/provision-module.mjs +191 -0
  750. package/.merlin-core/tools/verify-module.mjs +99 -0
  751. package/.merlin-core/tools/vps-security-audit.sh +234 -0
  752. package/INSTALL.md +312 -0
  753. package/LICENSE +118 -0
  754. package/PRIVACY-LICENSING.md +65 -0
  755. package/README.md +391 -0
  756. package/bin/README.md +15 -0
  757. package/bin/convert-to-merlin.sh +109 -0
  758. package/bin/fleet-patch-hooks.sh +144 -0
  759. package/bin/fleet-patch-v3-fixes.sh +127 -0
  760. package/bin/merlin-init.js +232 -0
  761. package/bin/merlin.js +321 -0
  762. package/package.json +127 -0
@@ -0,0 +1,3744 @@
1
+ <!-- Adapted from czlonkowski/n8n-skills (MIT). Source files: SKILL.md, DATA_ACCESS.md, BUILTIN_FUNCTIONS.md, COMMON_PATTERNS.md, ERROR_PATTERNS.md -->
2
+
3
+ # JavaScript Code Node — Consolidated Reference
4
+
5
+ Expert guidance for writing JavaScript code in n8n Code nodes.
6
+
7
+ > **Cross-references:**
8
+ >
9
+ > - [expression-syntax.md](expression-syntax.md) — Expression `{{ }}` syntax is for OTHER nodes; never use `{{ }}` inside Code nodes!
10
+ > - [code-python.md](code-python.md) — Python alternative for Code nodes
11
+ > - [validation-expert.md](validation-expert.md) — Validate Code node configuration and auto-fix common issues
12
+
13
+ ---
14
+
15
+ ## Quick Start
16
+
17
+ ```javascript
18
+ // Basic template for Code nodes
19
+ const items = $input.all();
20
+
21
+ // Process data
22
+ const processed = items.map((item) => ({
23
+ json: {
24
+ ...item.json,
25
+ processed: true,
26
+ timestamp: new Date().toISOString(),
27
+ },
28
+ }));
29
+
30
+ return processed;
31
+ ```
32
+
33
+ ### Essential Rules
34
+
35
+ 1. **Choose "Run Once for All Items" mode** (recommended for most use cases)
36
+ 2. **Access data**: `$input.all()`, `$input.first()`, or `$input.item`
37
+ 3. **CRITICAL**: Must return `[{json: {...}}]` format
38
+ 4. **CRITICAL**: Webhook data is under `$json.body` (not `$json` directly)
39
+ 5. **Built-ins available**: $helpers.httpRequest(), DateTime (Luxon), $jmespath()
40
+
41
+ ---
42
+
43
+ ## Mode Selection Guide
44
+
45
+ The Code node offers two execution modes. Choose based on your use case:
46
+
47
+ ### Run Once for All Items (Recommended - Default)
48
+
49
+ **Use this mode for:** 95% of use cases
50
+
51
+ - **How it works**: Code executes **once** regardless of input count
52
+ - **Data access**: `$input.all()` or `items` array
53
+ - **Best for**: Aggregation, filtering, batch processing, transformations, API calls with all data
54
+ - **Performance**: Faster for multiple items (single execution)
55
+
56
+ ```javascript
57
+ // Example: Calculate total from all items
58
+ const allItems = $input.all();
59
+ const total = allItems.reduce((sum, item) => sum + (item.json.amount || 0), 0);
60
+
61
+ return [
62
+ {
63
+ json: {
64
+ total,
65
+ count: allItems.length,
66
+ average: total / allItems.length,
67
+ },
68
+ },
69
+ ];
70
+ ```
71
+
72
+ **When to use:**
73
+
74
+ - Comparing items across the dataset
75
+ - Calculating totals, averages, or statistics
76
+ - Sorting or ranking items
77
+ - Deduplication
78
+ - Building aggregated reports
79
+ - Combining data from multiple items
80
+
81
+ ### Run Once for Each Item
82
+
83
+ **Use this mode for:** Specialized cases only
84
+
85
+ - **How it works**: Code executes **separately** for each input item
86
+ - **Data access**: `$input.item` or `$item`
87
+ - **Best for**: Item-specific logic, independent operations, per-item validation
88
+ - **Performance**: Slower for large datasets (multiple executions)
89
+
90
+ ```javascript
91
+ // Example: Add processing timestamp to each item
92
+ const item = $input.item;
93
+
94
+ return [
95
+ {
96
+ json: {
97
+ ...item.json,
98
+ processed: true,
99
+ processedAt: new Date().toISOString(),
100
+ },
101
+ },
102
+ ];
103
+ ```
104
+
105
+ **When to use:**
106
+
107
+ - Each item needs independent API call
108
+ - Per-item validation with different error handling
109
+ - Item-specific transformations based on item properties
110
+ - When items must be processed separately for business logic
111
+
112
+ **Decision Shortcut:**
113
+
114
+ - **Need to look at multiple items?** -> Use "All Items" mode
115
+ - **Each item completely independent?** -> Use "Each Item" mode
116
+ - **Not sure?** -> Use "All Items" mode (you can always loop inside)
117
+
118
+ ---
119
+
120
+ ## Return Format Requirements
121
+
122
+ **CRITICAL RULE**: Always return array of objects with `json` property
123
+
124
+ ### Correct Return Formats
125
+
126
+ ```javascript
127
+ // Single result
128
+ return [
129
+ {
130
+ json: {
131
+ field1: value1,
132
+ field2: value2,
133
+ },
134
+ },
135
+ ];
136
+
137
+ // Multiple results
138
+ return [
139
+ { json: { id: 1, data: "first" } },
140
+ { json: { id: 2, data: "second" } },
141
+ ];
142
+
143
+ // Transformed array
144
+ const transformed = $input
145
+ .all()
146
+ .filter((item) => item.json.valid)
147
+ .map((item) => ({
148
+ json: {
149
+ id: item.json.id,
150
+ processed: true,
151
+ },
152
+ }));
153
+ return transformed;
154
+
155
+ // Empty result (when no data to return)
156
+ return [];
157
+
158
+ // Conditional return
159
+ if (shouldProcess) {
160
+ return [{ json: processedData }];
161
+ } else {
162
+ return [];
163
+ }
164
+ ```
165
+
166
+ ### Incorrect Return Formats
167
+
168
+ ```javascript
169
+ // WRONG: Object without array wrapper
170
+ return {
171
+ json: { field: value },
172
+ };
173
+
174
+ // WRONG: Array without json wrapper
175
+ return [{ field: value }];
176
+
177
+ // WRONG: Plain string
178
+ return "processed";
179
+
180
+ // WRONG: Raw data without mapping
181
+ return $input.all(); // Missing .map()
182
+
183
+ // WRONG: Incomplete structure
184
+ return [{ data: value }]; // Should be {json: value}
185
+ ```
186
+
187
+ **Why it matters**: Next nodes expect array format. Incorrect format causes workflow execution to fail.
188
+
189
+ ---
190
+
191
+ ## Data Access Patterns
192
+
193
+ In n8n Code nodes, you access data from previous nodes using built-in variables and methods. Understanding which method to use is critical for correct workflow execution.
194
+
195
+ **Data Access Priority** (by common usage):
196
+
197
+ 1. **`$input.all()`** - Most common - Batch operations, aggregations
198
+ 2. **`$input.first()`** - Very common - Single item operations
199
+ 3. **`$input.item`** - Common - Each Item mode only
200
+ 4. **`$node["NodeName"].json`** - Specific node references
201
+ 5. **`$json`** - Direct current item (legacy, use `$input` instead)
202
+
203
+ ### Pattern 1: $input.all() - Process All Items
204
+
205
+ **Usage**: Most common pattern for batch processing
206
+
207
+ **When to use:**
208
+
209
+ - Processing multiple records
210
+ - Aggregating data (sum, count, average)
211
+ - Filtering arrays
212
+ - Transforming datasets
213
+ - Comparing items
214
+ - Sorting or ranking
215
+
216
+ #### Basic Usage
217
+
218
+ ```javascript
219
+ // Get all items from previous node
220
+ const allItems = $input.all();
221
+
222
+ // allItems is an array of objects like:
223
+ // [
224
+ // {json: {id: 1, name: "Alice"}},
225
+ // {json: {id: 2, name: "Bob"}}
226
+ // ]
227
+
228
+ console.log(`Received ${allItems.length} items`);
229
+
230
+ return allItems;
231
+ ```
232
+
233
+ #### Example 1: Filter Active Items
234
+
235
+ ```javascript
236
+ const allItems = $input.all();
237
+
238
+ // Filter only active items
239
+ const activeItems = allItems.filter((item) => item.json.status === "active");
240
+
241
+ return activeItems;
242
+ ```
243
+
244
+ #### Example 2: Transform All Items
245
+
246
+ ```javascript
247
+ const allItems = $input.all();
248
+
249
+ // Map to new structure
250
+ const transformed = allItems.map((item) => ({
251
+ json: {
252
+ id: item.json.id,
253
+ fullName: `${item.json.firstName} ${item.json.lastName}`,
254
+ email: item.json.email,
255
+ processedAt: new Date().toISOString(),
256
+ },
257
+ }));
258
+
259
+ return transformed;
260
+ ```
261
+
262
+ #### Example 3: Aggregate Data
263
+
264
+ ```javascript
265
+ const allItems = $input.all();
266
+
267
+ // Calculate total
268
+ const total = allItems.reduce((sum, item) => {
269
+ return sum + (item.json.amount || 0);
270
+ }, 0);
271
+
272
+ return [
273
+ {
274
+ json: {
275
+ total,
276
+ count: allItems.length,
277
+ average: total / allItems.length,
278
+ },
279
+ },
280
+ ];
281
+ ```
282
+
283
+ #### Example 4: Sort and Limit
284
+
285
+ ```javascript
286
+ const allItems = $input.all();
287
+
288
+ // Get top 5 by score
289
+ const topFive = allItems
290
+ .sort((a, b) => (b.json.score || 0) - (a.json.score || 0))
291
+ .slice(0, 5);
292
+
293
+ return topFive.map((item) => ({ json: item.json }));
294
+ ```
295
+
296
+ #### Example 5: Group By Category
297
+
298
+ ```javascript
299
+ const allItems = $input.all();
300
+
301
+ // Group items by category
302
+ const grouped = {};
303
+
304
+ for (const item of allItems) {
305
+ const category = item.json.category || "Uncategorized";
306
+
307
+ if (!grouped[category]) {
308
+ grouped[category] = [];
309
+ }
310
+
311
+ grouped[category].push(item.json);
312
+ }
313
+
314
+ // Convert to array format
315
+ return Object.entries(grouped).map(([category, items]) => ({
316
+ json: {
317
+ category,
318
+ items,
319
+ count: items.length,
320
+ },
321
+ }));
322
+ ```
323
+
324
+ #### Example 6: Deduplicate by ID
325
+
326
+ ```javascript
327
+ const allItems = $input.all();
328
+
329
+ // Remove duplicates by ID
330
+ const seen = new Set();
331
+ const unique = [];
332
+
333
+ for (const item of allItems) {
334
+ const id = item.json.id;
335
+
336
+ if (!seen.has(id)) {
337
+ seen.add(id);
338
+ unique.push(item);
339
+ }
340
+ }
341
+
342
+ return unique;
343
+ ```
344
+
345
+ ### Pattern 2: $input.first() - Get First Item
346
+
347
+ **Usage**: Very common for single-item operations
348
+
349
+ **When to use:**
350
+
351
+ - Previous node returns single object
352
+ - Working with API responses
353
+ - Getting initial/first data point
354
+ - Configuration or metadata access
355
+
356
+ #### Basic Usage
357
+
358
+ ```javascript
359
+ // Get first item from previous node
360
+ const firstItem = $input.first();
361
+
362
+ // Access the JSON data
363
+ const data = firstItem.json;
364
+
365
+ console.log("First item:", data);
366
+
367
+ return [{ json: data }];
368
+ ```
369
+
370
+ #### Example 1: Process Single API Response
371
+
372
+ ```javascript
373
+ // Get API response (typically single object)
374
+ const response = $input.first().json;
375
+
376
+ // Extract what you need
377
+ return [
378
+ {
379
+ json: {
380
+ userId: response.data.user.id,
381
+ userName: response.data.user.name,
382
+ status: response.status,
383
+ fetchedAt: new Date().toISOString(),
384
+ },
385
+ },
386
+ ];
387
+ ```
388
+
389
+ #### Example 2: Transform Single Object
390
+
391
+ ```javascript
392
+ const data = $input.first().json;
393
+
394
+ // Transform structure
395
+ return [
396
+ {
397
+ json: {
398
+ id: data.id,
399
+ contact: {
400
+ email: data.email,
401
+ phone: data.phone,
402
+ },
403
+ address: {
404
+ street: data.street,
405
+ city: data.city,
406
+ zip: data.zip,
407
+ },
408
+ },
409
+ },
410
+ ];
411
+ ```
412
+
413
+ #### Example 3: Validate Single Item
414
+
415
+ ```javascript
416
+ const item = $input.first().json;
417
+
418
+ // Validation logic
419
+ const isValid = item.email && item.email.includes("@");
420
+
421
+ return [
422
+ {
423
+ json: {
424
+ ...item,
425
+ valid: isValid,
426
+ validatedAt: new Date().toISOString(),
427
+ },
428
+ },
429
+ ];
430
+ ```
431
+
432
+ #### Example 4: Extract Nested Data
433
+
434
+ ```javascript
435
+ const response = $input.first().json;
436
+
437
+ // Navigate nested structure
438
+ const users = response.data?.users || [];
439
+
440
+ return users.map((user) => ({
441
+ json: {
442
+ id: user.id,
443
+ name: user.profile?.name || "Unknown",
444
+ email: user.contact?.email || "no-email",
445
+ },
446
+ }));
447
+ ```
448
+
449
+ #### Example 5: Combine with Other Methods
450
+
451
+ ```javascript
452
+ // Get first item's data
453
+ const firstData = $input.first().json;
454
+
455
+ // Use it to filter all items
456
+ const allItems = $input.all();
457
+ const matching = allItems.filter(
458
+ (item) => item.json.category === firstData.targetCategory,
459
+ );
460
+
461
+ return matching;
462
+ ```
463
+
464
+ ### Pattern 3: $input.item - Current Item (Each Item Mode)
465
+
466
+ **Usage**: Common in "Run Once for Each Item" mode
467
+
468
+ **When to use:**
469
+
470
+ - Mode is set to "Run Once for Each Item"
471
+ - Need to process items independently
472
+ - Per-item API calls or validations
473
+ - Item-specific error handling
474
+
475
+ **IMPORTANT**: Only use in "Each Item" mode. Will be undefined in "All Items" mode.
476
+
477
+ #### Basic Usage
478
+
479
+ ```javascript
480
+ // In "Run Once for Each Item" mode
481
+ const currentItem = $input.item;
482
+ const data = currentItem.json;
483
+
484
+ console.log("Processing item:", data.id);
485
+
486
+ return [
487
+ {
488
+ json: {
489
+ ...data,
490
+ processed: true,
491
+ },
492
+ },
493
+ ];
494
+ ```
495
+
496
+ #### Example 1: Add Processing Metadata
497
+
498
+ ```javascript
499
+ const item = $input.item;
500
+
501
+ return [
502
+ {
503
+ json: {
504
+ ...item.json,
505
+ processed: true,
506
+ processedAt: new Date().toISOString(),
507
+ processingDuration: Math.random() * 1000, // Simulated duration
508
+ },
509
+ },
510
+ ];
511
+ ```
512
+
513
+ #### Example 2: Per-Item Validation
514
+
515
+ ```javascript
516
+ const item = $input.item;
517
+ const data = item.json;
518
+
519
+ // Validate this specific item
520
+ const errors = [];
521
+
522
+ if (!data.email) errors.push("Email required");
523
+ if (!data.name) errors.push("Name required");
524
+ if (data.age && data.age < 18) errors.push("Must be 18+");
525
+
526
+ return [
527
+ {
528
+ json: {
529
+ ...data,
530
+ valid: errors.length === 0,
531
+ errors: errors.length > 0 ? errors : undefined,
532
+ },
533
+ },
534
+ ];
535
+ ```
536
+
537
+ #### Example 3: Item-Specific API Call
538
+
539
+ ```javascript
540
+ const item = $input.item;
541
+ const userId = item.json.userId;
542
+
543
+ // Make API call specific to this item
544
+ const response = await $helpers.httpRequest({
545
+ method: "GET",
546
+ url: `https://api.example.com/users/${userId}/details`,
547
+ });
548
+
549
+ return [
550
+ {
551
+ json: {
552
+ ...item.json,
553
+ details: response,
554
+ },
555
+ },
556
+ ];
557
+ ```
558
+
559
+ #### Example 4: Conditional Processing
560
+
561
+ ```javascript
562
+ const item = $input.item;
563
+ const data = item.json;
564
+
565
+ // Process based on item type
566
+ if (data.type === "premium") {
567
+ return [
568
+ {
569
+ json: {
570
+ ...data,
571
+ discount: 0.2,
572
+ tier: "premium",
573
+ },
574
+ },
575
+ ];
576
+ } else {
577
+ return [
578
+ {
579
+ json: {
580
+ ...data,
581
+ discount: 0.05,
582
+ tier: "standard",
583
+ },
584
+ },
585
+ ];
586
+ }
587
+ ```
588
+
589
+ ### Pattern 4: $node - Reference Other Nodes
590
+
591
+ **Usage**: Less common, but powerful for specific scenarios
592
+
593
+ **When to use:**
594
+
595
+ - Need data from specific named node
596
+ - Combining data from multiple nodes
597
+ - Accessing metadata about workflow execution
598
+
599
+ #### Basic Usage
600
+
601
+ ```javascript
602
+ // Get output from specific node
603
+ const webhookData = $node["Webhook"].json;
604
+ const apiData = $node["HTTP Request"].json;
605
+
606
+ return [
607
+ {
608
+ json: {
609
+ fromWebhook: webhookData,
610
+ fromAPI: apiData,
611
+ },
612
+ },
613
+ ];
614
+ ```
615
+
616
+ #### Example 1: Combine Multiple Sources
617
+
618
+ ```javascript
619
+ // Reference multiple nodes
620
+ const webhook = $node["Webhook"].json;
621
+ const database = $node["Postgres"].json;
622
+ const api = $node["HTTP Request"].json;
623
+
624
+ return [
625
+ {
626
+ json: {
627
+ combined: {
628
+ webhook: webhook.body,
629
+ dbRecords: database.length,
630
+ apiResponse: api.status,
631
+ },
632
+ processedAt: new Date().toISOString(),
633
+ },
634
+ },
635
+ ];
636
+ ```
637
+
638
+ #### Example 2: Compare Across Nodes
639
+
640
+ ```javascript
641
+ const oldData = $node["Get Old Data"].json;
642
+ const newData = $node["Get New Data"].json;
643
+
644
+ // Compare
645
+ const changes = {
646
+ added: newData.filter((n) => !oldData.find((o) => o.id === n.id)),
647
+ removed: oldData.filter((o) => !newData.find((n) => n.id === o.id)),
648
+ modified: newData.filter((n) => {
649
+ const old = oldData.find((o) => o.id === n.id);
650
+ return old && JSON.stringify(old) !== JSON.stringify(n);
651
+ }),
652
+ };
653
+
654
+ return [
655
+ {
656
+ json: {
657
+ changes,
658
+ summary: {
659
+ added: changes.added.length,
660
+ removed: changes.removed.length,
661
+ modified: changes.modified.length,
662
+ },
663
+ },
664
+ },
665
+ ];
666
+ ```
667
+
668
+ #### Example 3: Access Node Metadata
669
+
670
+ ```javascript
671
+ // Get data from specific execution path
672
+ const ifTrueBranch = $node["IF True"].json;
673
+ const ifFalseBranch = $node["IF False"].json;
674
+
675
+ // Use whichever branch executed
676
+ const result = ifTrueBranch || ifFalseBranch || {};
677
+
678
+ return [{ json: result }];
679
+ ```
680
+
681
+ ### Critical: Webhook Data Structure
682
+
683
+ **MOST COMMON MISTAKE**: Forgetting webhook data is nested under `.body`
684
+
685
+ #### The Problem
686
+
687
+ Webhook node wraps all incoming data under a `body` property. This catches many developers by surprise.
688
+
689
+ #### Structure
690
+
691
+ ```javascript
692
+ // Webhook node output structure:
693
+ {
694
+ "headers": {
695
+ "content-type": "application/json",
696
+ "user-agent": "...",
697
+ // ... other headers
698
+ },
699
+ "params": {},
700
+ "query": {},
701
+ "body": {
702
+ // YOUR DATA IS HERE
703
+ "name": "Alice",
704
+ "email": "alice@example.com",
705
+ "message": "Hello!"
706
+ }
707
+ }
708
+ ```
709
+
710
+ #### Wrong vs Right
711
+
712
+ ```javascript
713
+ // WRONG: Trying to access directly
714
+ const name = $json.name; // undefined
715
+ const email = $json.email; // undefined
716
+
717
+ // CORRECT: Access via .body
718
+ const name = $json.body.name; // "Alice"
719
+ const email = $json.body.email; // "alice@example.com"
720
+
721
+ // CORRECT: Extract body first
722
+ const webhookData = $json.body;
723
+ const name = webhookData.name; // "Alice"
724
+ const email = webhookData.email; // "alice@example.com"
725
+ ```
726
+
727
+ #### Example: Full Webhook Processing
728
+
729
+ ```javascript
730
+ // Get webhook data from previous node
731
+ const webhookOutput = $input.first().json;
732
+
733
+ // Access the actual payload
734
+ const payload = webhookOutput.body;
735
+
736
+ // Access headers if needed
737
+ const contentType = webhookOutput.headers["content-type"];
738
+
739
+ // Access query parameters if needed
740
+ const apiKey = webhookOutput.query.api_key;
741
+
742
+ // Process the actual data
743
+ return [
744
+ {
745
+ json: {
746
+ // Data from webhook body
747
+ userName: payload.name,
748
+ userEmail: payload.email,
749
+ message: payload.message,
750
+
751
+ // Metadata
752
+ receivedAt: new Date().toISOString(),
753
+ contentType: contentType,
754
+ authenticated: !!apiKey,
755
+ },
756
+ },
757
+ ];
758
+ ```
759
+
760
+ #### POST Data, Query Params, and Headers
761
+
762
+ ```javascript
763
+ const webhook = $input.first().json;
764
+
765
+ return [
766
+ {
767
+ json: {
768
+ // POST body data
769
+ formData: webhook.body,
770
+
771
+ // Query parameters (?key=value)
772
+ queryParams: webhook.query,
773
+
774
+ // HTTP headers
775
+ userAgent: webhook.headers["user-agent"],
776
+ contentType: webhook.headers["content-type"],
777
+
778
+ // Request metadata
779
+ method: webhook.method, // POST, GET, etc.
780
+ url: webhook.url,
781
+ },
782
+ },
783
+ ];
784
+ ```
785
+
786
+ #### Common Webhook Scenarios
787
+
788
+ ```javascript
789
+ // Scenario 1: Form submission
790
+ const formData = $json.body;
791
+ const name = formData.name;
792
+ const email = formData.email;
793
+
794
+ // Scenario 2: JSON API webhook
795
+ const apiPayload = $json.body;
796
+ const eventType = apiPayload.event;
797
+ const data = apiPayload.data;
798
+
799
+ // Scenario 3: Query parameters
800
+ const apiKey = $json.query.api_key;
801
+ const userId = $json.query.user_id;
802
+
803
+ // Scenario 4: Headers
804
+ const authorization = $json.headers["authorization"];
805
+ const signature = $json.headers["x-signature"];
806
+ ```
807
+
808
+ ### Choosing the Right Data Access Pattern
809
+
810
+ #### Decision Tree
811
+
812
+ ```
813
+ Do you need ALL items from previous node?
814
+ |- YES -> Use $input.all()
815
+ |
816
+ \- NO -> Do you need just the FIRST item?
817
+ |- YES -> Use $input.first()
818
+ |
819
+ \- NO -> Are you in "Each Item" mode?
820
+ |- YES -> Use $input.item
821
+ |
822
+ \- NO -> Do you need specific node data?
823
+ |- YES -> Use $node["NodeName"]
824
+ \- NO -> Use $input.first() (default)
825
+ ```
826
+
827
+ #### Quick Reference Table
828
+
829
+ | Scenario | Use This | Example |
830
+ | -------------------------- | ---------------- | ----------------------------------------------------- |
831
+ | Sum all amounts | `$input.all()` | `allItems.reduce((sum, i) => sum + i.json.amount, 0)` |
832
+ | Get API response | `$input.first()` | `$input.first().json.data` |
833
+ | Process each independently | `$input.item` | `$input.item.json` (Each Item mode) |
834
+ | Combine two nodes | `$node["Name"]` | `$node["API"].json` |
835
+ | Filter array | `$input.all()` | `allItems.filter(i => i.json.active)` |
836
+ | Transform single object | `$input.first()` | `{...input.first().json, new: true}` |
837
+ | Webhook data | `$input.first()` | `$input.first().json.body` |
838
+
839
+ ### Common Data Access Mistakes
840
+
841
+ #### Mistake 1: Using $json Without Context
842
+
843
+ ```javascript
844
+ // WRONG: $json is ambiguous
845
+ const value = $json.field;
846
+
847
+ // CORRECT: Be explicit
848
+ const value = $input.first().json.field;
849
+ ```
850
+
851
+ #### Mistake 2: Forgetting .json Property
852
+
853
+ ```javascript
854
+ // WRONG: Trying to access fields on item object
855
+ const items = $input.all();
856
+ const names = items.map((item) => item.name); // undefined
857
+
858
+ // CORRECT: Access via .json
859
+ const names = items.map((item) => item.json.name);
860
+ ```
861
+
862
+ #### Mistake 3: Using $input.item in All Items Mode
863
+
864
+ ```javascript
865
+ // WRONG: $input.item is undefined in "All Items" mode
866
+ const data = $input.item.json; // Error!
867
+
868
+ // CORRECT: Use appropriate method
869
+ const data = $input.first().json; // Or $input.all()
870
+ ```
871
+
872
+ #### Mistake 4: Not Handling Empty Arrays
873
+
874
+ ```javascript
875
+ // WRONG: Crashes if no items
876
+ const first = $input.all()[0].json;
877
+
878
+ // CORRECT: Check length first
879
+ const items = $input.all();
880
+ if (items.length === 0) {
881
+ return [];
882
+ }
883
+ const first = items[0].json;
884
+
885
+ // ALSO CORRECT: Use $input.first()
886
+ const first = $input.first().json; // Built-in safety
887
+ ```
888
+
889
+ #### Mistake 5: Modifying Original Data
890
+
891
+ ```javascript
892
+ // RISKY: Mutating original
893
+ const items = $input.all();
894
+ items[0].json.modified = true; // Modifies original
895
+ return items;
896
+
897
+ // SAFE: Create new objects
898
+ const items = $input.all();
899
+ return items.map((item) => ({
900
+ json: {
901
+ ...item.json,
902
+ modified: true,
903
+ },
904
+ }));
905
+ ```
906
+
907
+ ### Advanced Data Access Patterns
908
+
909
+ #### Pattern: Pagination Handling
910
+
911
+ ```javascript
912
+ const currentPage = $input.all();
913
+ const pageNumber = $node["Set Page"].json.page || 1;
914
+
915
+ // Combine with previous pages
916
+ const allPreviousPages = $node["Accumulator"]?.json.accumulated || [];
917
+
918
+ return [
919
+ {
920
+ json: {
921
+ accumulated: [...allPreviousPages, ...currentPage],
922
+ currentPage: pageNumber,
923
+ totalItems: allPreviousPages.length + currentPage.length,
924
+ },
925
+ },
926
+ ];
927
+ ```
928
+
929
+ #### Pattern: Conditional Node Reference
930
+
931
+ ```javascript
932
+ // Access different nodes based on condition
933
+ const condition = $input.first().json.type;
934
+
935
+ let data;
936
+ if (condition === "api") {
937
+ data = $node["API Response"].json;
938
+ } else if (condition === "database") {
939
+ data = $node["Database"].json;
940
+ } else {
941
+ data = $node["Default"].json;
942
+ }
943
+
944
+ return [{ json: data }];
945
+ ```
946
+
947
+ #### Pattern: Multi-Node Aggregation
948
+
949
+ ```javascript
950
+ // Collect data from multiple named nodes
951
+ const sources = ["Source1", "Source2", "Source3"];
952
+ const allData = [];
953
+
954
+ for (const source of sources) {
955
+ const nodeData = $node[source]?.json;
956
+ if (nodeData) {
957
+ allData.push({
958
+ source,
959
+ data: nodeData,
960
+ });
961
+ }
962
+ }
963
+
964
+ return allData.map((item) => ({ json: item }));
965
+ ```
966
+
967
+ ---
968
+
969
+ ## Built-in Functions & Helpers
970
+
971
+ n8n Code nodes provide powerful built-in functions beyond standard JavaScript:
972
+
973
+ 1. **$helpers.httpRequest()** - Make HTTP requests
974
+ 2. **DateTime (Luxon)** - Advanced date/time operations
975
+ 3. **$jmespath()** - Query JSON structures
976
+ 4. **$getWorkflowStaticData()** - Persistent storage
977
+ 5. **Standard JavaScript Globals** - Math, JSON, console, etc.
978
+ 6. **Available Node.js Modules** - crypto, Buffer, URL
979
+
980
+ ### 1. $helpers.httpRequest() - HTTP Requests
981
+
982
+ Make HTTP requests directly from Code nodes without using HTTP Request node.
983
+
984
+ #### Basic Usage
985
+
986
+ ```javascript
987
+ const response = await $helpers.httpRequest({
988
+ method: "GET",
989
+ url: "https://api.example.com/users",
990
+ });
991
+
992
+ return [{ json: { data: response } }];
993
+ ```
994
+
995
+ #### Complete Options
996
+
997
+ ```javascript
998
+ const response = await $helpers.httpRequest({
999
+ method: "POST", // GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
1000
+ url: "https://api.example.com/users",
1001
+ headers: {
1002
+ Authorization: "Bearer token123",
1003
+ "Content-Type": "application/json",
1004
+ "User-Agent": "n8n-workflow",
1005
+ },
1006
+ body: {
1007
+ name: "John Doe",
1008
+ email: "john@example.com",
1009
+ },
1010
+ qs: {
1011
+ // Query string parameters
1012
+ page: 1,
1013
+ limit: 10,
1014
+ },
1015
+ timeout: 10000, // Milliseconds (default: no timeout)
1016
+ json: true, // Auto-parse JSON response (default: true)
1017
+ simple: false, // Don't throw on HTTP errors (default: true)
1018
+ resolveWithFullResponse: false, // Return only body (default: false)
1019
+ });
1020
+ ```
1021
+
1022
+ #### GET Request
1023
+
1024
+ ```javascript
1025
+ // Simple GET
1026
+ const users = await $helpers.httpRequest({
1027
+ method: "GET",
1028
+ url: "https://api.example.com/users",
1029
+ });
1030
+
1031
+ return [{ json: { users } }];
1032
+ ```
1033
+
1034
+ ```javascript
1035
+ // GET with query parameters
1036
+ const results = await $helpers.httpRequest({
1037
+ method: "GET",
1038
+ url: "https://api.example.com/search",
1039
+ qs: {
1040
+ q: "javascript",
1041
+ page: 1,
1042
+ per_page: 50,
1043
+ },
1044
+ });
1045
+
1046
+ return [{ json: results }];
1047
+ ```
1048
+
1049
+ #### POST Request
1050
+
1051
+ ```javascript
1052
+ // POST with JSON body
1053
+ const newUser = await $helpers.httpRequest({
1054
+ method: "POST",
1055
+ url: "https://api.example.com/users",
1056
+ headers: {
1057
+ "Content-Type": "application/json",
1058
+ Authorization: "Bearer " + $env.API_KEY,
1059
+ },
1060
+ body: {
1061
+ name: $json.body.name,
1062
+ email: $json.body.email,
1063
+ role: "user",
1064
+ },
1065
+ });
1066
+
1067
+ return [{ json: newUser }];
1068
+ ```
1069
+
1070
+ #### PUT/PATCH Request
1071
+
1072
+ ```javascript
1073
+ // Update resource
1074
+ const updated = await $helpers.httpRequest({
1075
+ method: "PATCH",
1076
+ url: `https://api.example.com/users/${userId}`,
1077
+ body: {
1078
+ name: "Updated Name",
1079
+ status: "active",
1080
+ },
1081
+ });
1082
+
1083
+ return [{ json: updated }];
1084
+ ```
1085
+
1086
+ #### DELETE Request
1087
+
1088
+ ```javascript
1089
+ // Delete resource
1090
+ await $helpers.httpRequest({
1091
+ method: "DELETE",
1092
+ url: `https://api.example.com/users/${userId}`,
1093
+ headers: {
1094
+ Authorization: "Bearer " + $env.API_KEY,
1095
+ },
1096
+ });
1097
+
1098
+ return [{ json: { deleted: true, userId } }];
1099
+ ```
1100
+
1101
+ #### Authentication Patterns
1102
+
1103
+ ```javascript
1104
+ // Bearer Token
1105
+ const response = await $helpers.httpRequest({
1106
+ url: "https://api.example.com/data",
1107
+ headers: {
1108
+ Authorization: `Bearer ${$env.API_TOKEN}`,
1109
+ },
1110
+ });
1111
+ ```
1112
+
1113
+ ```javascript
1114
+ // API Key in Header
1115
+ const response = await $helpers.httpRequest({
1116
+ url: "https://api.example.com/data",
1117
+ headers: {
1118
+ "X-API-Key": $env.API_KEY,
1119
+ },
1120
+ });
1121
+ ```
1122
+
1123
+ ```javascript
1124
+ // Basic Auth (manual)
1125
+ const credentials = Buffer.from(`${username}:${password}`).toString("base64");
1126
+
1127
+ const response = await $helpers.httpRequest({
1128
+ url: "https://api.example.com/data",
1129
+ headers: {
1130
+ Authorization: `Basic ${credentials}`,
1131
+ },
1132
+ });
1133
+ ```
1134
+
1135
+ #### Error Handling
1136
+
1137
+ ```javascript
1138
+ // Handle HTTP errors gracefully
1139
+ try {
1140
+ const response = await $helpers.httpRequest({
1141
+ method: "GET",
1142
+ url: "https://api.example.com/users",
1143
+ simple: false, // Don't throw on 4xx/5xx
1144
+ });
1145
+
1146
+ if (response.statusCode >= 200 && response.statusCode < 300) {
1147
+ return [{ json: { success: true, data: response.body } }];
1148
+ } else {
1149
+ return [
1150
+ {
1151
+ json: {
1152
+ success: false,
1153
+ status: response.statusCode,
1154
+ error: response.body,
1155
+ },
1156
+ },
1157
+ ];
1158
+ }
1159
+ } catch (error) {
1160
+ return [
1161
+ {
1162
+ json: {
1163
+ success: false,
1164
+ error: error.message,
1165
+ },
1166
+ },
1167
+ ];
1168
+ }
1169
+ ```
1170
+
1171
+ #### Full Response Access
1172
+
1173
+ ```javascript
1174
+ // Get full response including headers and status
1175
+ const response = await $helpers.httpRequest({
1176
+ url: "https://api.example.com/data",
1177
+ resolveWithFullResponse: true,
1178
+ });
1179
+
1180
+ return [
1181
+ {
1182
+ json: {
1183
+ statusCode: response.statusCode,
1184
+ headers: response.headers,
1185
+ body: response.body,
1186
+ rateLimit: response.headers["x-ratelimit-remaining"],
1187
+ },
1188
+ },
1189
+ ];
1190
+ ```
1191
+
1192
+ ### 2. DateTime (Luxon) - Date & Time Operations
1193
+
1194
+ n8n includes Luxon for powerful date/time handling. Access via `DateTime` global.
1195
+
1196
+ #### Current Date/Time
1197
+
1198
+ ```javascript
1199
+ // Current time
1200
+ const now = DateTime.now();
1201
+
1202
+ // Current time in specific timezone
1203
+ const nowTokyo = DateTime.now().setZone("Asia/Tokyo");
1204
+
1205
+ // Today at midnight
1206
+ const today = DateTime.now().startOf("day");
1207
+
1208
+ return [
1209
+ {
1210
+ json: {
1211
+ iso: now.toISO(), // "2025-01-20T15:30:00.000Z"
1212
+ formatted: now.toFormat("yyyy-MM-dd HH:mm:ss"), // "2025-01-20 15:30:00"
1213
+ unix: now.toSeconds(), // Unix timestamp
1214
+ millis: now.toMillis(), // Milliseconds since epoch
1215
+ },
1216
+ },
1217
+ ];
1218
+ ```
1219
+
1220
+ #### Formatting Dates
1221
+
1222
+ ```javascript
1223
+ const now = DateTime.now();
1224
+
1225
+ return [
1226
+ {
1227
+ json: {
1228
+ isoFormat: now.toISO(), // ISO 8601: "2025-01-20T15:30:00.000Z"
1229
+ sqlFormat: now.toSQL(), // SQL: "2025-01-20 15:30:00.000"
1230
+ httpFormat: now.toHTTP(), // HTTP: "Mon, 20 Jan 2025 15:30:00 GMT"
1231
+
1232
+ // Custom formats
1233
+ dateOnly: now.toFormat("yyyy-MM-dd"), // "2025-01-20"
1234
+ timeOnly: now.toFormat("HH:mm:ss"), // "15:30:00"
1235
+ readable: now.toFormat("MMMM dd, yyyy"), // "January 20, 2025"
1236
+ compact: now.toFormat("yyyyMMdd"), // "20250120"
1237
+ withDay: now.toFormat("EEEE, MMMM dd, yyyy"), // "Monday, January 20, 2025"
1238
+ custom: now.toFormat("dd/MM/yy HH:mm"), // "20/01/25 15:30"
1239
+ },
1240
+ },
1241
+ ];
1242
+ ```
1243
+
1244
+ #### Parsing Dates
1245
+
1246
+ ```javascript
1247
+ // From ISO string
1248
+ const dt1 = DateTime.fromISO("2025-01-20T15:30:00");
1249
+
1250
+ // From specific format
1251
+ const dt2 = DateTime.fromFormat("01/20/2025", "MM/dd/yyyy");
1252
+
1253
+ // From SQL
1254
+ const dt3 = DateTime.fromSQL("2025-01-20 15:30:00");
1255
+
1256
+ // From Unix timestamp
1257
+ const dt4 = DateTime.fromSeconds(1737384600);
1258
+
1259
+ // From milliseconds
1260
+ const dt5 = DateTime.fromMillis(1737384600000);
1261
+
1262
+ return [{ json: { parsed: dt1.toISO() } }];
1263
+ ```
1264
+
1265
+ #### Date Arithmetic
1266
+
1267
+ ```javascript
1268
+ const now = DateTime.now();
1269
+
1270
+ return [
1271
+ {
1272
+ json: {
1273
+ // Adding time
1274
+ tomorrow: now.plus({ days: 1 }).toISO(),
1275
+ nextWeek: now.plus({ weeks: 1 }).toISO(),
1276
+ nextMonth: now.plus({ months: 1 }).toISO(),
1277
+ inTwoHours: now.plus({ hours: 2 }).toISO(),
1278
+
1279
+ // Subtracting time
1280
+ yesterday: now.minus({ days: 1 }).toISO(),
1281
+ lastWeek: now.minus({ weeks: 1 }).toISO(),
1282
+ lastMonth: now.minus({ months: 1 }).toISO(),
1283
+ twoHoursAgo: now.minus({ hours: 2 }).toISO(),
1284
+
1285
+ // Complex operations
1286
+ in90Days: now.plus({ days: 90 }).toFormat("yyyy-MM-dd"),
1287
+ in6Months: now.plus({ months: 6 }).toFormat("yyyy-MM-dd"),
1288
+ },
1289
+ },
1290
+ ];
1291
+ ```
1292
+
1293
+ #### Time Comparisons
1294
+
1295
+ ```javascript
1296
+ const now = DateTime.now();
1297
+ const targetDate = DateTime.fromISO("2025-12-31");
1298
+
1299
+ return [
1300
+ {
1301
+ json: {
1302
+ // Comparisons
1303
+ isFuture: targetDate > now,
1304
+ isPast: targetDate < now,
1305
+ isEqual: targetDate.equals(now),
1306
+
1307
+ // Differences
1308
+ daysUntil: targetDate.diff(now, "days").days,
1309
+ hoursUntil: targetDate.diff(now, "hours").hours,
1310
+ monthsUntil: targetDate.diff(now, "months").months,
1311
+
1312
+ // Detailed difference
1313
+ detailedDiff: targetDate
1314
+ .diff(now, ["months", "days", "hours"])
1315
+ .toObject(),
1316
+ },
1317
+ },
1318
+ ];
1319
+ ```
1320
+
1321
+ #### Timezone Operations
1322
+
1323
+ ```javascript
1324
+ const now = DateTime.now();
1325
+
1326
+ return [
1327
+ {
1328
+ json: {
1329
+ // Current timezone
1330
+ local: now.toISO(),
1331
+
1332
+ // Convert to different timezone
1333
+ tokyo: now.setZone("Asia/Tokyo").toISO(),
1334
+ newYork: now.setZone("America/New_York").toISO(),
1335
+ london: now.setZone("Europe/London").toISO(),
1336
+ utc: now.toUTC().toISO(),
1337
+
1338
+ // Get timezone info
1339
+ timezone: now.zoneName, // "America/Los_Angeles"
1340
+ offset: now.offset, // Offset in minutes
1341
+ offsetFormatted: now.toFormat("ZZ"), // "+08:00"
1342
+ },
1343
+ },
1344
+ ];
1345
+ ```
1346
+
1347
+ #### Start/End of Period
1348
+
1349
+ ```javascript
1350
+ const now = DateTime.now();
1351
+
1352
+ return [
1353
+ {
1354
+ json: {
1355
+ startOfDay: now.startOf("day").toISO(),
1356
+ endOfDay: now.endOf("day").toISO(),
1357
+ startOfWeek: now.startOf("week").toISO(),
1358
+ endOfWeek: now.endOf("week").toISO(),
1359
+ startOfMonth: now.startOf("month").toISO(),
1360
+ endOfMonth: now.endOf("month").toISO(),
1361
+ startOfYear: now.startOf("year").toISO(),
1362
+ endOfYear: now.endOf("year").toISO(),
1363
+ },
1364
+ },
1365
+ ];
1366
+ ```
1367
+
1368
+ #### Weekday & Month Info
1369
+
1370
+ ```javascript
1371
+ const now = DateTime.now();
1372
+
1373
+ return [
1374
+ {
1375
+ json: {
1376
+ // Day info
1377
+ weekday: now.weekday, // 1 = Monday, 7 = Sunday
1378
+ weekdayShort: now.weekdayShort, // "Mon"
1379
+ weekdayLong: now.weekdayLong, // "Monday"
1380
+ isWeekend: now.weekday > 5, // Saturday or Sunday
1381
+
1382
+ // Month info
1383
+ month: now.month, // 1-12
1384
+ monthShort: now.monthShort, // "Jan"
1385
+ monthLong: now.monthLong, // "January"
1386
+
1387
+ // Year info
1388
+ year: now.year, // 2025
1389
+ quarter: now.quarter, // 1-4
1390
+ daysInMonth: now.daysInMonth, // 28-31
1391
+ },
1392
+ },
1393
+ ];
1394
+ ```
1395
+
1396
+ ### 3. $jmespath() - JSON Querying
1397
+
1398
+ Query and transform JSON structures using JMESPath syntax.
1399
+
1400
+ #### Basic Queries
1401
+
1402
+ ```javascript
1403
+ const data = $input.first().json;
1404
+
1405
+ // Extract specific field
1406
+ const names = $jmespath(data, "users[*].name");
1407
+
1408
+ // Filter array
1409
+ const adults = $jmespath(data, "users[?age >= `18`]");
1410
+
1411
+ // Get specific index
1412
+ const firstUser = $jmespath(data, "users[0]");
1413
+
1414
+ return [{ json: { names, adults, firstUser } }];
1415
+ ```
1416
+
1417
+ #### Advanced Queries
1418
+
1419
+ ```javascript
1420
+ const data = $input.first().json;
1421
+
1422
+ // Sort and slice
1423
+ const top5 = $jmespath(data, "users | sort_by(@, &score) | reverse(@) | [0:5]");
1424
+
1425
+ // Extract nested fields
1426
+ const emails = $jmespath(data, "users[*].contact.email");
1427
+
1428
+ // Multi-field extraction
1429
+ const simplified = $jmespath(
1430
+ data,
1431
+ "users[*].{name: name, email: contact.email}",
1432
+ );
1433
+
1434
+ // Conditional filtering
1435
+ const premium = $jmespath(data, "users[?subscription.tier == `premium`]");
1436
+
1437
+ return [{ json: { top5, emails, simplified, premium } }];
1438
+ ```
1439
+
1440
+ #### Common JMESPath Patterns
1441
+
1442
+ ```javascript
1443
+ // Pattern 1: Filter and project
1444
+ const query1 = $jmespath(
1445
+ data,
1446
+ "products[?price > `100`].{name: name, price: price}",
1447
+ );
1448
+
1449
+ // Pattern 2: Aggregate functions
1450
+ const query2 = $jmespath(data, "sum(products[*].price)");
1451
+ const query3 = $jmespath(data, "max(products[*].price)");
1452
+ const query4 = $jmespath(data, "length(products)");
1453
+
1454
+ // Pattern 3: Nested filtering
1455
+ const query5 = $jmespath(data, "categories[*].products[?inStock == `true`]");
1456
+
1457
+ return [{ json: { query1, query2, query3, query4, query5 } }];
1458
+ ```
1459
+
1460
+ ### 4. $getWorkflowStaticData() - Persistent Storage
1461
+
1462
+ Store data that persists across workflow executions.
1463
+
1464
+ #### Basic Usage
1465
+
1466
+ ```javascript
1467
+ // Get static data storage
1468
+ const staticData = $getWorkflowStaticData();
1469
+
1470
+ // Initialize counter if doesn't exist
1471
+ if (!staticData.counter) {
1472
+ staticData.counter = 0;
1473
+ }
1474
+
1475
+ // Increment counter
1476
+ staticData.counter++;
1477
+
1478
+ return [
1479
+ {
1480
+ json: {
1481
+ executionCount: staticData.counter,
1482
+ },
1483
+ },
1484
+ ];
1485
+ ```
1486
+
1487
+ #### Use Cases
1488
+
1489
+ ```javascript
1490
+ // Use Case 1: Rate limiting
1491
+ const staticData = $getWorkflowStaticData();
1492
+ const now = Date.now();
1493
+
1494
+ if (!staticData.lastRun) {
1495
+ staticData.lastRun = now;
1496
+ staticData.runCount = 1;
1497
+ } else {
1498
+ const timeSinceLastRun = now - staticData.lastRun;
1499
+
1500
+ if (timeSinceLastRun < 60000) {
1501
+ // Less than 1 minute
1502
+ return [{ json: { error: "Rate limit: wait 1 minute between runs" } }];
1503
+ }
1504
+
1505
+ staticData.lastRun = now;
1506
+ staticData.runCount++;
1507
+ }
1508
+
1509
+ return [{ json: { allowed: true, totalRuns: staticData.runCount } }];
1510
+ ```
1511
+
1512
+ ```javascript
1513
+ // Use Case 2: Tracking last processed ID
1514
+ const staticData = $getWorkflowStaticData();
1515
+ const currentItems = $input.all();
1516
+
1517
+ // Get last processed ID
1518
+ const lastId = staticData.lastProcessedId || 0;
1519
+
1520
+ // Filter only new items
1521
+ const newItems = currentItems.filter((item) => item.json.id > lastId);
1522
+
1523
+ // Update last processed ID
1524
+ if (newItems.length > 0) {
1525
+ staticData.lastProcessedId = Math.max(
1526
+ ...newItems.map((item) => item.json.id),
1527
+ );
1528
+ }
1529
+
1530
+ return newItems;
1531
+ ```
1532
+
1533
+ ```javascript
1534
+ // Use Case 3: Accumulating results
1535
+ const staticData = $getWorkflowStaticData();
1536
+
1537
+ if (!staticData.accumulated) {
1538
+ staticData.accumulated = [];
1539
+ }
1540
+
1541
+ // Add current items to accumulated list
1542
+ const currentData = $input.all().map((item) => item.json);
1543
+ staticData.accumulated.push(...currentData);
1544
+
1545
+ return [
1546
+ {
1547
+ json: {
1548
+ currentBatch: currentData.length,
1549
+ totalAccumulated: staticData.accumulated.length,
1550
+ allData: staticData.accumulated,
1551
+ },
1552
+ },
1553
+ ];
1554
+ ```
1555
+
1556
+ ### 5. Standard JavaScript Globals
1557
+
1558
+ #### Math Object
1559
+
1560
+ ```javascript
1561
+ return [
1562
+ {
1563
+ json: {
1564
+ // Rounding
1565
+ rounded: Math.round(3.7), // 4
1566
+ floor: Math.floor(3.7), // 3
1567
+ ceil: Math.ceil(3.2), // 4
1568
+
1569
+ // Min/Max
1570
+ max: Math.max(1, 5, 3, 9, 2), // 9
1571
+ min: Math.min(1, 5, 3, 9, 2), // 1
1572
+
1573
+ // Random
1574
+ random: Math.random(), // 0-1
1575
+ randomInt: Math.floor(Math.random() * 100), // 0-99
1576
+
1577
+ // Other
1578
+ abs: Math.abs(-5), // 5
1579
+ sqrt: Math.sqrt(16), // 4
1580
+ pow: Math.pow(2, 3), // 8
1581
+ },
1582
+ },
1583
+ ];
1584
+ ```
1585
+
1586
+ #### JSON Object
1587
+
1588
+ ```javascript
1589
+ // Parse JSON string
1590
+ const jsonString = '{"name": "John", "age": 30}';
1591
+ const parsed = JSON.parse(jsonString);
1592
+
1593
+ // Stringify object
1594
+ const obj = { name: "John", age: 30 };
1595
+ const stringified = JSON.stringify(obj);
1596
+
1597
+ // Pretty print
1598
+ const pretty = JSON.stringify(obj, null, 2);
1599
+
1600
+ return [{ json: { parsed, stringified, pretty } }];
1601
+ ```
1602
+
1603
+ #### console Object
1604
+
1605
+ ```javascript
1606
+ // Debug logging (appears in browser console, press F12)
1607
+ console.log("Processing items:", $input.all().length);
1608
+ console.log("First item:", $input.first().json);
1609
+
1610
+ // Other console methods
1611
+ console.error("Error message");
1612
+ console.warn("Warning message");
1613
+ console.info("Info message");
1614
+
1615
+ // Continues to return data
1616
+ return [{ json: { processed: true } }];
1617
+ ```
1618
+
1619
+ #### Object Methods
1620
+
1621
+ ```javascript
1622
+ const obj = { name: "John", age: 30, city: "NYC" };
1623
+
1624
+ return [
1625
+ {
1626
+ json: {
1627
+ keys: Object.keys(obj), // ["name", "age", "city"]
1628
+ values: Object.values(obj), // ["John", 30, "NYC"]
1629
+ entries: Object.entries(obj), // [["name", "John"], ...]
1630
+
1631
+ // Check property
1632
+ hasName: "name" in obj, // true
1633
+
1634
+ // Merge objects
1635
+ merged: Object.assign({}, obj, { country: "USA" }),
1636
+ },
1637
+ },
1638
+ ];
1639
+ ```
1640
+
1641
+ #### Array Methods
1642
+
1643
+ ```javascript
1644
+ const arr = [1, 2, 3, 4, 5];
1645
+
1646
+ return [
1647
+ {
1648
+ json: {
1649
+ mapped: arr.map((x) => x * 2), // [2, 4, 6, 8, 10]
1650
+ filtered: arr.filter((x) => x > 2), // [3, 4, 5]
1651
+ reduced: arr.reduce((sum, x) => sum + x, 0), // 15
1652
+ some: arr.some((x) => x > 3), // true
1653
+ every: arr.every((x) => x > 0), // true
1654
+ find: arr.find((x) => x > 3), // 4
1655
+ includes: arr.includes(3), // true
1656
+ joined: arr.join(", "), // "1, 2, 3, 4, 5"
1657
+ },
1658
+ },
1659
+ ];
1660
+ ```
1661
+
1662
+ ### 6. Available Node.js Modules
1663
+
1664
+ #### crypto Module
1665
+
1666
+ ```javascript
1667
+ const crypto = require("crypto");
1668
+
1669
+ // Hash functions
1670
+ const hash = crypto.createHash("sha256").update("my secret text").digest("hex");
1671
+
1672
+ // MD5 hash
1673
+ const md5 = crypto.createHash("md5").update("my text").digest("hex");
1674
+
1675
+ // Random values
1676
+ const randomBytes = crypto.randomBytes(16).toString("hex");
1677
+
1678
+ return [{ json: { hash, md5, randomBytes } }];
1679
+ ```
1680
+
1681
+ #### Buffer (built-in)
1682
+
1683
+ ```javascript
1684
+ // Base64 encoding
1685
+ const encoded = Buffer.from("Hello World").toString("base64");
1686
+
1687
+ // Base64 decoding
1688
+ const decoded = Buffer.from(encoded, "base64").toString();
1689
+
1690
+ // Hex encoding
1691
+ const hex = Buffer.from("Hello").toString("hex");
1692
+
1693
+ return [{ json: { encoded, decoded, hex } }];
1694
+ ```
1695
+
1696
+ #### URL / URLSearchParams
1697
+
1698
+ ```javascript
1699
+ // Parse URL
1700
+ const url = new URL("https://example.com/path?param1=value1&param2=value2");
1701
+
1702
+ // Build query string
1703
+ const params = new URLSearchParams({
1704
+ search: "query",
1705
+ page: 1,
1706
+ limit: 10,
1707
+ });
1708
+
1709
+ return [
1710
+ {
1711
+ json: {
1712
+ host: url.host,
1713
+ pathname: url.pathname,
1714
+ search: url.search,
1715
+ queryString: params.toString(), // "search=query&page=1&limit=10"
1716
+ },
1717
+ },
1718
+ ];
1719
+ ```
1720
+
1721
+ ### What's NOT Available
1722
+
1723
+ **External npm packages are NOT available:**
1724
+
1725
+ - axios
1726
+ - lodash
1727
+ - moment (use DateTime/Luxon instead)
1728
+ - request
1729
+ - Any other npm package
1730
+
1731
+ **Workaround**: Use $helpers.httpRequest() for HTTP, or add data to workflow via HTTP Request node.
1732
+
1733
+ ---
1734
+
1735
+ ## 10 Common Patterns
1736
+
1737
+ Production-tested patterns for n8n Code nodes. Each pattern includes use case, key techniques, complete example, and variations.
1738
+
1739
+ **Pattern Categories:**
1740
+
1741
+ - Data Aggregation (Patterns 1, 5, 10)
1742
+ - Content Processing (Patterns 2, 3)
1743
+ - Data Validation & Comparison (Patterns 4)
1744
+ - Data Transformation (Patterns 5, 6, 7)
1745
+ - Output Formatting (Pattern 8)
1746
+ - Filtering & Ranking (Pattern 9)
1747
+
1748
+ ### Pattern 1: Multi-Source Data Aggregation
1749
+
1750
+ **Use Case**: Combining data from multiple APIs, RSS feeds, webhooks, or databases
1751
+
1752
+ **When to use:**
1753
+
1754
+ - Collecting data from multiple services
1755
+ - Normalizing different API response formats
1756
+ - Merging data sources into unified structure
1757
+ - Building aggregated reports
1758
+
1759
+ **Key Techniques**: Loop iteration, conditional parsing, data normalization
1760
+
1761
+ #### Complete Example
1762
+
1763
+ ```javascript
1764
+ // Process and structure data collected from multiple sources
1765
+ const allItems = $input.all();
1766
+ let processedArticles = [];
1767
+
1768
+ // Handle different source formats
1769
+ for (const item of allItems) {
1770
+ const sourceName = item.json.name || "Unknown";
1771
+ const sourceData = item.json;
1772
+
1773
+ // Parse source-specific structure - Hacker News format
1774
+ if (sourceName === "Hacker News" && sourceData.hits) {
1775
+ for (const hit of sourceData.hits) {
1776
+ processedArticles.push({
1777
+ title: hit.title,
1778
+ url: hit.url,
1779
+ summary: hit.story_text || "No summary",
1780
+ source: "Hacker News",
1781
+ score: hit.points || 0,
1782
+ fetchedAt: new Date().toISOString(),
1783
+ });
1784
+ }
1785
+ }
1786
+
1787
+ // Parse source-specific structure - Reddit format
1788
+ else if (sourceName === "Reddit" && sourceData.data?.children) {
1789
+ for (const post of sourceData.data.children) {
1790
+ processedArticles.push({
1791
+ title: post.data.title,
1792
+ url: post.data.url,
1793
+ summary: post.data.selftext || "No summary",
1794
+ source: "Reddit",
1795
+ score: post.data.score || 0,
1796
+ fetchedAt: new Date().toISOString(),
1797
+ });
1798
+ }
1799
+ }
1800
+
1801
+ // Parse source-specific structure - RSS feed format
1802
+ else if (sourceName === "RSS" && sourceData.items) {
1803
+ for (const rssItem of sourceData.items) {
1804
+ processedArticles.push({
1805
+ title: rssItem.title,
1806
+ url: rssItem.link,
1807
+ summary: rssItem.description || "No summary",
1808
+ source: "RSS Feed",
1809
+ score: 0,
1810
+ fetchedAt: new Date().toISOString(),
1811
+ });
1812
+ }
1813
+ }
1814
+ }
1815
+
1816
+ // Sort by score (highest first)
1817
+ processedArticles.sort((a, b) => b.score - a.score);
1818
+
1819
+ return processedArticles.map((article) => ({ json: article }));
1820
+ ```
1821
+
1822
+ #### Variations
1823
+
1824
+ ```javascript
1825
+ // Variation 1: Add source weighting
1826
+ for (const article of processedArticles) {
1827
+ const weights = {
1828
+ "Hacker News": 1.5,
1829
+ Reddit: 1.0,
1830
+ "RSS Feed": 0.8,
1831
+ };
1832
+
1833
+ article.weightedScore = article.score * (weights[article.source] || 1.0);
1834
+ }
1835
+
1836
+ // Variation 2: Filter by minimum score
1837
+ processedArticles = processedArticles.filter((article) => article.score >= 10);
1838
+
1839
+ // Variation 3: Deduplicate by URL
1840
+ const seen = new Set();
1841
+ processedArticles = processedArticles.filter((article) => {
1842
+ if (seen.has(article.url)) {
1843
+ return false;
1844
+ }
1845
+ seen.add(article.url);
1846
+ return true;
1847
+ });
1848
+ ```
1849
+
1850
+ ### Pattern 2: Regex Filtering & Pattern Matching
1851
+
1852
+ **Use Case**: Content analysis, keyword extraction, mention tracking, text parsing
1853
+
1854
+ **When to use:**
1855
+
1856
+ - Extracting mentions or tags from text
1857
+ - Finding patterns in unstructured data
1858
+ - Counting keyword occurrences
1859
+ - Validating formats (emails, phone numbers)
1860
+
1861
+ **Key Techniques**: Regex matching, object aggregation, sorting/ranking
1862
+
1863
+ #### Complete Example
1864
+
1865
+ ```javascript
1866
+ // Extract and track mentions using regex patterns
1867
+ const etfPattern = /\b([A-Z]{2,5})\b/g;
1868
+ const knownETFs = ["VOO", "VTI", "VT", "SCHD", "QYLD", "VXUS", "SPY", "QQQ"];
1869
+
1870
+ const etfMentions = {};
1871
+
1872
+ for (const item of $input.all()) {
1873
+ const data = item.json.data;
1874
+
1875
+ // Skip if no data or children
1876
+ if (!data?.children) continue;
1877
+
1878
+ for (const post of data.children) {
1879
+ // Combine title and body text
1880
+ const title = post.data.title || "";
1881
+ const body = post.data.selftext || "";
1882
+ const combinedText = (title + " " + body).toUpperCase();
1883
+
1884
+ // Find all matches
1885
+ const matches = combinedText.match(etfPattern);
1886
+
1887
+ if (matches) {
1888
+ for (const match of matches) {
1889
+ // Only count known ETFs
1890
+ if (knownETFs.includes(match)) {
1891
+ if (!etfMentions[match]) {
1892
+ etfMentions[match] = {
1893
+ count: 0,
1894
+ totalScore: 0,
1895
+ posts: [],
1896
+ };
1897
+ }
1898
+
1899
+ etfMentions[match].count++;
1900
+ etfMentions[match].totalScore += post.data.score || 0;
1901
+ etfMentions[match].posts.push({
1902
+ title: post.data.title,
1903
+ url: post.data.url,
1904
+ score: post.data.score,
1905
+ });
1906
+ }
1907
+ }
1908
+ }
1909
+ }
1910
+ }
1911
+
1912
+ // Convert to array and sort by mention count
1913
+ return Object.entries(etfMentions)
1914
+ .map(([etf, data]) => ({
1915
+ json: {
1916
+ etf,
1917
+ mentions: data.count,
1918
+ totalScore: data.totalScore,
1919
+ averageScore: data.totalScore / data.count,
1920
+ topPosts: data.posts.sort((a, b) => b.score - a.score).slice(0, 3),
1921
+ },
1922
+ }))
1923
+ .sort((a, b) => b.json.mentions - a.json.mentions);
1924
+ ```
1925
+
1926
+ #### Variations
1927
+
1928
+ ```javascript
1929
+ // Variation 1: Email extraction
1930
+ const emailPattern = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g;
1931
+ const emails = text.match(emailPattern) || [];
1932
+
1933
+ // Variation 2: Phone number extraction
1934
+ const phonePattern = /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g;
1935
+ const phones = text.match(phonePattern) || [];
1936
+
1937
+ // Variation 3: Hashtag extraction
1938
+ const hashtagPattern = /#(\w+)/g;
1939
+ const hashtags = [];
1940
+ let match;
1941
+ while ((match = hashtagPattern.exec(text)) !== null) {
1942
+ hashtags.push(match[1]);
1943
+ }
1944
+
1945
+ // Variation 4: URL extraction
1946
+ const urlPattern = /https?:\/\/[^\s]+/g;
1947
+ const urls = text.match(urlPattern) || [];
1948
+ ```
1949
+
1950
+ ### Pattern 3: Markdown Parsing & Structured Data Extraction
1951
+
1952
+ **Use Case**: Parsing formatted text, extracting structured fields, content transformation
1953
+
1954
+ **When to use:**
1955
+
1956
+ - Parsing markdown or HTML
1957
+ - Extracting data from structured text
1958
+ - Converting formatted content to JSON
1959
+ - Processing documentation or articles
1960
+
1961
+ **Key Techniques**: Regex grouping, helper functions, data normalization, while loops for iteration
1962
+
1963
+ #### Complete Example
1964
+
1965
+ ```javascript
1966
+ // Parse markdown and extract structured information
1967
+ const markdown = $input.first().json.data.markdown;
1968
+ const adRegex = /##\s*(.*?)\n(.*?)(?=\n##|\n---|$)/gs;
1969
+
1970
+ const ads = [];
1971
+ let match;
1972
+
1973
+ // Helper function to parse time strings to minutes
1974
+ function parseTimeToMinutes(timeStr) {
1975
+ if (!timeStr) return 999999; // Sort unparseable times last
1976
+
1977
+ const hourMatch = timeStr.match(/(\d+)\s*hour/);
1978
+ const dayMatch = timeStr.match(/(\d+)\s*day/);
1979
+ const minMatch = timeStr.match(/(\d+)\s*min/);
1980
+
1981
+ let totalMinutes = 0;
1982
+ if (dayMatch) totalMinutes += parseInt(dayMatch[1]) * 1440; // 24 * 60
1983
+ if (hourMatch) totalMinutes += parseInt(hourMatch[1]) * 60;
1984
+ if (minMatch) totalMinutes += parseInt(minMatch[1]);
1985
+
1986
+ return totalMinutes;
1987
+ }
1988
+
1989
+ // Extract all job postings from markdown
1990
+ while ((match = adRegex.exec(markdown)) !== null) {
1991
+ const title = match[1]?.trim() || "No title";
1992
+ const content = match[2]?.trim() || "";
1993
+
1994
+ // Extract structured fields from content
1995
+ const districtMatch = content.match(/\*\*District:\*\*\s*(.*?)(?:\n|$)/);
1996
+ const salaryMatch = content.match(/\*\*Salary:\*\*\s*(.*?)(?:\n|$)/);
1997
+ const timeMatch = content.match(/Posted:\s*(.*?)\*/);
1998
+
1999
+ ads.push({
2000
+ title: title,
2001
+ district: districtMatch?.[1].trim() || "Unknown",
2002
+ salary: salaryMatch?.[1].trim() || "Not specified",
2003
+ postedTimeAgo: timeMatch?.[1] || "Unknown",
2004
+ timeInMinutes: parseTimeToMinutes(timeMatch?.[1]),
2005
+ fullContent: content,
2006
+ extractedAt: new Date().toISOString(),
2007
+ });
2008
+ }
2009
+
2010
+ // Sort by recency (posted time)
2011
+ ads.sort((a, b) => a.timeInMinutes - b.timeInMinutes);
2012
+
2013
+ return ads.map((ad) => ({ json: ad }));
2014
+ ```
2015
+
2016
+ #### Variations
2017
+
2018
+ ````javascript
2019
+ // Variation 1: Parse HTML table to JSON
2020
+ const tableRegex = /<tr>(.*?)<\/tr>/gs;
2021
+ const cellRegex = /<td>(.*?)<\/td>/g;
2022
+
2023
+ const rows = [];
2024
+ let tableMatch;
2025
+
2026
+ while ((tableMatch = tableRegex.exec(htmlTable)) !== null) {
2027
+ const cells = [];
2028
+ let cellMatch;
2029
+
2030
+ while ((cellMatch = cellRegex.exec(tableMatch[1])) !== null) {
2031
+ cells.push(cellMatch[1].trim());
2032
+ }
2033
+
2034
+ if (cells.length > 0) {
2035
+ rows.push(cells);
2036
+ }
2037
+ }
2038
+
2039
+ // Variation 2: Extract code blocks from markdown
2040
+ const codeBlockRegex = /```(\w+)?\n(.*?)```/gs;
2041
+ const codeBlocks = [];
2042
+
2043
+ while ((match = codeBlockRegex.exec(markdown)) !== null) {
2044
+ codeBlocks.push({
2045
+ language: match[1] || "plain",
2046
+ code: match[2].trim(),
2047
+ });
2048
+ }
2049
+
2050
+ // Variation 3: Parse YAML frontmatter
2051
+ const frontmatterRegex = /^---\n(.*?)\n---/s;
2052
+ const frontmatterMatch = content.match(frontmatterRegex);
2053
+
2054
+ if (frontmatterMatch) {
2055
+ const yamlLines = frontmatterMatch[1].split("\n");
2056
+ const metadata = {};
2057
+
2058
+ for (const line of yamlLines) {
2059
+ const [key, ...valueParts] = line.split(":");
2060
+ if (key && valueParts.length > 0) {
2061
+ metadata[key.trim()] = valueParts.join(":").trim();
2062
+ }
2063
+ }
2064
+ }
2065
+ ````
2066
+
2067
+ ### Pattern 4: JSON Comparison & Validation
2068
+
2069
+ **Use Case**: Workflow versioning, configuration validation, change detection, data integrity
2070
+
2071
+ **When to use:**
2072
+
2073
+ - Comparing two versions of data
2074
+ - Detecting changes in configurations
2075
+ - Validating data consistency
2076
+ - Checking for differences
2077
+
2078
+ **Key Techniques**: JSON ordering, base64 decoding, deep comparison, object manipulation
2079
+
2080
+ > **See also**: [validation-expert.md](validation-expert.md) for structured validation workflows
2081
+
2082
+ #### Complete Example
2083
+
2084
+ ```javascript
2085
+ // Compare and validate JSON objects from different sources
2086
+ const orderJsonKeys = (jsonObj) => {
2087
+ const ordered = {};
2088
+ Object.keys(jsonObj)
2089
+ .sort()
2090
+ .forEach((key) => {
2091
+ ordered[key] = jsonObj[key];
2092
+ });
2093
+ return ordered;
2094
+ };
2095
+
2096
+ const allItems = $input.all();
2097
+
2098
+ // Assume first item is base64-encoded original, second is current
2099
+ const origWorkflow = JSON.parse(
2100
+ Buffer.from(allItems[0].json.content, "base64").toString(),
2101
+ );
2102
+ const currentWorkflow = allItems[1].json;
2103
+
2104
+ // Order keys for consistent comparison
2105
+ const orderedOriginal = orderJsonKeys(origWorkflow);
2106
+ const orderedCurrent = orderJsonKeys(currentWorkflow);
2107
+
2108
+ // Deep comparison
2109
+ const isSame =
2110
+ JSON.stringify(orderedOriginal) === JSON.stringify(orderedCurrent);
2111
+
2112
+ // Find differences
2113
+ const differences = [];
2114
+ for (const key of Object.keys(orderedOriginal)) {
2115
+ if (
2116
+ JSON.stringify(orderedOriginal[key]) !== JSON.stringify(orderedCurrent[key])
2117
+ ) {
2118
+ differences.push({
2119
+ field: key,
2120
+ original: orderedOriginal[key],
2121
+ current: orderedCurrent[key],
2122
+ });
2123
+ }
2124
+ }
2125
+
2126
+ // Check for new keys
2127
+ for (const key of Object.keys(orderedCurrent)) {
2128
+ if (!(key in orderedOriginal)) {
2129
+ differences.push({
2130
+ field: key,
2131
+ original: null,
2132
+ current: orderedCurrent[key],
2133
+ status: "new",
2134
+ });
2135
+ }
2136
+ }
2137
+
2138
+ return [
2139
+ {
2140
+ json: {
2141
+ identical: isSame,
2142
+ differenceCount: differences.length,
2143
+ differences: differences,
2144
+ original: orderedOriginal,
2145
+ current: orderedCurrent,
2146
+ comparedAt: new Date().toISOString(),
2147
+ },
2148
+ },
2149
+ ];
2150
+ ```
2151
+
2152
+ #### Variations
2153
+
2154
+ ```javascript
2155
+ // Variation 1: Simple equality check
2156
+ const isEqual = JSON.stringify(obj1) === JSON.stringify(obj2);
2157
+
2158
+ // Variation 2: Deep diff with detailed changes
2159
+ function deepDiff(obj1, obj2, path = "") {
2160
+ const changes = [];
2161
+
2162
+ for (const key in obj1) {
2163
+ const currentPath = path ? `${path}.${key}` : key;
2164
+
2165
+ if (!(key in obj2)) {
2166
+ changes.push({ type: "removed", path: currentPath, value: obj1[key] });
2167
+ } else if (typeof obj1[key] === "object" && typeof obj2[key] === "object") {
2168
+ changes.push(...deepDiff(obj1[key], obj2[key], currentPath));
2169
+ } else if (obj1[key] !== obj2[key]) {
2170
+ changes.push({
2171
+ type: "modified",
2172
+ path: currentPath,
2173
+ from: obj1[key],
2174
+ to: obj2[key],
2175
+ });
2176
+ }
2177
+ }
2178
+
2179
+ for (const key in obj2) {
2180
+ if (!(key in obj1)) {
2181
+ const currentPath = path ? `${path}.${key}` : key;
2182
+ changes.push({ type: "added", path: currentPath, value: obj2[key] });
2183
+ }
2184
+ }
2185
+
2186
+ return changes;
2187
+ }
2188
+
2189
+ // Variation 3: Schema validation
2190
+ function validateSchema(data, schema) {
2191
+ const errors = [];
2192
+
2193
+ for (const field of schema.required || []) {
2194
+ if (!(field in data)) {
2195
+ errors.push(`Missing required field: ${field}`);
2196
+ }
2197
+ }
2198
+
2199
+ for (const [field, type] of Object.entries(schema.types || {})) {
2200
+ if (field in data && typeof data[field] !== type) {
2201
+ errors.push(
2202
+ `Field ${field} should be ${type}, got ${typeof data[field]}`,
2203
+ );
2204
+ }
2205
+ }
2206
+
2207
+ return {
2208
+ valid: errors.length === 0,
2209
+ errors,
2210
+ };
2211
+ }
2212
+ ```
2213
+
2214
+ ### Pattern 5: CRM Data Transformation
2215
+
2216
+ **Use Case**: Lead enrichment, data normalization, API preparation, form data processing
2217
+
2218
+ **When to use:**
2219
+
2220
+ - Processing form submissions
2221
+ - Preparing data for CRM APIs
2222
+ - Normalizing contact information
2223
+ - Enriching lead data
2224
+
2225
+ **Key Techniques**: Object destructuring, data mapping, format conversion, field splitting
2226
+
2227
+ #### Complete Example
2228
+
2229
+ ```javascript
2230
+ // Transform form data into CRM-compatible format
2231
+ const item = $input.all()[0];
2232
+ const { name, email, phone, company, course_interest, message, timestamp } =
2233
+ item.json;
2234
+
2235
+ // Split name into first and last
2236
+ const nameParts = name.split(" ");
2237
+ const firstName = nameParts[0] || "";
2238
+ const lastName = nameParts.slice(1).join(" ") || "Unknown";
2239
+
2240
+ // Format phone number
2241
+ const cleanPhone = phone.replace(/[^\d]/g, ""); // Remove non-digits
2242
+
2243
+ // Build CRM data structure
2244
+ const crmData = {
2245
+ data: {
2246
+ type: "Contact",
2247
+ attributes: {
2248
+ first_name: firstName,
2249
+ last_name: lastName,
2250
+ email1: email,
2251
+ phone_work: cleanPhone,
2252
+ account_name: company,
2253
+ description: `Course Interest: ${course_interest}\n\nMessage: ${message}\n\nSubmitted: ${timestamp}`,
2254
+ lead_source: "Website Form",
2255
+ status: "New",
2256
+ },
2257
+ },
2258
+ metadata: {
2259
+ original_submission: timestamp,
2260
+ processed_at: new Date().toISOString(),
2261
+ },
2262
+ };
2263
+
2264
+ return [
2265
+ {
2266
+ json: {
2267
+ ...item.json,
2268
+ crmData,
2269
+ processed: true,
2270
+ },
2271
+ },
2272
+ ];
2273
+ ```
2274
+
2275
+ #### Variations
2276
+
2277
+ ```javascript
2278
+ // Variation 1: Multiple contact processing
2279
+ const contacts = $input.all();
2280
+
2281
+ return contacts.map((item) => {
2282
+ const data = item.json;
2283
+ const [firstName, ...lastNameParts] = data.name.split(" ");
2284
+
2285
+ return {
2286
+ json: {
2287
+ firstName,
2288
+ lastName: lastNameParts.join(" ") || "Unknown",
2289
+ email: data.email.toLowerCase(),
2290
+ phone: data.phone.replace(/[^\d]/g, ""),
2291
+ tags: [data.source, data.interest_level].filter(Boolean),
2292
+ },
2293
+ };
2294
+ });
2295
+
2296
+ // Variation 2: Field validation and normalization
2297
+ function normalizePContact(raw) {
2298
+ return {
2299
+ first_name: raw.firstName?.trim() || "",
2300
+ last_name: raw.lastName?.trim() || "Unknown",
2301
+ email: raw.email?.toLowerCase().trim() || "",
2302
+ phone: raw.phone?.replace(/[^\d]/g, "") || "",
2303
+ company: raw.company?.trim() || "Unknown",
2304
+ title: raw.title?.trim() || "",
2305
+ valid: Boolean(raw.email && raw.firstName),
2306
+ };
2307
+ }
2308
+
2309
+ // Variation 3: Lead scoring
2310
+ function calculateLeadScore(data) {
2311
+ let score = 0;
2312
+
2313
+ if (data.email) score += 10;
2314
+ if (data.phone) score += 10;
2315
+ if (data.company) score += 15;
2316
+ if (data.title?.toLowerCase().includes("director")) score += 20;
2317
+ if (data.title?.toLowerCase().includes("manager")) score += 15;
2318
+ if (data.message?.length > 100) score += 10;
2319
+
2320
+ return score;
2321
+ }
2322
+ ```
2323
+
2324
+ ### Pattern 6: Release Information Processing
2325
+
2326
+ **Use Case**: Version management, changelog parsing, release notes generation, GitHub API processing
2327
+
2328
+ **When to use:**
2329
+
2330
+ - Processing GitHub releases
2331
+ - Filtering stable versions
2332
+ - Generating changelog summaries
2333
+ - Extracting version information
2334
+
2335
+ **Key Techniques**: Array filtering, conditional field extraction, date formatting, string manipulation
2336
+
2337
+ #### Complete Example
2338
+
2339
+ ```javascript
2340
+ // Extract and filter stable releases from GitHub API
2341
+ const allReleases = $input.first().json;
2342
+
2343
+ const stableReleases = allReleases
2344
+ .filter((release) => !release.prerelease && !release.draft)
2345
+ .slice(0, 10)
2346
+ .map((release) => {
2347
+ // Extract highlights section from changelog
2348
+ const body = release.body || "";
2349
+ let highlights = "No highlights available";
2350
+
2351
+ if (body.includes("## Highlights:")) {
2352
+ highlights = body.split("## Highlights:")[1]?.split("##")[0]?.trim();
2353
+ } else {
2354
+ // Fallback to first 500 chars
2355
+ highlights = body.substring(0, 500) + "...";
2356
+ }
2357
+
2358
+ return {
2359
+ tag: release.tag_name,
2360
+ name: release.name,
2361
+ published: release.published_at,
2362
+ publishedDate: new Date(release.published_at).toLocaleDateString(),
2363
+ author: release.author.login,
2364
+ url: release.html_url,
2365
+ changelog: body,
2366
+ highlights: highlights,
2367
+ assetCount: release.assets.length,
2368
+ assets: release.assets.map((asset) => ({
2369
+ name: asset.name,
2370
+ size: asset.size,
2371
+ downloadCount: asset.download_count,
2372
+ downloadUrl: asset.browser_download_url,
2373
+ })),
2374
+ };
2375
+ });
2376
+
2377
+ return stableReleases.map((release) => ({ json: release }));
2378
+ ```
2379
+
2380
+ #### Variations
2381
+
2382
+ ```javascript
2383
+ // Variation 1: Version comparison
2384
+ function compareVersions(v1, v2) {
2385
+ const parts1 = v1.replace("v", "").split(".").map(Number);
2386
+ const parts2 = v2.replace("v", "").split(".").map(Number);
2387
+
2388
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
2389
+ const num1 = parts1[i] || 0;
2390
+ const num2 = parts2[i] || 0;
2391
+
2392
+ if (num1 > num2) return 1;
2393
+ if (num1 < num2) return -1;
2394
+ }
2395
+
2396
+ return 0;
2397
+ }
2398
+
2399
+ // Variation 2: Breaking change detection
2400
+ function hasBreakingChanges(changelog) {
2401
+ const breakingKeywords = [
2402
+ "BREAKING CHANGE",
2403
+ "breaking change",
2404
+ "BC:",
2405
+ "\u{1F4A5}",
2406
+ ];
2407
+
2408
+ return breakingKeywords.some((keyword) => changelog.includes(keyword));
2409
+ }
2410
+
2411
+ // Variation 3: Extract version numbers
2412
+ const versionPattern = /v?(\d+)\.(\d+)\.(\d+)/;
2413
+ const match = tagName.match(versionPattern);
2414
+
2415
+ if (match) {
2416
+ const [_, major, minor, patch] = match;
2417
+ const version = {
2418
+ major: parseInt(major),
2419
+ minor: parseInt(minor),
2420
+ patch: parseInt(patch),
2421
+ };
2422
+ }
2423
+ ```
2424
+
2425
+ ### Pattern 7: Array Transformation with Context
2426
+
2427
+ **Use Case**: Quick data transformation, field mapping, adding computed fields
2428
+
2429
+ **When to use:**
2430
+
2431
+ - Transforming arrays with additional context
2432
+ - Adding calculated fields
2433
+ - Simplifying complex objects
2434
+ - Pluralization logic
2435
+
2436
+ **Key Techniques**: Array methods chaining, ternary operators, computed properties
2437
+
2438
+ #### Complete Example
2439
+
2440
+ ```javascript
2441
+ // Transform releases with contextual information
2442
+ const releases = $input
2443
+ .first()
2444
+ .json.filter((release) => !release.prerelease && !release.draft)
2445
+ .slice(0, 10)
2446
+ .map((release) => ({
2447
+ version: release.tag_name,
2448
+ assetCount: release.assets.length,
2449
+ assetsCountText: release.assets.length === 1 ? "file" : "files",
2450
+ downloadUrl: release.html_url,
2451
+ isRecent:
2452
+ new Date(release.published_at) >
2453
+ new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
2454
+ age: Math.floor(
2455
+ (Date.now() - new Date(release.published_at)) / (24 * 60 * 60 * 1000),
2456
+ ),
2457
+ ageText: `${Math.floor((Date.now() - new Date(release.published_at)) / (24 * 60 * 60 * 1000))} days ago`,
2458
+ }));
2459
+
2460
+ return releases.map((release) => ({ json: release }));
2461
+ ```
2462
+
2463
+ #### Variations
2464
+
2465
+ ```javascript
2466
+ // Variation 1: Add ranking
2467
+ const items = $input
2468
+ .all()
2469
+ .sort((a, b) => b.json.score - a.json.score)
2470
+ .map((item, index) => ({
2471
+ json: {
2472
+ ...item.json,
2473
+ rank: index + 1,
2474
+ medal: index < 3 ? ["\u{1F947}", "\u{1F948}", "\u{1F949}"][index] : "",
2475
+ },
2476
+ }));
2477
+
2478
+ // Variation 2: Add percentage calculations
2479
+ const total = $input.all().reduce((sum, item) => sum + item.json.value, 0);
2480
+
2481
+ const itemsWithPercentage = $input.all().map((item) => ({
2482
+ json: {
2483
+ ...item.json,
2484
+ percentage: ((item.json.value / total) * 100).toFixed(2) + "%",
2485
+ },
2486
+ }));
2487
+
2488
+ // Variation 3: Add category labels
2489
+ const categorize = (value) => {
2490
+ if (value > 100) return "High";
2491
+ if (value > 50) return "Medium";
2492
+ return "Low";
2493
+ };
2494
+
2495
+ const categorized = $input.all().map((item) => ({
2496
+ json: {
2497
+ ...item.json,
2498
+ category: categorize(item.json.value),
2499
+ },
2500
+ }));
2501
+ ```
2502
+
2503
+ ### Pattern 8: Slack Block Kit Formatting
2504
+
2505
+ **Use Case**: Chat notifications, rich message formatting, interactive messages
2506
+
2507
+ **When to use:**
2508
+
2509
+ - Sending formatted Slack messages
2510
+ - Creating interactive notifications
2511
+ - Building rich content for chat platforms
2512
+ - Status reports and alerts
2513
+
2514
+ **Key Techniques**: Template literals, nested objects, Block Kit syntax, date formatting
2515
+
2516
+ #### Complete Example
2517
+
2518
+ ```javascript
2519
+ // Create Slack-formatted message with structured blocks
2520
+ const date = new Date().toISOString().split("T")[0];
2521
+ const data = $input.first().json;
2522
+
2523
+ return [
2524
+ {
2525
+ json: {
2526
+ text: `Daily Report - ${date}`, // Fallback text
2527
+ blocks: [
2528
+ {
2529
+ type: "header",
2530
+ text: {
2531
+ type: "plain_text",
2532
+ text: `\u{1F4CA} Daily Security Report - ${date}`,
2533
+ },
2534
+ },
2535
+ {
2536
+ type: "section",
2537
+ text: {
2538
+ type: "mrkdwn",
2539
+ text: `*Status:* ${data.status === "ok" ? "\u2705 All Clear" : "\u26A0\uFE0F Issues Detected"}\n*Alerts:* ${data.alertCount || 0}\n*Updated:* ${new Date().toLocaleString()}`,
2540
+ },
2541
+ },
2542
+ {
2543
+ type: "divider",
2544
+ },
2545
+ {
2546
+ type: "section",
2547
+ fields: [
2548
+ {
2549
+ type: "mrkdwn",
2550
+ text: `*Failed Logins:*\n${data.failedLogins || 0}`,
2551
+ },
2552
+ {
2553
+ type: "mrkdwn",
2554
+ text: `*API Errors:*\n${data.apiErrors || 0}`,
2555
+ },
2556
+ {
2557
+ type: "mrkdwn",
2558
+ text: `*Uptime:*\n${data.uptime || "100%"}`,
2559
+ },
2560
+ {
2561
+ type: "mrkdwn",
2562
+ text: `*Response Time:*\n${data.avgResponseTime || "N/A"}ms`,
2563
+ },
2564
+ ],
2565
+ },
2566
+ {
2567
+ type: "context",
2568
+ elements: [
2569
+ {
2570
+ type: "mrkdwn",
2571
+ text: `Report generated automatically by n8n workflow`,
2572
+ },
2573
+ ],
2574
+ },
2575
+ ],
2576
+ },
2577
+ },
2578
+ ];
2579
+ ```
2580
+
2581
+ #### Variations
2582
+
2583
+ ```javascript
2584
+ // Variation 1: Interactive buttons
2585
+ const blocksWithButtons = [
2586
+ {
2587
+ type: "section",
2588
+ text: {
2589
+ type: "mrkdwn",
2590
+ text: "Would you like to approve this request?",
2591
+ },
2592
+ accessory: {
2593
+ type: "button",
2594
+ text: {
2595
+ type: "plain_text",
2596
+ text: "Approve",
2597
+ },
2598
+ style: "primary",
2599
+ value: "approve",
2600
+ action_id: "approve_button",
2601
+ },
2602
+ },
2603
+ ];
2604
+
2605
+ // Variation 2: List formatting
2606
+ const items = ["Item 1", "Item 2", "Item 3"];
2607
+ const formattedList = items.map((item, i) => `${i + 1}. ${item}`).join("\n");
2608
+
2609
+ // Variation 3: Status indicators
2610
+ function getStatusEmoji(status) {
2611
+ const statusMap = {
2612
+ success: "\u2705",
2613
+ warning: "\u26A0\uFE0F",
2614
+ error: "\u274C",
2615
+ info: "\u2139\uFE0F",
2616
+ };
2617
+
2618
+ return statusMap[status] || "\u2022";
2619
+ }
2620
+
2621
+ // Variation 4: Truncate long messages
2622
+ function truncate(text, maxLength = 3000) {
2623
+ if (text.length <= maxLength) return text;
2624
+ return text.substring(0, maxLength - 3) + "...";
2625
+ }
2626
+ ```
2627
+
2628
+ ### Pattern 9: Top N Filtering & Ranking
2629
+
2630
+ **Use Case**: RAG pipelines, ranking algorithms, result filtering, leaderboards
2631
+
2632
+ **When to use:**
2633
+
2634
+ - Getting top results by score
2635
+ - Filtering best/worst performers
2636
+ - Building leaderboards
2637
+ - Relevance ranking
2638
+
2639
+ **Key Techniques**: Sorting, slicing, null coalescing, score calculations
2640
+
2641
+ #### Complete Example
2642
+
2643
+ ```javascript
2644
+ // Filter and rank by similarity score, return top results
2645
+ const ragResponse = $input.item.json;
2646
+ const chunks = ragResponse.chunks || [];
2647
+
2648
+ // Sort by similarity (highest first)
2649
+ const topChunks = chunks
2650
+ .sort((a, b) => (b.similarity || 0) - (a.similarity || 0))
2651
+ .slice(0, 6);
2652
+
2653
+ return [
2654
+ {
2655
+ json: {
2656
+ query: ragResponse.query,
2657
+ topChunks: topChunks,
2658
+ count: topChunks.length,
2659
+ maxSimilarity: topChunks[0]?.similarity || 0,
2660
+ minSimilarity: topChunks[topChunks.length - 1]?.similarity || 0,
2661
+ averageSimilarity:
2662
+ topChunks.reduce((sum, chunk) => sum + (chunk.similarity || 0), 0) /
2663
+ topChunks.length,
2664
+ },
2665
+ },
2666
+ ];
2667
+ ```
2668
+
2669
+ #### Variations
2670
+
2671
+ ```javascript
2672
+ // Variation 1: Top N with minimum threshold
2673
+ const threshold = 0.7;
2674
+ const topItems = $input
2675
+ .all()
2676
+ .filter((item) => item.json.score >= threshold)
2677
+ .sort((a, b) => b.json.score - a.json.score)
2678
+ .slice(0, 10);
2679
+
2680
+ // Variation 2: Bottom N (worst performers)
2681
+ const bottomItems = $input
2682
+ .all()
2683
+ .sort((a, b) => a.json.score - b.json.score) // Ascending
2684
+ .slice(0, 5);
2685
+
2686
+ // Variation 3: Top N by multiple criteria
2687
+ const ranked = $input
2688
+ .all()
2689
+ .map((item) => ({
2690
+ ...item,
2691
+ compositeScore: item.json.relevance * 0.6 + item.json.recency * 0.4,
2692
+ }))
2693
+ .sort((a, b) => b.compositeScore - a.compositeScore)
2694
+ .slice(0, 10);
2695
+
2696
+ // Variation 4: Percentile filtering
2697
+ const allScores = $input
2698
+ .all()
2699
+ .map((item) => item.json.score)
2700
+ .sort((a, b) => b - a);
2701
+ const percentile95 = allScores[Math.floor(allScores.length * 0.05)];
2702
+
2703
+ const topPercentile = $input
2704
+ .all()
2705
+ .filter((item) => item.json.score >= percentile95);
2706
+ ```
2707
+
2708
+ ### Pattern 10: String Aggregation & Reporting
2709
+
2710
+ **Use Case**: Report generation, log aggregation, content concatenation, summary creation
2711
+
2712
+ **When to use:**
2713
+
2714
+ - Combining multiple text outputs
2715
+ - Generating reports from data
2716
+ - Aggregating logs or messages
2717
+ - Creating formatted summaries
2718
+
2719
+ **Key Techniques**: Array joining, string concatenation, template literals, timestamp handling
2720
+
2721
+ #### Complete Example
2722
+
2723
+ ```javascript
2724
+ // Aggregate multiple text inputs into formatted report
2725
+ const allItems = $input.all();
2726
+
2727
+ // Collect all messages
2728
+ const messages = allItems.map((item) => item.json.message);
2729
+
2730
+ // Build report
2731
+ const header = `\u{1F3AF} **Daily Summary Report**\n\u{1F4C5} ${new Date().toLocaleString()}\n\u{1F4CA} Total Items: ${messages.length}\n\n`;
2732
+ const divider = "\n\n---\n\n";
2733
+ const footer = `\n\n---\n\n\u2705 Report generated at ${new Date().toISOString()}`;
2734
+
2735
+ const finalReport = header + messages.join(divider) + footer;
2736
+
2737
+ return [
2738
+ {
2739
+ json: {
2740
+ report: finalReport,
2741
+ messageCount: messages.length,
2742
+ generatedAt: new Date().toISOString(),
2743
+ reportLength: finalReport.length,
2744
+ },
2745
+ },
2746
+ ];
2747
+ ```
2748
+
2749
+ #### Variations
2750
+
2751
+ ```javascript
2752
+ // Variation 1: Numbered list
2753
+ const numberedReport = allItems
2754
+ .map(
2755
+ (item, index) =>
2756
+ `${index + 1}. ${item.json.title}\n ${item.json.description}`,
2757
+ )
2758
+ .join("\n\n");
2759
+
2760
+ // Variation 2: Markdown table
2761
+ const headers = "| Name | Status | Score |\n|------|--------|-------|\n";
2762
+ const rows = allItems
2763
+ .map(
2764
+ (item) =>
2765
+ `| ${item.json.name} | ${item.json.status} | ${item.json.score} |`,
2766
+ )
2767
+ .join("\n");
2768
+
2769
+ const table = headers + rows;
2770
+
2771
+ // Variation 3: HTML report
2772
+ const htmlReport = `
2773
+ <!DOCTYPE html>
2774
+ <html>
2775
+ <head><title>Report</title></head>
2776
+ <body>
2777
+ <h1>Report - ${new Date().toLocaleDateString()}</h1>
2778
+ <ul>
2779
+ ${allItems.map((item) => `<li>${item.json.title}: ${item.json.value}</li>`).join("\n ")}
2780
+ </ul>
2781
+ </body>
2782
+ </html>
2783
+ `;
2784
+
2785
+ // Variation 4: JSON summary
2786
+ const summary = {
2787
+ generated: new Date().toISOString(),
2788
+ totalItems: allItems.length,
2789
+ items: allItems.map((item) => item.json),
2790
+ statistics: {
2791
+ total: allItems.reduce((sum, item) => sum + (item.json.value || 0), 0),
2792
+ average:
2793
+ allItems.reduce((sum, item) => sum + (item.json.value || 0), 0) /
2794
+ allItems.length,
2795
+ max: Math.max(...allItems.map((item) => item.json.value || 0)),
2796
+ min: Math.min(...allItems.map((item) => item.json.value || 0)),
2797
+ },
2798
+ };
2799
+ ```
2800
+
2801
+ ### Choosing the Right Pattern
2802
+
2803
+ | Your Goal | Use Pattern |
2804
+ | ------------------------------ | ------------------------------------ |
2805
+ | Combine multiple API responses | Pattern 1 (Multi-source Aggregation) |
2806
+ | Extract mentions or keywords | Pattern 2 (Regex Filtering) |
2807
+ | Parse formatted text | Pattern 3 (Markdown Parsing) |
2808
+ | Detect changes in data | Pattern 4 (JSON Comparison) |
2809
+ | Prepare form data for CRM | Pattern 5 (CRM Transformation) |
2810
+ | Process GitHub releases | Pattern 6 (Release Processing) |
2811
+ | Add computed fields | Pattern 7 (Array Transformation) |
2812
+ | Format Slack messages | Pattern 8 (Block Kit Formatting) |
2813
+ | Get top results | Pattern 9 (Top N Filtering) |
2814
+ | Create text reports | Pattern 10 (String Aggregation) |
2815
+
2816
+ ### Combining Patterns
2817
+
2818
+ Many real workflows combine multiple patterns:
2819
+
2820
+ ```javascript
2821
+ // Example: Multi-source aggregation + Top N filtering
2822
+ const allItems = $input.all();
2823
+ const aggregated = [];
2824
+
2825
+ // Pattern 1: Aggregate from different sources
2826
+ for (const item of allItems) {
2827
+ // ... aggregation logic
2828
+ aggregated.push(normalizedItem);
2829
+ }
2830
+
2831
+ // Pattern 9: Get top 10 by score
2832
+ const top10 = aggregated.sort((a, b) => b.score - a.score).slice(0, 10);
2833
+
2834
+ // Pattern 10: Generate report
2835
+ const report = `Top 10 Items:\n\n${top10.map((item, i) => `${i + 1}. ${item.title} (${item.score})`).join("\n")}`;
2836
+
2837
+ return [{ json: { report, items: top10 } }];
2838
+ ```
2839
+
2840
+ ---
2841
+
2842
+ ## Error Patterns & Prevention
2843
+
2844
+ This section covers the **top 5 error patterns** encountered in n8n Code nodes. Understanding and avoiding these errors will save significant debugging time.
2845
+
2846
+ > **See also**: [validation-expert.md](validation-expert.md) for automated validation of Code node configurations
2847
+
2848
+ **Error Frequency**:
2849
+
2850
+ 1. Empty Code / Missing Return - **38% of failures**
2851
+ 2. Expression Syntax Confusion - **8% of failures**
2852
+ 3. Incorrect Return Wrapper - **5% of failures**
2853
+ 4. Unmatched Expression Brackets - **6% of failures**
2854
+ 5. Missing Null Checks - **Common runtime error**
2855
+
2856
+ ### Error #1: Empty Code or Missing Return Statement
2857
+
2858
+ **Frequency**: Most common error (38% of all validation failures)
2859
+
2860
+ **What Happens**:
2861
+
2862
+ - Workflow execution fails
2863
+ - Next nodes receive no data
2864
+ - Error: "Code cannot be empty" or "Code must return data"
2865
+
2866
+ #### The Problem
2867
+
2868
+ ```javascript
2869
+ // ERROR: No code at all
2870
+ // (Empty code field)
2871
+ ```
2872
+
2873
+ ```javascript
2874
+ // ERROR: Code executes but doesn't return anything
2875
+ const items = $input.all();
2876
+
2877
+ // Process items
2878
+ for (const item of items) {
2879
+ console.log(item.json.name);
2880
+ }
2881
+
2882
+ // Forgot to return!
2883
+ ```
2884
+
2885
+ ```javascript
2886
+ // ERROR: Early return path exists, but not all paths return
2887
+ const items = $input.all();
2888
+
2889
+ if (items.length === 0) {
2890
+ return []; // This path returns
2891
+ }
2892
+
2893
+ // Process items
2894
+ const processed = items.map((item) => ({ json: item.json }));
2895
+
2896
+ // Forgot to return processed!
2897
+ ```
2898
+
2899
+ #### The Solution
2900
+
2901
+ ```javascript
2902
+ // CORRECT: Always return data
2903
+ const items = $input.all();
2904
+
2905
+ // Process items
2906
+ const processed = items.map((item) => ({
2907
+ json: {
2908
+ ...item.json,
2909
+ processed: true,
2910
+ },
2911
+ }));
2912
+
2913
+ return processed; // Return statement present
2914
+ ```
2915
+
2916
+ ```javascript
2917
+ // CORRECT: Return empty array if no items
2918
+ const items = $input.all();
2919
+
2920
+ if (items.length === 0) {
2921
+ return []; // Valid: empty array when no data
2922
+ }
2923
+
2924
+ // Process and return
2925
+ return items.map((item) => ({ json: item.json }));
2926
+ ```
2927
+
2928
+ ```javascript
2929
+ // CORRECT: All code paths return
2930
+ const items = $input.all();
2931
+
2932
+ if (items.length === 0) {
2933
+ return [];
2934
+ } else if (items.length === 1) {
2935
+ return [{ json: { single: true, data: items[0].json } }];
2936
+ } else {
2937
+ return items.map((item) => ({ json: item.json }));
2938
+ }
2939
+
2940
+ // All paths covered
2941
+ ```
2942
+
2943
+ #### Checklist
2944
+
2945
+ - [ ] Code field is not empty
2946
+ - [ ] Return statement exists
2947
+ - [ ] ALL code paths return data (if/else branches)
2948
+ - [ ] Return format is correct (`[{json: {...}}]`)
2949
+ - [ ] Return happens even on errors (use try-catch)
2950
+
2951
+ ### Error #2: Expression Syntax Confusion
2952
+
2953
+ **Frequency**: 8% of validation failures
2954
+
2955
+ **What Happens**:
2956
+
2957
+ - Syntax error in code execution
2958
+ - Error: "Unexpected token" or "Expression syntax is not valid in Code nodes"
2959
+ - Template variables not evaluated
2960
+
2961
+ > **IMPORTANT**: Expression `{{ }}` syntax belongs in other nodes (Set, IF, HTTP Request). Code nodes use plain JavaScript. See [expression-syntax.md](expression-syntax.md) for when to use expressions vs code.
2962
+
2963
+ #### The Problem
2964
+
2965
+ n8n has TWO distinct syntaxes:
2966
+
2967
+ 1. **Expression syntax** `{{ }}` - Used in OTHER nodes (Set, IF, HTTP Request)
2968
+ 2. **JavaScript** - Used in CODE nodes (no `{{ }}`)
2969
+
2970
+ Many developers mistakenly use expression syntax inside Code nodes.
2971
+
2972
+ ```javascript
2973
+ // WRONG: Using n8n expression syntax in Code node
2974
+ const userName = "{{ $json.name }}";
2975
+ const userEmail = "{{ $json.body.email }}";
2976
+
2977
+ return [
2978
+ {
2979
+ json: {
2980
+ name: userName,
2981
+ email: userEmail,
2982
+ },
2983
+ },
2984
+ ];
2985
+
2986
+ // Result: Literal string "{{ $json.name }}", NOT the value!
2987
+ ```
2988
+
2989
+ ```javascript
2990
+ // WRONG: Trying to evaluate expressions
2991
+ const value = "{{ $now.toFormat('yyyy-MM-dd') }}";
2992
+ ```
2993
+
2994
+ #### The Solution
2995
+
2996
+ ```javascript
2997
+ // CORRECT: Use JavaScript directly (no {{ }})
2998
+ const userName = $json.name;
2999
+ const userEmail = $json.body.email;
3000
+
3001
+ return [
3002
+ {
3003
+ json: {
3004
+ name: userName,
3005
+ email: userEmail,
3006
+ },
3007
+ },
3008
+ ];
3009
+ ```
3010
+
3011
+ ```javascript
3012
+ // CORRECT: JavaScript template literals (use backticks)
3013
+ const message = `Hello, ${$json.name}! Your email is ${$json.email}`;
3014
+
3015
+ return [
3016
+ {
3017
+ json: {
3018
+ greeting: message,
3019
+ },
3020
+ },
3021
+ ];
3022
+ ```
3023
+
3024
+ ```javascript
3025
+ // CORRECT: Direct variable access
3026
+ const item = $input.first().json;
3027
+
3028
+ return [
3029
+ {
3030
+ json: {
3031
+ name: item.name,
3032
+ email: item.email,
3033
+ timestamp: new Date().toISOString(), // JavaScript Date, not {{ }}
3034
+ },
3035
+ },
3036
+ ];
3037
+ ```
3038
+
3039
+ #### Comparison Table
3040
+
3041
+ | Context | Syntax | Example |
3042
+ | --------------------- | --------------------- | --------------------------- |
3043
+ | Set node | `{{ }}` expressions | `{{ $json.name }}` |
3044
+ | IF node | `{{ }}` expressions | `{{ $json.age > 18 }}` |
3045
+ | HTTP Request URL | `{{ }}` expressions | `{{ $json.userId }}` |
3046
+ | **Code node** | **JavaScript** | `$json.name` |
3047
+ | **Code node strings** | **Template literals** | `` `Hello ${$json.name}` `` |
3048
+
3049
+ #### Quick Fix Guide
3050
+
3051
+ ```javascript
3052
+ // WRONG -> RIGHT conversions
3053
+
3054
+ // "{{ $json.field }}"
3055
+ // -> $json.field
3056
+
3057
+ // "{{ $now }}"
3058
+ // -> new Date().toISOString()
3059
+
3060
+ // "{{ $node['HTTP Request'].json.data }}"
3061
+ // -> $node["HTTP Request"].json.data
3062
+
3063
+ // `{{ $json.firstName }} {{ $json.lastName }}`
3064
+ // -> `${$json.firstName} ${$json.lastName}`
3065
+ ```
3066
+
3067
+ ### Error #3: Incorrect Return Wrapper Format
3068
+
3069
+ **Frequency**: 5% of validation failures
3070
+
3071
+ **What Happens**:
3072
+
3073
+ - Error: "Return value must be an array of objects"
3074
+ - Error: "Each item must have a json property"
3075
+ - Next nodes receive malformed data
3076
+
3077
+ #### The Problem
3078
+
3079
+ Code nodes MUST return:
3080
+
3081
+ - **Array** of objects
3082
+ - Each object MUST have a **`json` property**
3083
+
3084
+ ```javascript
3085
+ // WRONG: Returning object instead of array
3086
+ return {
3087
+ json: {
3088
+ result: "success",
3089
+ },
3090
+ };
3091
+ // Missing array wrapper []
3092
+ ```
3093
+
3094
+ ```javascript
3095
+ // WRONG: Returning array without json wrapper
3096
+ return [
3097
+ { id: 1, name: "Alice" },
3098
+ { id: 2, name: "Bob" },
3099
+ ];
3100
+ // Missing json property
3101
+ ```
3102
+
3103
+ ```javascript
3104
+ // WRONG: Returning plain value
3105
+ return "processed";
3106
+ ```
3107
+
3108
+ ```javascript
3109
+ // WRONG: Returning items without mapping
3110
+ return $input.all();
3111
+ // Works if items already have json property, but not guaranteed
3112
+ ```
3113
+
3114
+ ```javascript
3115
+ // WRONG: Incomplete structure
3116
+ return [{ data: { result: "success" } }];
3117
+ // Should be {json: {...}}, not {data: {...}}
3118
+ ```
3119
+
3120
+ #### The Solution
3121
+
3122
+ ```javascript
3123
+ // CORRECT: Single result
3124
+ return [
3125
+ {
3126
+ json: {
3127
+ result: "success",
3128
+ timestamp: new Date().toISOString(),
3129
+ },
3130
+ },
3131
+ ];
3132
+ ```
3133
+
3134
+ ```javascript
3135
+ // CORRECT: Multiple results
3136
+ return [
3137
+ { json: { id: 1, name: "Alice" } },
3138
+ { json: { id: 2, name: "Bob" } },
3139
+ { json: { id: 3, name: "Carol" } },
3140
+ ];
3141
+ ```
3142
+
3143
+ ```javascript
3144
+ // CORRECT: Transforming array
3145
+ const items = $input.all();
3146
+
3147
+ return items.map((item) => ({
3148
+ json: {
3149
+ id: item.json.id,
3150
+ name: item.json.name,
3151
+ processed: true,
3152
+ },
3153
+ }));
3154
+ ```
3155
+
3156
+ ```javascript
3157
+ // CORRECT: Empty result
3158
+ return [];
3159
+ // Valid when no data to return
3160
+ ```
3161
+
3162
+ ```javascript
3163
+ // CORRECT: Conditional returns
3164
+ if (shouldProcess) {
3165
+ return [{ json: { result: "processed" } }];
3166
+ } else {
3167
+ return [];
3168
+ }
3169
+ ```
3170
+
3171
+ #### Return Format Checklist
3172
+
3173
+ - [ ] Return value is an **array** `[...]`
3174
+ - [ ] Each array element has **`json` property**
3175
+ - [ ] Structure is `[{json: {...}}]` or `[{json: {...}}, {json: {...}}]`
3176
+ - [ ] NOT `{json: {...}}` (missing array wrapper)
3177
+ - [ ] NOT `[{...}]` (missing json property)
3178
+
3179
+ #### Common Scenarios
3180
+
3181
+ ```javascript
3182
+ // Scenario 1: Single object from API
3183
+ const response = $input.first().json;
3184
+
3185
+ // CORRECT
3186
+ return [{ json: response }];
3187
+
3188
+ // WRONG
3189
+ return { json: response };
3190
+
3191
+ // Scenario 2: Array of objects
3192
+ const users = $input.all();
3193
+
3194
+ // CORRECT
3195
+ return users.map((user) => ({ json: user.json }));
3196
+
3197
+ // WRONG
3198
+ return users; // Risky - depends on existing structure
3199
+
3200
+ // Scenario 3: Computed result
3201
+ const total = $input.all().reduce((sum, item) => sum + item.json.amount, 0);
3202
+
3203
+ // CORRECT
3204
+ return [{ json: { total } }];
3205
+
3206
+ // WRONG
3207
+ return { total };
3208
+
3209
+ // Scenario 4: No results
3210
+ // CORRECT
3211
+ return [];
3212
+
3213
+ // WRONG
3214
+ return null;
3215
+ ```
3216
+
3217
+ ### Error #4: Unmatched Expression Brackets
3218
+
3219
+ **Frequency**: 6% of validation failures
3220
+
3221
+ **What Happens**:
3222
+
3223
+ - Parsing error during save
3224
+ - Error: "Unmatched expression brackets"
3225
+ - Code appears correct but fails validation
3226
+
3227
+ #### The Problem
3228
+
3229
+ This error typically occurs when:
3230
+
3231
+ 1. Strings contain unbalanced quotes
3232
+ 2. Multi-line strings with special characters
3233
+ 3. Template literals with nested brackets
3234
+
3235
+ ```javascript
3236
+ // WRONG: Unescaped quote in string
3237
+ const message = "It's a nice day";
3238
+ // Single quote breaks string
3239
+ ```
3240
+
3241
+ ```javascript
3242
+ // WRONG: Unbalanced brackets in regex
3243
+ const pattern = /\{(\w+)\}/; // JSON storage issue
3244
+ ```
3245
+
3246
+ ```javascript
3247
+ // WRONG: Multi-line string with quotes
3248
+ const html = "
3249
+ <div class="container">
3250
+ <p>Hello</p>
3251
+ </div>
3252
+ ";
3253
+ // Quote balance issues
3254
+ ```
3255
+
3256
+ #### The Solution
3257
+
3258
+ ```javascript
3259
+ // CORRECT: Escape quotes
3260
+ const message = "It\\'s a nice day";
3261
+ // Or use different quotes
3262
+ const message = "It's a nice day"; // Double quotes work
3263
+ ```
3264
+
3265
+ ```javascript
3266
+ // CORRECT: Escape regex properly
3267
+ const pattern = /\\{(\\w+)\\}/;
3268
+ ```
3269
+
3270
+ ```javascript
3271
+ // CORRECT: Template literals for multi-line
3272
+ const html = `
3273
+ <div class="container">
3274
+ <p>Hello</p>
3275
+ </div>
3276
+ `;
3277
+ // Backticks handle multi-line and quotes
3278
+ ```
3279
+
3280
+ ```javascript
3281
+ // CORRECT: Escape backslashes
3282
+ const path = "C:\\\\Users\\\\Documents\\\\file.txt";
3283
+ ```
3284
+
3285
+ #### Escaping Guide
3286
+
3287
+ | Character | Escape As | Example |
3288
+ | ------------------------------------ | --------- | ------------------------ |
3289
+ | Single quote in single-quoted string | `\\'` | `'It\\'s working'` |
3290
+ | Double quote in double-quoted string | `\\"` | `"She said \\"hello\\""` |
3291
+ | Backslash | `\\\\` | `"C:\\\\path"` |
3292
+ | Newline | `\\n` | `"Line 1\\nLine 2"` |
3293
+ | Tab | `\\t` | `"Column1\\tColumn2"` |
3294
+
3295
+ #### Best Practices
3296
+
3297
+ ```javascript
3298
+ // BEST: Use template literals for complex strings
3299
+ const message = `User ${name} said: "Hello!"`;
3300
+
3301
+ // BEST: Use template literals for HTML
3302
+ const html = `
3303
+ <div class="${className}">
3304
+ <h1>${title}</h1>
3305
+ <p>${content}</p>
3306
+ </div>
3307
+ `;
3308
+
3309
+ // BEST: Use template literals for JSON
3310
+ const jsonString = `{
3311
+ "name": "${name}",
3312
+ "email": "${email}"
3313
+ }`;
3314
+ ```
3315
+
3316
+ ### Error #5: Missing Null Checks / Undefined Access
3317
+
3318
+ **Frequency**: Very common runtime error
3319
+
3320
+ **What Happens**:
3321
+
3322
+ - Workflow execution stops
3323
+ - Error: "Cannot read property 'X' of undefined"
3324
+ - Error: "Cannot read property 'X' of null"
3325
+ - Crashes on missing data
3326
+
3327
+ #### The Problem
3328
+
3329
+ ```javascript
3330
+ // WRONG: No null check - crashes if user doesn't exist
3331
+ const email = item.json.user.email;
3332
+ ```
3333
+
3334
+ ```javascript
3335
+ // WRONG: Assumes array has items
3336
+ const firstItem = $input.all()[0].json;
3337
+ ```
3338
+
3339
+ ```javascript
3340
+ // WRONG: Assumes nested property exists
3341
+ const city = $json.address.city;
3342
+ ```
3343
+
3344
+ ```javascript
3345
+ // WRONG: No validation before array operations
3346
+ const names = $json.users.map((user) => user.name);
3347
+ ```
3348
+
3349
+ #### The Solution
3350
+
3351
+ ```javascript
3352
+ // CORRECT: Optional chaining
3353
+ const email = item.json?.user?.email || "no-email@example.com";
3354
+ ```
3355
+
3356
+ ```javascript
3357
+ // CORRECT: Check array length
3358
+ const items = $input.all();
3359
+
3360
+ if (items.length === 0) {
3361
+ return [];
3362
+ }
3363
+
3364
+ const firstItem = items[0].json;
3365
+ ```
3366
+
3367
+ ```javascript
3368
+ // CORRECT: Guard clauses
3369
+ const data = $input.first().json;
3370
+
3371
+ if (!data.address) {
3372
+ return [{ json: { error: "No address provided" } }];
3373
+ }
3374
+
3375
+ const city = data.address.city;
3376
+ ```
3377
+
3378
+ ```javascript
3379
+ // CORRECT: Default values
3380
+ const users = $json.users || [];
3381
+ const names = users.map((user) => user.name || "Unknown");
3382
+ ```
3383
+
3384
+ ```javascript
3385
+ // CORRECT: Try-catch for risky operations
3386
+ try {
3387
+ const email = item.json.user.email.toLowerCase();
3388
+ return [{ json: { email } }];
3389
+ } catch (error) {
3390
+ return [
3391
+ {
3392
+ json: {
3393
+ error: "Invalid user data",
3394
+ details: error.message,
3395
+ },
3396
+ },
3397
+ ];
3398
+ }
3399
+ ```
3400
+
3401
+ #### Safe Access Patterns
3402
+
3403
+ ```javascript
3404
+ // Pattern 1: Optional chaining (modern, recommended)
3405
+ const value = data?.nested?.property?.value;
3406
+
3407
+ // Pattern 2: Logical OR with default
3408
+ const value = data.property || "default";
3409
+
3410
+ // Pattern 3: Ternary check
3411
+ const value = data.property ? data.property : "default";
3412
+
3413
+ // Pattern 4: Guard clause
3414
+ if (!data.property) {
3415
+ return [];
3416
+ }
3417
+ const value = data.property;
3418
+
3419
+ // Pattern 5: Try-catch
3420
+ try {
3421
+ const value = data.nested.property.value;
3422
+ } catch (error) {
3423
+ const value = "default";
3424
+ }
3425
+ ```
3426
+
3427
+ #### Webhook Data Safety
3428
+
3429
+ ```javascript
3430
+ // Webhook data requires extra safety
3431
+
3432
+ // RISKY: Assumes all fields exist
3433
+ const name = $json.body.user.name;
3434
+ const email = $json.body.user.email;
3435
+
3436
+ // SAFE: Check each level
3437
+ const body = $json.body || {};
3438
+ const user = body.user || {};
3439
+ const name = user.name || "Unknown";
3440
+ const email = user.email || "no-email";
3441
+
3442
+ // BETTER: Optional chaining
3443
+ const name = $json.body?.user?.name || "Unknown";
3444
+ const email = $json.body?.user?.email || "no-email";
3445
+ ```
3446
+
3447
+ #### Array Safety
3448
+
3449
+ ```javascript
3450
+ // RISKY: No length check
3451
+ const items = $input.all();
3452
+ const firstId = items[0].json.id;
3453
+
3454
+ // SAFE: Check length
3455
+ const items = $input.all();
3456
+
3457
+ if (items.length > 0) {
3458
+ const firstId = items[0].json.id;
3459
+ } else {
3460
+ // Handle empty case
3461
+ return [];
3462
+ }
3463
+
3464
+ // BETTER: Use $input.first()
3465
+ const firstItem = $input.first();
3466
+ const firstId = firstItem.json.id; // Built-in safety
3467
+ ```
3468
+
3469
+ #### Object Property Safety
3470
+
3471
+ ```javascript
3472
+ // RISKY: Direct access
3473
+ const config = $json.settings.advanced.timeout;
3474
+
3475
+ // SAFE: Step by step with defaults
3476
+ const settings = $json.settings || {};
3477
+ const advanced = settings.advanced || {};
3478
+ const timeout = advanced.timeout || 30000;
3479
+
3480
+ // BETTER: Optional chaining
3481
+ const timeout = $json.settings?.advanced?.timeout ?? 30000;
3482
+ // Note: ?? (nullish coalescing) vs || (logical OR)
3483
+ ```
3484
+
3485
+ ### Quick Error Reference
3486
+
3487
+ | Error Message | Likely Cause | Fix |
3488
+ | ------------------------------------- | --------------------------------- | ------------------------------ |
3489
+ | "Code cannot be empty" | Empty code field | Add meaningful code |
3490
+ | "Code must return data" | Missing return statement | Add `return [...]` |
3491
+ | "Return value must be an array" | Returning object instead of array | Wrap in `[...]` |
3492
+ | "Each item must have json property" | Missing `json` wrapper | Use `{json: {...}}` |
3493
+ | "Unexpected token" | Expression syntax `{{ }}` in code | Remove `{{ }}`, use JavaScript |
3494
+ | "Cannot read property X of undefined" | Missing null check | Use optional chaining `?.` |
3495
+ | "Cannot read property X of null" | Null value access | Add guard clause or default |
3496
+ | "Unmatched expression brackets" | Quote/bracket imbalance | Check string escaping |
3497
+
3498
+ ### Debugging Tips
3499
+
3500
+ #### 1. Use console.log()
3501
+
3502
+ ```javascript
3503
+ const items = $input.all();
3504
+ console.log("Items count:", items.length);
3505
+ console.log("First item:", items[0]);
3506
+
3507
+ // Check browser console (F12) for output
3508
+ ```
3509
+
3510
+ #### 2. Return Intermediate Results
3511
+
3512
+ ```javascript
3513
+ // Debug by returning current state
3514
+ const items = $input.all();
3515
+ const processed = items.map((item) => ({ json: item.json }));
3516
+
3517
+ // Return to see what you have
3518
+ return processed;
3519
+ ```
3520
+
3521
+ #### 3. Try-Catch for Troubleshooting
3522
+
3523
+ ```javascript
3524
+ try {
3525
+ // Your code here
3526
+ const result = riskyOperation();
3527
+ return [{ json: { result } }];
3528
+ } catch (error) {
3529
+ // See what failed
3530
+ return [
3531
+ {
3532
+ json: {
3533
+ error: error.message,
3534
+ stack: error.stack,
3535
+ },
3536
+ },
3537
+ ];
3538
+ }
3539
+ ```
3540
+
3541
+ #### 4. Validate Input Structure
3542
+
3543
+ ```javascript
3544
+ const items = $input.all();
3545
+
3546
+ // Check what you received
3547
+ console.log("Input structure:", JSON.stringify(items[0], null, 2));
3548
+
3549
+ // Then process
3550
+ ```
3551
+
3552
+ ---
3553
+
3554
+ ## Error Prevention Checklist
3555
+
3556
+ Use this checklist before deploying Code nodes:
3557
+
3558
+ ### Code Structure
3559
+
3560
+ - [ ] Code field is not empty
3561
+ - [ ] Return statement exists
3562
+ - [ ] All code paths return data
3563
+
3564
+ ### Return Format
3565
+
3566
+ - [ ] Returns array: `[...]`
3567
+ - [ ] Each item has `json` property: `{json: {...}}`
3568
+ - [ ] Format is `[{json: {...}}]`
3569
+
3570
+ ### Syntax
3571
+
3572
+ - [ ] No `{{ }}` expression syntax (use JavaScript) — see [expression-syntax.md](expression-syntax.md)
3573
+ - [ ] Template literals use backticks: `` `${variable}` ``
3574
+ - [ ] All quotes and brackets balanced
3575
+ - [ ] Strings properly escaped
3576
+
3577
+ ### Data Safety
3578
+
3579
+ - [ ] Null checks for optional properties
3580
+ - [ ] Array length checks before access
3581
+ - [ ] Webhook data accessed via `.body`
3582
+ - [ ] Try-catch for risky operations
3583
+ - [ ] Default values for missing data
3584
+
3585
+ ### Testing
3586
+
3587
+ - [ ] Test with empty input
3588
+ - [ ] Test with missing fields
3589
+ - [ ] Test with unexpected data types
3590
+ - [ ] Check browser console for errors
3591
+
3592
+ ---
3593
+
3594
+ ## Best Practices
3595
+
3596
+ ### 1. Always Validate Input Data
3597
+
3598
+ ```javascript
3599
+ const items = $input.all();
3600
+
3601
+ // Check if data exists
3602
+ if (!items || items.length === 0) {
3603
+ return [];
3604
+ }
3605
+
3606
+ // Validate structure
3607
+ if (!items[0].json) {
3608
+ return [{ json: { error: "Invalid input format" } }];
3609
+ }
3610
+
3611
+ // Continue processing...
3612
+ ```
3613
+
3614
+ ### 2. Use Try-Catch for Error Handling
3615
+
3616
+ ```javascript
3617
+ try {
3618
+ const response = await $helpers.httpRequest({
3619
+ url: "https://api.example.com/data",
3620
+ });
3621
+
3622
+ return [{ json: { success: true, data: response } }];
3623
+ } catch (error) {
3624
+ return [
3625
+ {
3626
+ json: {
3627
+ success: false,
3628
+ error: error.message,
3629
+ },
3630
+ },
3631
+ ];
3632
+ }
3633
+ ```
3634
+
3635
+ ### 3. Prefer Array Methods Over Loops
3636
+
3637
+ ```javascript
3638
+ // GOOD: Functional approach
3639
+ const processed = $input
3640
+ .all()
3641
+ .filter((item) => item.json.valid)
3642
+ .map((item) => ({ json: { id: item.json.id } }));
3643
+
3644
+ // SLOWER: Manual loop
3645
+ const processed = [];
3646
+ for (const item of $input.all()) {
3647
+ if (item.json.valid) {
3648
+ processed.push({ json: { id: item.json.id } });
3649
+ }
3650
+ }
3651
+ ```
3652
+
3653
+ ### 4. Filter Early, Process Late
3654
+
3655
+ ```javascript
3656
+ // GOOD: Filter first to reduce processing
3657
+ const processed = $input
3658
+ .all()
3659
+ .filter((item) => item.json.status === "active") // Reduce dataset first
3660
+ .map((item) => expensiveTransformation(item)); // Then transform
3661
+
3662
+ // WASTEFUL: Transform everything, then filter
3663
+ const processed = $input
3664
+ .all()
3665
+ .map((item) => expensiveTransformation(item)) // Wastes CPU
3666
+ .filter((item) => item.json.status === "active");
3667
+ ```
3668
+
3669
+ ### 5. Use Descriptive Variable Names
3670
+
3671
+ ```javascript
3672
+ // GOOD: Clear intent
3673
+ const activeUsers = $input.all().filter((item) => item.json.active);
3674
+ const totalRevenue = activeUsers.reduce(
3675
+ (sum, user) => sum + user.json.revenue,
3676
+ 0,
3677
+ );
3678
+
3679
+ // BAD: Unclear purpose
3680
+ const a = $input.all().filter((item) => item.json.active);
3681
+ const t = a.reduce((s, u) => s + u.json.revenue, 0);
3682
+ ```
3683
+
3684
+ ### 6. Debug with console.log()
3685
+
3686
+ ```javascript
3687
+ // Debug statements appear in browser console
3688
+ const items = $input.all();
3689
+ console.log(`Processing ${items.length} items`);
3690
+
3691
+ for (const item of items) {
3692
+ console.log("Item data:", item.json);
3693
+ // Process...
3694
+ }
3695
+
3696
+ return result;
3697
+ ```
3698
+
3699
+ ---
3700
+
3701
+ ## When to Use Code Node
3702
+
3703
+ Use Code node when:
3704
+
3705
+ - Complex transformations requiring multiple steps
3706
+ - Custom calculations or business logic
3707
+ - Recursive operations
3708
+ - API response parsing with complex structure
3709
+ - Multi-step conditionals
3710
+ - Data aggregation across items
3711
+
3712
+ Consider other nodes when:
3713
+
3714
+ - Simple field mapping -> Use **Set** node
3715
+ - Basic filtering -> Use **Filter** node
3716
+ - Simple conditionals -> Use **IF** or **Switch** node
3717
+ - HTTP requests only -> Use **HTTP Request** node
3718
+
3719
+ **Code node excels at**: Complex logic that would require chaining many simple nodes
3720
+
3721
+ ---
3722
+
3723
+ ## Quick Reference Checklist
3724
+
3725
+ Before deploying Code nodes, verify:
3726
+
3727
+ - [ ] **Code is not empty** - Must have meaningful logic
3728
+ - [ ] **Return statement exists** - Must return array of objects
3729
+ - [ ] **Proper return format** - Each item: `{json: {...}}`
3730
+ - [ ] **Data access correct** - Using `$input.all()`, `$input.first()`, or `$input.item`
3731
+ - [ ] **No n8n expressions** - Use JavaScript template literals: `` `${value}` `` — see [expression-syntax.md](expression-syntax.md)
3732
+ - [ ] **Error handling** - Guard clauses for null/undefined inputs
3733
+ - [ ] **Webhook data** - Access via `.body` if from webhook
3734
+ - [ ] **Mode selection** - "All Items" for most cases
3735
+ - [ ] **Performance** - Prefer map/filter over manual loops
3736
+ - [ ] **Output consistent** - All code paths return same structure
3737
+
3738
+ ---
3739
+
3740
+ ## n8n Documentation
3741
+
3742
+ - Code Node Guide: https://docs.n8n.io/code/code-node/
3743
+ - Built-in Methods: https://docs.n8n.io/code-examples/methods-variables-reference/
3744
+ - Luxon Documentation: https://moment.github.io/luxon/