groundswell 0.0.1 → 0.0.2

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 (242) hide show
  1. package/.claude/commands/subtask-planning/prp-base-create.md +120 -0
  2. package/.claude/commands/subtask-planning/prp-base-execute.md +65 -0
  3. package/.claude/commands/task-breakdown.md +94 -0
  4. package/.claude/system_prompts/task-breakdown.md +1 -0
  5. package/CHANGELOG.md +188 -0
  6. package/PRD.md +543 -0
  7. package/README.md +99 -5
  8. package/examples/README.md +15 -1
  9. package/examples/examples/11-reparenting-workflows.ts +269 -0
  10. package/examples/index.ts +4 -0
  11. package/package-lock.json +2398 -0
  12. package/package.json +3 -1
  13. package/plan/001_d3bb02af4886/TEST_RESULTS.md +259 -0
  14. package/plan/001_d3bb02af4886/bug_fix_tasks.json +484 -0
  15. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S1/PRP.md +488 -0
  16. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S2/PRP.md +581 -0
  17. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M1T1S3/PRP.md +687 -0
  18. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S1/PRP.md +492 -0
  19. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/PRP.md +932 -0
  20. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/concurrent_error_testing_patterns.md +1109 -0
  21. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/vitest_concurrent_testing.md +802 -0
  22. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T1S3/research/workflow_engine_test_references.md +603 -0
  23. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S1/PRP.md +564 -0
  24. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S3/PRP.md +518 -0
  25. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T2S4/PRP.md +1252 -0
  26. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/PRP.md +364 -0
  27. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/CODEBASE_INVENTORY.md +114 -0
  28. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/DECORATOR_DOCUMENTATION_PATTERNS.md +205 -0
  29. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/PRD_LOCATION_ANALYSIS.md +199 -0
  30. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M2T3S1/research/ULTRATHINK_PRP_PLAN.md +134 -0
  31. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/PRP.md +495 -0
  32. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S1/research/console_error_inventory.md +435 -0
  33. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S2/PRP.md +506 -0
  34. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T1S3/PRP.md +612 -0
  35. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/PRP.md +558 -0
  36. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T2S2/research/external_research.md +788 -0
  37. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S2/PRP.md +460 -0
  38. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T3S3/PRP.md +454 -0
  39. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/PRP.md +520 -0
  40. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/RECOMMENDATION.md +417 -0
  41. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/external_workflow_engines_research.md +760 -0
  42. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S1/research/security_implications_analysis.md +245 -0
  43. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M3T4S2/PRP.md +792 -0
  44. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/PRP.md +535 -0
  45. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S1/TEST_EXECUTION_REPORT.md +190 -0
  46. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/PRP.md +654 -0
  47. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/TEST_FIX_REPORT.md +227 -0
  48. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/KEY_FINDINGS.md +345 -0
  49. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/QUICK_REFERENCE.md +193 -0
  50. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T1S2/research/test_maintenance_research.md +1323 -0
  51. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/BREAKING_CHANGES_AUDIT.md +1011 -0
  52. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S1/PRP.md +927 -0
  53. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/P1M4T3S2/PRP.md +505 -0
  54. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/architecture/logger_child_signature_analysis.md +401 -0
  55. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/child_implementation_research.md +142 -0
  56. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/test_patterns_research.md +112 -0
  57. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S3/vitest_patterns_research.md +159 -0
  58. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/PRP.md +549 -0
  59. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/VERIFICATION_REPORT.md +368 -0
  60. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/edge_case_analysis.md +172 -0
  61. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M1T1S4/usage_inventory.md +175 -0
  62. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S2/PRP.md +696 -0
  63. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T1S4/PRP.md +860 -0
  64. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/PRP.md +1066 -0
  65. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01-testing-aggregated-errors.md +1103 -0
  66. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/01_typescript_error_aggregation_patterns.md +789 -0
  67. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02-error-merge-strategy-testing-guide.md +1098 -0
  68. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/02_aggregate_error_patterns.md +1037 -0
  69. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03-promise-allsettled-testing-patterns.md +916 -0
  70. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/03_error_merging_strategies.md +1045 -0
  71. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/04_github_stackoverflow_examples.md +890 -0
  72. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/05_comprehensive_summary.md +822 -0
  73. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/INDEX.md +668 -0
  74. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/QUICK_REFERENCE.md +706 -0
  75. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/README.md +265 -0
  76. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S2/research/RESEARCH_REPORT.md +655 -0
  77. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T2S4/research/vitest_testing_patterns.md +1103 -0
  78. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M2T3S2/PRP.md +426 -0
  79. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/PRP.md +506 -0
  80. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/QUICK_REFERENCE.md +114 -0
  81. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/RESEARCH_SUMMARY.md +316 -0
  82. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S2/research/vitest_observer_error_logging_best_practices.md +754 -0
  83. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T1S3/PRP.md +612 -0
  84. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/PRP.md +719 -0
  85. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/README.md +215 -0
  86. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S1/analysis.md +765 -0
  87. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T2S3/PRP.md +718 -0
  88. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/DECISION.md +149 -0
  89. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/PRP.md +470 -0
  90. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/ULTRATHINK_PLAN.md +332 -0
  91. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/codebase_workflow_name_analysis.md +167 -0
  92. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/external_best_practices.md +265 -0
  93. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T3S1/research/validation_patterns.md +273 -0
  94. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S1/workflow_engine_ancestry_api_research.md +760 -0
  95. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M3T4S3-PRP.md +434 -0
  96. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S1/PRP.md +717 -0
  97. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/PRP.md +472 -0
  98. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/VALIDATION_REPORT.md +125 -0
  99. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/P1M4T2S2/research/ULTRATHINK_PRP_PLAN.md +301 -0
  100. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/error-logging-best-practices.md +1170 -0
  101. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/research_typescript_partial_and_overloads.md +940 -0
  102. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-quick-reference.md +151 -0
  103. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/docs/vitest-research.md +650 -0
  104. package/plan/001_d3bb02af4886/bugfix/001_e8e04329daf3/prd_snapshot.md +259 -0
  105. package/plan/001_d3bb02af4886/bugfix/P1M1T1S1/PRP.md +457 -0
  106. package/plan/001_d3bb02af4886/bugfix/RESEARCH_SUMMARY.md +346 -0
  107. package/plan/001_d3bb02af4886/bugfix/architecture/codebase_structure.md +311 -0
  108. package/plan/001_d3bb02af4886/bugfix/architecture/concurrent_execution_best_practices.md +1565 -0
  109. package/plan/001_d3bb02af4886/bugfix/architecture/error_handling_patterns.md +288 -0
  110. package/plan/001_d3bb02af4886/bugfix/architecture/promise_all_analysis.md +741 -0
  111. package/plan/001_d3bb02af4886/docs/PRP/P1M1T1S4-functional-workflow-error-state-capture-test.md +652 -0
  112. package/plan/001_d3bb02af4886/docs/PRP/PRP.md +527 -0
  113. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S1-PRP.md +415 -0
  114. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S2-PRP.md +378 -0
  115. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M1T2S4-PRP.md +713 -0
  116. package/plan/001_d3bb02af4886/docs/PRP/bugfix/P1M2T1S4-PRP.md +370 -0
  117. package/plan/001_d3bb02af4886/docs/PRP_P1M3T1S3.md +499 -0
  118. package/plan/001_d3bb02af4886/docs/TEST_RESULTS.md +230 -0
  119. package/plan/001_d3bb02af4886/docs/bugfix/ANALYSIS_PRD_VS_IMPLEMENTATION.md +1134 -0
  120. package/plan/001_d3bb02af4886/docs/bugfix/GAP_ANALYSIS_SUMMARY.md +179 -0
  121. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/PRP.md +629 -0
  122. package/plan/001_d3bb02af4886/docs/bugfix/P1M4T2S1/validation-report.md +214 -0
  123. package/plan/001_d3bb02af4886/docs/bugfix/PRP_P1M4T2S3.md +629 -0
  124. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_PRP.md +529 -0
  125. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_QUICK_REFERENCE.md +142 -0
  126. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_README.md +304 -0
  127. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_TEST_RESULTS.md +558 -0
  128. package/plan/001_d3bb02af4886/docs/bugfix/bugfix_VALIDATION_SUMMARY.md +256 -0
  129. package/plan/001_d3bb02af4886/docs/bugfix/system_context.md +346 -0
  130. package/plan/001_d3bb02af4886/docs/bugfix-architecture/bug_analysis.md +415 -0
  131. package/plan/001_d3bb02af4886/docs/bugfix-architecture/implementation_patterns.md +489 -0
  132. package/plan/001_d3bb02af4886/docs/bugfix-architecture/system_context.md +218 -0
  133. package/plan/001_d3bb02af4886/docs/bugfix_INITIATION_SUMMARY.md +380 -0
  134. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_PATTERNS.md +1923 -0
  135. package/plan/001_d3bb02af4886/docs/research/CYCLE_DETECTION_QUICK_REF.md +319 -0
  136. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/codebase-context.md +115 -0
  137. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/cycle-detection-algorithms.md +134 -0
  138. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/test-patterns.md +153 -0
  139. package/plan/001_d3bb02af4886/docs/research/P1M1T2S1/workflow-class.md +132 -0
  140. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_BEST_PRACTICES.md +716 -0
  141. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/DECORATOR_DOCUMENTATION_QUICK_REF.md +186 -0
  142. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/GROUNDSWELL_DECORATOR_EXAMPLES.md +604 -0
  143. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/INDEX.md +213 -0
  144. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/codebase_structure.md +30 -0
  145. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/existing_test_pattern.md +56 -0
  146. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/getRootObservers_implementation.md +53 -0
  147. package/plan/001_d3bb02af4886/docs/research/P1M2T1S4/test_conventions.md +49 -0
  148. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/PRP.md +958 -0
  149. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/QUICK_REFERENCE.md +339 -0
  150. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/README.md +305 -0
  151. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/SUMMARY.md +433 -0
  152. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/bidirectional-tree-consistency-testing.md +1574 -0
  153. package/plan/001_d3bb02af4886/docs/research/P1M3T1S4/test-pattern-examples.md +1014 -0
  154. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_QUICK_REF.md +376 -0
  155. package/plan/001_d3bb02af4886/docs/research/PROMISE_ALLSETTLED_RESEARCH.md +1507 -0
  156. package/plan/001_d3bb02af4886/docs/research/bugfix_typescript_patterns.md +949 -0
  157. package/plan/001_d3bb02af4886/docs/research/error-testing-research.md +619 -0
  158. package/plan/001_d3bb02af4886/docs/research/error_handling_patterns.md +723 -0
  159. package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-security-guide.md +56 -0
  160. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/PRP_TEMPLATE.md +460 -0
  161. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/QUICK_REFERENCE.md +324 -0
  162. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/README.md +175 -0
  163. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/RESEARCH_REPORT.md +499 -0
  164. package/plan/001_d3bb02af4886/docs/research/incremental-tree-map-updates/SUMMARY.md +163 -0
  165. package/plan/bugfix/BUG_FIX_SUMMARY.md +961 -0
  166. package/src/__tests__/adversarial/attachChild-performance.test.ts +216 -0
  167. package/src/__tests__/adversarial/circular-reference.test.ts +101 -0
  168. package/src/__tests__/adversarial/complex-circular-reference.test.ts +139 -0
  169. package/src/__tests__/adversarial/concurrent-task-failures.test.ts +571 -0
  170. package/src/__tests__/adversarial/deep-analysis.test.ts +729 -0
  171. package/src/__tests__/adversarial/deep-hierarchy-stress.test.ts +213 -0
  172. package/src/__tests__/adversarial/e2e-prd-validation.test.ts +448 -0
  173. package/src/__tests__/adversarial/edge-case.test.ts +703 -0
  174. package/src/__tests__/adversarial/error-merge-strategy.test.ts +760 -0
  175. package/src/__tests__/adversarial/incremental-performance.test.ts +140 -0
  176. package/src/__tests__/adversarial/node-map-update-benchmarks.test.ts +457 -0
  177. package/src/__tests__/adversarial/observer-propagation.test.ts +487 -0
  178. package/src/__tests__/adversarial/parent-validation.test.ts +143 -0
  179. package/src/__tests__/adversarial/prd-12-2-compliance.test.ts +611 -0
  180. package/src/__tests__/adversarial/prd-compliance.test.ts +731 -0
  181. package/src/__tests__/compatibility/backward-compatibility.test.ts +1572 -0
  182. package/src/__tests__/helpers/index.ts +18 -0
  183. package/src/__tests__/helpers/tree-verification.ts +257 -0
  184. package/src/__tests__/integration/bidirectional-consistency.test.ts +847 -0
  185. package/src/__tests__/integration/observer-logging.test.ts +643 -0
  186. package/src/__tests__/integration/tree-mirroring.test.ts +37 -0
  187. package/src/__tests__/integration/workflow-reparenting.test.ts +303 -0
  188. package/src/__tests__/unit/context.test.ts +79 -0
  189. package/src/__tests__/unit/logger.test.ts +293 -0
  190. package/src/__tests__/unit/observable.test.ts +321 -0
  191. package/src/__tests__/unit/tree-debugger-incremental.test.ts +170 -0
  192. package/src/__tests__/unit/utils/workflow-error-utils.test.ts +209 -0
  193. package/src/__tests__/unit/workflow-detachChild.test.ts +100 -0
  194. package/src/__tests__/unit/workflow-emitEvent-childDetached.test.ts +153 -0
  195. package/src/__tests__/unit/workflow-isDescendantOf.test.ts +180 -0
  196. package/src/__tests__/unit/workflow.test.ts +277 -1
  197. package/src/core/agent.ts +21 -1
  198. package/src/core/logger.ts +27 -2
  199. package/src/core/workflow-context.ts +6 -4
  200. package/src/core/workflow.ts +252 -14
  201. package/src/debugger/tree-debugger.ts +52 -7
  202. package/src/decorators/task.ts +65 -2
  203. package/src/index.ts +4 -2
  204. package/src/types/decorators.ts +8 -1
  205. package/src/types/events.ts +1 -0
  206. package/src/utils/index.ts +1 -0
  207. package/src/utils/observable.ts +32 -3
  208. package/src/utils/workflow-error-utils.ts +56 -0
  209. package/tsconfig.json +1 -1
  210. package/llms_full.txt +0 -5890
  211. package/tasks.json +0 -0
  212. /package/plan/{backlog.json → 001_d3bb02af4886/backlog.json} +0 -0
  213. /package/plan/{P1P2/PRP.md → 001_d3bb02af4886/docs/PRP/P1P2-PRP.md} +0 -0
  214. /package/plan/{P3P4/PRP.md → 001_d3bb02af4886/docs/PRP/P3P4-PRP.md} +0 -0
  215. /package/plan/{P4P5/PRP.md → 001_d3bb02af4886/docs/PRP/P4P5-PRP.md} +0 -0
  216. /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/external_deps.md +0 -0
  217. /package/plan/{architecture → 001_d3bb02af4886/docs/architecture}/system_context.md +0 -0
  218. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_BEST_PRACTICES.md +0 -0
  219. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_CODE_PATTERNS.md +0 -0
  220. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_INTEGRATION_GUIDE.md +0 -0
  221. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/LRU_CACHE_RESEARCH_INDEX.md +0 -0
  222. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_INDEX.md +0 -0
  223. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/REFLECTION_RESEARCH_REPORT.md +0 -0
  224. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/RESEARCH_SUMMARY.md +0 -0
  225. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/anthropic-sdk.md +0 -0
  226. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/async-local-storage.md +0 -0
  227. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-code-patterns.md +0 -0
  228. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-decision-matrix.md +0 -0
  229. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-implementation-guide.md +0 -0
  230. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-integration-guide.md +0 -0
  231. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-patterns.md +0 -0
  232. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/reflection-quick-reference.md +0 -0
  233. /package/plan/{P1P2/research → 001_d3bb02af4886/docs/research/P1P2}/zod-schema.md +0 -0
  234. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/caching-lru.md +0 -0
  235. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/introspection-tools.md +0 -0
  236. /package/plan/{P3P4/research → 001_d3bb02af4886/docs/research/P3P4}/reflection-patterns.md +0 -0
  237. /package/plan/{P4P5/research → 001_d3bb02af4886/docs/research/P4P5}/RESEARCH_SUMMARY.md +0 -0
  238. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/INTROSPECTION_RESEARCH_SUMMARY.md +0 -0
  239. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/README-INTROSPECTION.md +0 -0
  240. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/agent-introspection-patterns.md +0 -0
  241. /package/plan/{research → 001_d3bb02af4886/docs/research/general}/introspection-tool-examples.md +0 -0
  242. /package/{PRPs/PRDs/001-hierarchical-workflow-engine.md → plan/001_d3bb02af4886/prd_snapshot.md} +0 -0
@@ -0,0 +1,1170 @@
1
+ # Error Logging Best Practices for TypeScript/JavaScript Applications
2
+
3
+ **Research Date:** 2026-01-12
4
+ **Focus Areas:** Observer pattern error handling, logger context propagation, structured logging patterns, TypeScript-specific considerations
5
+
6
+ ---
7
+
8
+ ## Table of Contents
9
+
10
+ 1. [Observer Pattern Error Handling Best Practices](#1-observer-pattern-error-handling-best-practices)
11
+ 2. [Logger Context Propagation Through Callback Chains](#2-logger-context-propagation-through-callback-chains)
12
+ 3. [Replacing console.error with Structured Logging](#3-replacing-consoleerror-with-structured-logging)
13
+ 4. [TypeScript-Specific Considerations](#4-typescript-specific-considerations)
14
+ 5. [Recommended Libraries and Tools](#5-recommended-libraries-and-tools)
15
+ 6. [Implementation Examples](#6-implementation-examples)
16
+
17
+ ---
18
+
19
+ ## 1. Observer Pattern Error Handling Best Practices
20
+
21
+ ### 1.1 Core Principles
22
+
23
+ **Error Isolation**
24
+ - Errors in one observer should not prevent other observers from receiving notifications
25
+ - Each observer callback should be wrapped in a try-catch block
26
+ - Failed observers should be logged but should not break the notification chain
27
+
28
+ **Fail-Safe Notification**
29
+ ```typescript
30
+ interface Observer<T> {
31
+ next(value: T): void | Promise<void>;
32
+ error(err: Error): void | Promise<void>;
33
+ complete(): void | Promise<void>;
34
+ }
35
+
36
+ class SafeObservable<T> {
37
+ private observers: Set<Observer<T>> = new Set();
38
+
39
+ subscribe(observer: Observer<T>): () => void {
40
+ this.observers.add(observer);
41
+ return () => this.observers.delete(observer);
42
+ }
43
+
44
+ notify(value: T): void {
45
+ this.observers.forEach(observer => {
46
+ try {
47
+ const result = observer.next(value);
48
+
49
+ // Handle async observers
50
+ if (result instanceof Promise) {
51
+ result.catch(err => {
52
+ this.handleObserverError(observer, err, value);
53
+ });
54
+ }
55
+ } catch (err) {
56
+ this.handleObserverError(observer, err, value);
57
+ }
58
+ });
59
+ }
60
+
61
+ private handleObserverError(
62
+ observer: Observer<T>,
63
+ err: unknown,
64
+ value: T
65
+ ): void {
66
+ const error = err instanceof Error ? err : new Error(String(err));
67
+
68
+ // Try to notify observer of error
69
+ try {
70
+ observer.error(error);
71
+ } catch (handlerError) {
72
+ // Last resort: log to fallback logger
73
+ console.error('Error in observer error handler:', handlerError);
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### 1.2 Error Handling Patterns
80
+
81
+ **Pattern 1: Safe Notification with Error Callback**
82
+ ```typescript
83
+ type SafeObserverCallback<T> = (value: T) => void | Promise<void>;
84
+ type ErrorHandler = (error: Error, observer: SafeObserverCallback<any>) => void;
85
+
86
+ class ErrorSafeObservable<T> {
87
+ private observers: Map<SafeObserverCallback<T>, ErrorHandler> = new Map();
88
+
89
+ subscribe(
90
+ onNext: SafeObserverCallback<T>,
91
+ onError?: ErrorHandler
92
+ ): () => void {
93
+ this.observers.set(onNext, onError || this.defaultErrorHandler);
94
+ return () => this.observers.delete(onNext);
95
+ }
96
+
97
+ notify(value: T): void {
98
+ this.observers.forEach((errorHandler, observer) => {
99
+ try {
100
+ const result = observer(value);
101
+ if (result instanceof Promise) {
102
+ result.catch(err => errorHandler(err, observer));
103
+ }
104
+ } catch (err) {
105
+ errorHandler(err, observer);
106
+ }
107
+ });
108
+ }
109
+
110
+ private defaultErrorHandler: ErrorHandler = (error, observer) => {
111
+ console.error('Observer callback error:', error);
112
+ };
113
+ }
114
+ ```
115
+
116
+ **Pattern 2: Error Aggregation**
117
+ ```typescript
118
+ interface ObserverError {
119
+ observer: string;
120
+ error: Error;
121
+ timestamp: Date;
122
+ value?: any;
123
+ }
124
+
125
+ class ObservableWithErrorAggregation<T> {
126
+ private observers: Set<Observer<T>> = new Set();
127
+ private errors: ObserverError[] = [];
128
+
129
+ notify(value: T): ObserverError[] {
130
+ this.errors = [];
131
+
132
+ this.observers.forEach(observer => {
133
+ try {
134
+ observer.next(value);
135
+ } catch (err) {
136
+ this.errors.push({
137
+ observer: observer.constructor.name || 'Anonymous',
138
+ error: err instanceof Error ? err : new Error(String(err)),
139
+ timestamp: new Date(),
140
+ value
141
+ });
142
+ }
143
+ });
144
+
145
+ return this.errors;
146
+ }
147
+
148
+ getErrors(): ObserverError[] {
149
+ return [...this.errors];
150
+ }
151
+ }
152
+ ```
153
+
154
+ ### 1.3 Best Practices for Observer Error Handling
155
+
156
+ 1. **Always wrap observer callbacks in try-catch**
157
+ - Prevents cascading failures
158
+ - Allows other observers to execute
159
+
160
+ 2. **Provide error feedback to observers**
161
+ - Implement the `error()` method on observers
162
+ - Pass errors back to the observer for handling
163
+
164
+ 3. **Log all observer errors**
165
+ - Use structured logging with context
166
+ - Include observer identity and value that caused error
167
+
168
+ 4. **Consider unsubscribing failed observers**
169
+ - Optional: Auto-unsubscribe after N errors
170
+ - Prevents repeated failures from same observer
171
+
172
+ 5. **Handle both sync and async observers**
173
+ - Check for Promise return values
174
+ - Attach catch handlers to async callbacks
175
+
176
+ ---
177
+
178
+ ## 2. Logger Context Propagation Through Callback Chains
179
+
180
+ ### 2.1 Context Propagation Patterns
181
+
182
+ **Pattern 1: AsyncLocalStorage (Node.js)**
183
+ ```typescript
184
+ import { AsyncLocalStorage } from 'async_hooks';
185
+
186
+ interface LogContext {
187
+ correlationId: string;
188
+ userId?: string;
189
+ requestId?: string;
190
+ operation?: string;
191
+ }
192
+
193
+ const contextStorage = new AsyncLocalStorage<LogContext>();
194
+
195
+ class ContextualLogger {
196
+ error(message: string, error?: Error): void {
197
+ const context = contextStorage.getStore();
198
+ console.error({
199
+ timestamp: new Date().toISOString(),
200
+ message,
201
+ error: error ? {
202
+ name: error.name,
203
+ message: error.message,
204
+ stack: error.stack
205
+ } : undefined,
206
+ ...context
207
+ });
208
+ }
209
+
210
+ info(message: string, metadata?: Record<string, any>): void {
211
+ const context = contextStorage.getStore();
212
+ console.info({
213
+ timestamp: new Date().toISOString(),
214
+ message,
215
+ ...metadata,
216
+ ...context
217
+ });
218
+ }
219
+ }
220
+
221
+ // Usage
222
+ const logger = new ContextualLogger();
223
+
224
+ async function withContext<T>(
225
+ context: LogContext,
226
+ fn: () => Promise<T>
227
+ ): Promise<T> {
228
+ return contextStorage.run(context, fn);
229
+ }
230
+
231
+ // Example: Context propagates through callback chain
232
+ async function processUser(userId: string) {
233
+ return withContext(
234
+ { correlationId: generateId(), userId, operation: 'processUser' },
235
+ async () => {
236
+ logger.info('Starting user processing');
237
+
238
+ // Context is preserved through all async operations
239
+ await processData();
240
+ await validateData();
241
+
242
+ logger.info('Completed user processing');
243
+ }
244
+ );
245
+ }
246
+ ```
247
+
248
+ **Pattern 2: Explicit Context Passing**
249
+ ```typescript
250
+ interface LoggerContext {
251
+ traceId: string;
252
+ component: string;
253
+ userId?: string;
254
+ }
255
+
256
+ type ContextualCallback<T> = (context: LoggerContext, data: T) => void;
257
+
258
+ class ContextAwareObservable<T> {
259
+ private baseContext: LoggerContext;
260
+ private observers: Set<ContextualCallback<T>> = new Set();
261
+
262
+ constructor(baseContext: LoggerContext) {
263
+ this.baseContext = baseContext;
264
+ }
265
+
266
+ subscribe(callback: ContextualCallback<T>): () => void {
267
+ this.observers.add(callback);
268
+ return () => this.observers.delete(callback);
269
+ }
270
+
271
+ notify(data: T): void {
272
+ const context = {
273
+ ...this.baseContext,
274
+ timestamp: new Date().toISOString()
275
+ };
276
+
277
+ this.observers.forEach(callback => {
278
+ try {
279
+ callback(context, data);
280
+ } catch (err) {
281
+ console.error('Observer error:', {
282
+ error: err instanceof Error ? err.message : String(err),
283
+ context
284
+ });
285
+ }
286
+ });
287
+ }
288
+ }
289
+
290
+ // Usage
291
+ const observable = new ContextAwareObservable({
292
+ traceId: 'trace-123',
293
+ component: 'UserService'
294
+ });
295
+
296
+ observable.subscribe((context, data) => {
297
+ console.log('Received data:', { context, data });
298
+ });
299
+ ```
300
+
301
+ **Pattern 3: Logger Factory Pattern**
302
+ ```typescript
303
+ class LoggerFactory {
304
+ private static baseContext: Record<string, any> = {};
305
+
306
+ static setBaseContext(context: Record<string, any>): void {
307
+ this.baseContext = { ...this.baseContext, ...context };
308
+ }
309
+
310
+ static createLogger(component: string): Logger {
311
+ return new Logger({
312
+ ...this.baseContext,
313
+ component
314
+ });
315
+ }
316
+
317
+ static withContext<T>(
318
+ context: Record<string, any>,
319
+ fn: () => T
320
+ ): T {
321
+ const originalContext = { ...this.baseContext };
322
+ this.baseContext = { ...this.baseContext, ...context };
323
+
324
+ try {
325
+ return fn();
326
+ } finally {
327
+ this.baseContext = originalContext;
328
+ }
329
+ }
330
+ }
331
+
332
+ class Logger {
333
+ constructor(private context: Record<string, any>) {}
334
+
335
+ error(message: string, error?: Error): void {
336
+ console.error({
337
+ timestamp: new Date().toISOString(),
338
+ level: 'error',
339
+ message,
340
+ ...(error && {
341
+ error: {
342
+ name: error.name,
343
+ message: error.message,
344
+ stack: error.stack
345
+ }
346
+ }),
347
+ ...this.context
348
+ });
349
+ }
350
+ }
351
+ ```
352
+
353
+ ### 2.2 Best Practices for Context Propagation
354
+
355
+ 1. **Use AsyncLocalStorage in Node.js**
356
+ - Automatic propagation through async boundaries
357
+ - No need to manually pass context
358
+ - Zero overhead for synchronous code
359
+
360
+ 2. **Include correlation/trace IDs**
361
+ - Track requests across service boundaries
362
+ - Enable distributed tracing
363
+ - Use UUIDs or similar unique identifiers
364
+
365
+ 3. **Make context immutable**
366
+ - Prevent accidental modifications
367
+ - Use Readonly types in TypeScript
368
+ - Create new context objects instead of mutating
369
+
370
+ 4. **Set context at entry points**
371
+ - HTTP request handlers
372
+ - Message queue consumers
373
+ - Scheduled job entry points
374
+
375
+ 5. **Beware of context loss**
376
+ - Some async operations lose context
377
+ - Be careful with setTimeout/setInterval
378
+ - Test context propagation thoroughly
379
+
380
+ ---
381
+
382
+ ## 3. Replacing console.error with Structured Logging
383
+
384
+ ### 3.1 Why Replace console.error?
385
+
386
+ **Limitations of console.error:**
387
+ - Inconsistent format across browsers/environments
388
+ - Difficult to parse and search in production
389
+ - No built-in log levels or filtering
390
+ - Lacks metadata/context attachment
391
+ - Not suitable for centralized logging
392
+
393
+ **Benefits of Structured Logging:**
394
+ - JSON format for easy parsing
395
+ - Searchable and queryable
396
+ - Consistent schema across application
397
+ - Support for log levels and filtering
398
+ - Integration with log aggregation tools
399
+ - Better debugging in production
400
+
401
+ ### 3.2 Structured Logging Libraries
402
+
403
+ **Winston (Industry Standard)**
404
+ ```typescript
405
+ import winston from 'winston';
406
+
407
+ const logger = winston.createLogger({
408
+ level: process.env.LOG_LEVEL || 'info',
409
+ format: winston.format.combine(
410
+ winston.format.timestamp({
411
+ format: 'YYYY-MM-DD HH:mm:ss'
412
+ }),
413
+ winston.format.errors({ stack: true }),
414
+ winston.format.json()
415
+ ),
416
+ defaultMeta: {
417
+ service: 'user-service',
418
+ environment: process.env.NODE_ENV
419
+ },
420
+ transports: [
421
+ new winston.transports.Console({
422
+ format: winston.format.combine(
423
+ winston.format.colorize(),
424
+ winston.format.simple()
425
+ )
426
+ }),
427
+ new winston.transports.File({
428
+ filename: 'error.log',
429
+ level: 'error'
430
+ }),
431
+ new winston.transports.File({
432
+ filename: 'combined.log'
433
+ })
434
+ ]
435
+ });
436
+
437
+ // Usage
438
+ logger.error('Failed to process user', {
439
+ userId: '12345',
440
+ error: error.message,
441
+ stack: error.stack,
442
+ operation: 'processUser'
443
+ });
444
+ ```
445
+
446
+ **Pino (High Performance)**
447
+ ```typescript
448
+ import pino from 'pino';
449
+
450
+ const logger = pino({
451
+ level: process.env.LOG_LEVEL || 'info',
452
+ formatters: {
453
+ level: (label) => {
454
+ return { level: label };
455
+ }
456
+ },
457
+ redact: ['password', 'token', 'secret'],
458
+ timestamp: pino.stdTimeFunctions.isoTime
459
+ });
460
+
461
+ // Usage
462
+ logger.error({
463
+ userId: '12345',
464
+ err: {
465
+ type: error.name,
466
+ message: error.message,
467
+ stack: error.stack
468
+ },
469
+ operation: 'processUser'
470
+ }, 'Failed to process user');
471
+ ```
472
+
473
+ **Roarr (Minimalist)**
474
+ ```typescript
475
+ import Logger from 'roarr';
476
+
477
+ const logger = new Logger();
478
+
479
+ logger.error({
480
+ userId: '12345',
481
+ error: {
482
+ message: error.message,
483
+ stack: error.stack
484
+ }
485
+ }, 'Failed to process user');
486
+ ```
487
+
488
+ ### 3.3 Migration Strategy
489
+
490
+ **Phase 1: Create Logging Abstraction**
491
+ ```typescript
492
+ interface ILogger {
493
+ error(message: string, error?: Error, context?: Record<string, any>): void;
494
+ warn(message: string, context?: Record<string, any>): void;
495
+ info(message: string, context?: Record<string, any>): void;
496
+ debug(message: string, context?: Record<string, any>): void;
497
+ }
498
+
499
+ // Create adapter for your chosen library
500
+ class LoggerAdapter implements ILogger {
501
+ constructor(private winston: winston.Logger) {}
502
+
503
+ error(message: string, error?: Error, context?: Record<string, any>): void {
504
+ this.winston.error(message, {
505
+ ...(error && {
506
+ error: {
507
+ name: error.name,
508
+ message: error.message,
509
+ stack: error.stack
510
+ }
511
+ }),
512
+ ...context
513
+ });
514
+ }
515
+
516
+ // ... other methods
517
+ }
518
+ ```
519
+
520
+ **Phase 2: Gradual Replacement**
521
+ ```typescript
522
+ // Before
523
+ console.error('Observer error:', error);
524
+
525
+ // After
526
+ logger.error('Observer error', error, {
527
+ component: 'Observable',
528
+ observer: observerName
529
+ });
530
+ ```
531
+
532
+ **Phase 3: Replace All Instances**
533
+ ```bash
534
+ # Find all console.error calls
535
+ grep -r "console\.error" src/
536
+
537
+ # Replace systematically
538
+ ```
539
+
540
+ ### 3.4 Structured Logging Best Practices
541
+
542
+ 1. **Use consistent field names**
543
+ - `timestamp` (ISO 8601 format)
544
+ - `level` (error, warn, info, debug)
545
+ - `message` (human-readable description)
546
+ - `error` (error details)
547
+ - `context` (additional metadata)
548
+
549
+ 2. **Include correlation IDs**
550
+ - Link related log entries
551
+ - Track requests across boundaries
552
+ - Enable distributed tracing
553
+
554
+ 3. **Sanitize sensitive data**
555
+ - Passwords, tokens, API keys
556
+ - Personal information (PII)
557
+ - Use redaction in logger configuration
558
+
559
+ 4. **Use appropriate log levels**
560
+ - `error`: Application errors requiring attention
561
+ - `warn`: Warning conditions not stopping execution
562
+ - `info`: General informational messages
563
+ - `debug`: Detailed diagnostic information
564
+
565
+ 5. **Structure error objects consistently**
566
+ ```typescript
567
+ {
568
+ error: {
569
+ type: 'DatabaseError',
570
+ message: 'Connection failed',
571
+ code: 'DB_CONN_001',
572
+ stack: '...',
573
+ context: {
574
+ host: 'localhost',
575
+ port: 5432
576
+ }
577
+ }
578
+ }
579
+ ```
580
+
581
+ ---
582
+
583
+ ## 4. TypeScript-Specific Considerations
584
+
585
+ ### 4.1 Type-Safe Error Handling
586
+
587
+ **Typed Error Classes**
588
+ ```typescript
589
+ abstract class AppError extends Error {
590
+ abstract readonly code: string;
591
+ abstract readonly statusCode: number;
592
+
593
+ constructor(
594
+ message: string,
595
+ public readonly context?: Record<string, any>
596
+ ) {
597
+ super(message);
598
+ this.name = this.constructor.name;
599
+ Error.captureStackTrace(this, this.constructor);
600
+ }
601
+ }
602
+
603
+ class ValidationError extends AppError {
604
+ readonly code = 'VALIDATION_ERROR';
605
+ readonly statusCode = 400;
606
+
607
+ constructor(
608
+ message: string,
609
+ public readonly validationErrors: Record<string, string[]>
610
+ ) {
611
+ super(message);
612
+ }
613
+ }
614
+
615
+ class DatabaseError extends AppError {
616
+ readonly code = 'DATABASE_ERROR';
617
+ readonly statusCode = 500;
618
+
619
+ constructor(
620
+ message: string,
621
+ public readonly originalError?: Error
622
+ ) {
623
+ super(message);
624
+ }
625
+ }
626
+ ```
627
+
628
+ **Type-Safe Observer Pattern**
629
+ ```typescript
630
+ type SafeObserverCallback<T, E extends Error = Error> = (
631
+ value: T
632
+ ) => void | Promise<void>;
633
+
634
+ type ErrorHandler<E extends Error = Error> = (
635
+ error: E
636
+ ) => void | Promise<void>;
637
+
638
+ interface StrictObserver<T, E extends Error = Error> {
639
+ next(value: T): void | Promise<void>;
640
+ error(error: E): void | Promise<void>;
641
+ complete(): void | Promise<void>;
642
+ }
643
+
644
+ class TypedObservable<T, E extends Error = Error> {
645
+ private observers: Set<StrictObserver<T, E>> = new Set();
646
+
647
+ subscribe(observer: StrictObserver<T, E>): () => void {
648
+ this.observers.add(observer);
649
+ return () => this.observers.delete(observer);
650
+ }
651
+
652
+ notify(value: T): void;
653
+ notify(error: E): void;
654
+ notify(value: T | E): void {
655
+ this.observers.forEach(observer => {
656
+ try {
657
+ if (value instanceof Error) {
658
+ observer.error(value as E);
659
+ } else {
660
+ observer.next(value);
661
+ }
662
+ } catch (err) {
663
+ console.error('Observer error:', err);
664
+ }
665
+ });
666
+ }
667
+ }
668
+ ```
669
+
670
+ ### 4.2 Type-Safe Logger
671
+
672
+ ```typescript
673
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
674
+
675
+ interface LogMetadata {
676
+ [key: string]: any;
677
+ }
678
+
679
+ interface LogEntry {
680
+ timestamp: string;
681
+ level: LogLevel;
682
+ message: string;
683
+ error?: {
684
+ name: string;
685
+ message: string;
686
+ stack?: string;
687
+ code?: string;
688
+ };
689
+ metadata?: LogMetadata;
690
+ }
691
+
692
+ class TypedLogger {
693
+ constructor(
694
+ private component: string,
695
+ private baseContext: LogMetadata = {}
696
+ ) {}
697
+
698
+ private log(level: LogLevel, message: string, entry: Partial<LogEntry> = {}): void {
699
+ const logEntry: LogEntry = {
700
+ timestamp: new Date().toISOString(),
701
+ level,
702
+ message,
703
+ ...entry,
704
+ metadata: {
705
+ component: this.component,
706
+ ...this.baseContext,
707
+ ...entry.metadata
708
+ }
709
+ };
710
+
711
+ console[level](JSON.stringify(logEntry));
712
+ }
713
+
714
+ error(message: string, error?: Error, metadata?: LogMetadata): void {
715
+ this.log('error', message, {
716
+ ...(error && {
717
+ error: {
718
+ name: error.name,
719
+ message: error.message,
720
+ stack: error.stack,
721
+ code: (error as any).code
722
+ }
723
+ }),
724
+ metadata
725
+ });
726
+ }
727
+
728
+ warn(message: string, metadata?: LogMetadata): void {
729
+ this.log('warn', message, { metadata });
730
+ }
731
+
732
+ info(message: string, metadata?: LogMetadata): void {
733
+ this.log('info', message, { metadata });
734
+ }
735
+
736
+ debug(message: string, metadata?: LogMetadata): void {
737
+ this.log('debug', message, { metadata });
738
+ }
739
+
740
+ withContext(context: LogMetadata): TypedLogger {
741
+ return new TypedLogger(this.component, {
742
+ ...this.baseContext,
743
+ ...context
744
+ });
745
+ }
746
+ }
747
+
748
+ // Usage
749
+ const logger = new TypedLogger('UserService');
750
+
751
+ logger.error('Failed to create user', error, {
752
+ userId: '12345',
753
+ email: 'user@example.com'
754
+ });
755
+
756
+ const userScopedLogger = logger.withContext({ userId: '12345' });
757
+ userScopedLogger.info('User profile updated');
758
+ ```
759
+
760
+ ### 4.3 Type Guards for Error Handling
761
+
762
+ ```typescript
763
+ function isError(error: unknown): error is Error {
764
+ return (
765
+ error instanceof Error ||
766
+ (typeof error === 'object' &&
767
+ error !== null &&
768
+ 'message' in error &&
769
+ typeof error.message === 'string')
770
+ );
771
+ }
772
+
773
+ function isAppError(error: unknown): error is AppError {
774
+ return isError(error) && error instanceof AppError;
775
+ }
776
+
777
+ function handleUnknownError(error: unknown): void {
778
+ if (isAppError(error)) {
779
+ logger.error('Application error', error, {
780
+ code: error.code,
781
+ context: error.context
782
+ });
783
+ } else if (isError(error)) {
784
+ logger.error('Unexpected error', error);
785
+ } else {
786
+ logger.error('Unknown error type', undefined, {
787
+ error: String(error)
788
+ });
789
+ }
790
+ }
791
+ ```
792
+
793
+ ### 4.4 TypeScript Best Practices
794
+
795
+ 1. **Use discriminated unions for error types**
796
+ ```typescript
797
+ type Result<T, E extends Error = Error> =
798
+ | { success: true; data: T }
799
+ | { success: false; error: E };
800
+ ```
801
+
802
+ 2. **Leverage utility types**
803
+ ```typescript
804
+ type ErrorContext<T extends Error> = {
805
+ [K in keyof T]?: T[K];
806
+ };
807
+ ```
808
+
809
+ 3. **Use readonly for context**
810
+ ```typescript
811
+ interface LogContext {
812
+ readonly correlationId: string;
813
+ readonly userId?: string;
814
+ }
815
+ ```
816
+
817
+ 4. **Enable strict error checking**
818
+ ```typescript
819
+ // tsconfig.json
820
+ {
821
+ "compilerOptions": {
822
+ "strictNullChecks": true,
823
+ "strictPropertyInitialization": true,
824
+ "noImplicitAny": true,
825
+ "useUnknownInCatchVariables": true
826
+ }
827
+ }
828
+ ```
829
+
830
+ 5. **Type-safe logger factories**
831
+ ```typescript
832
+ function createLogger(component: string): Logger {
833
+ return new TypedLogger(component);
834
+ }
835
+
836
+ // Ensure component names are valid
837
+ type ValidComponent =
838
+ | 'UserService'
839
+ | 'AuthService'
840
+ | 'DatabaseService';
841
+
842
+ function createComponentLogger(
843
+ component: ValidComponent
844
+ ): Logger {
845
+ return createLogger(component);
846
+ }
847
+ ```
848
+
849
+ ---
850
+
851
+ ## 5. Recommended Libraries and Tools
852
+
853
+ ### 5.1 Logging Libraries
854
+
855
+ | Library | Performance | Features | Best For |
856
+ |---------|-------------|----------|----------|
857
+ | **Winston** | Medium | Rich features, multiple transports | General-purpose applications |
858
+ | **Pino** | Very Fast | Minimal, high performance | High-throughput applications |
859
+ | **Bunyan** | Fast | JSON-first, extensible | Node.js applications |
860
+ | **log4js** | Medium | Flexible, multiple categories | Applications needing categories |
861
+ | **Roarr** | Fast | Minimalist, structured | Modern Node.js applications |
862
+
863
+ ### 5.2 Error Handling Libraries
864
+
865
+ | Library | Purpose | TypeScript Support |
866
+ |---------|---------|-------------------|
867
+ | **fp-ts** | Functional error handling | Excellent |
868
+ | **neverthrow** | Result type for error handling | Excellent |
869
+ | **ts-results** | Result/Option types | Excellent |
870
+ | **Vest** | Validation framework | Good |
871
+
872
+ ### 5.3 Observable/RxJS Libraries
873
+
874
+ | Library | Error Handling | TypeScript Support |
875
+ |---------|---------------|-------------------|
876
+ | **RxJS** | Comprehensive error operators | Excellent |
877
+ | **Zen-observable** | Basic observer pattern | Good |
878
+ | **Observable-Flyd** | Lightweight streams | Basic |
879
+
880
+ ---
881
+
882
+ ## 6. Implementation Examples
883
+
884
+ ### 6.1 Complete Observer with Structured Logging
885
+
886
+ ```typescript
887
+ import winston from 'winston';
888
+
889
+ // Setup logger
890
+ const logger = winston.createLogger({
891
+ level: 'info',
892
+ format: winston.format.combine(
893
+ winston.format.timestamp(),
894
+ winston.format.json()
895
+ ),
896
+ transports: [new winston.transports.Console()]
897
+ });
898
+
899
+ // Error types
900
+ class ObserverError extends Error {
901
+ constructor(
902
+ message: string,
903
+ public readonly observerName: string,
904
+ public readonly value?: any
905
+ ) {
906
+ super(message);
907
+ this.name = 'ObserverError';
908
+ }
909
+ }
910
+
911
+ // Observer interface with error handling
912
+ interface Observer<T> {
913
+ next(value: T): void | Promise<void>;
914
+ error(error: Error): void | Promise<void>;
915
+ complete(): void | Promise<void>;
916
+ }
917
+
918
+ // Observable with comprehensive error handling
919
+ class Observable<T> {
920
+ private observers: Map<string, Observer<T>> = new Map();
921
+ private errors: ObserverError[] = [];
922
+
923
+ subscribe(observer: Observer<T>, name: string): () => void {
924
+ this.observers.set(name, observer);
925
+ return () => this.observers.delete(name);
926
+ }
927
+
928
+ notify(value: T): void {
929
+ this.errors = [];
930
+
931
+ this.observers.forEach((observer, name) => {
932
+ try {
933
+ const result = observer.next(value);
934
+
935
+ if (result instanceof Promise) {
936
+ result.catch(err => {
937
+ this.handleError(name, err, value);
938
+ });
939
+ }
940
+ } catch (err) {
941
+ this.handleError(name, err, value);
942
+ }
943
+ });
944
+
945
+ // Log all errors
946
+ this.errors.forEach(err => {
947
+ logger.error('Observer callback failed', err, {
948
+ component: 'Observable',
949
+ observer: err.observerName,
950
+ value: err.value
951
+ });
952
+ });
953
+ }
954
+
955
+ private handleError(
956
+ observerName: string,
957
+ err: unknown,
958
+ value: T
959
+ ): void {
960
+ const error = err instanceof Error
961
+ ? err
962
+ : new Error(String(err));
963
+
964
+ const observerError = new ObserverError(
965
+ error.message,
966
+ observerName,
967
+ value
968
+ );
969
+
970
+ this.errors.push(observerError);
971
+
972
+ // Try to notify observer
973
+ const observer = this.observers.get(observerName);
974
+ if (observer) {
975
+ try {
976
+ observer.error(observerError);
977
+ } catch (handlerError) {
978
+ logger.error('Observer error handler failed', handlerError instanceof Error ? handlerError : undefined, {
979
+ component: 'Observable',
980
+ observer: observerName,
981
+ originalError: error.message
982
+ });
983
+ }
984
+ }
985
+ }
986
+ }
987
+
988
+ // Usage
989
+ const observable = new Observable<number>();
990
+
991
+ observable.subscribe(
992
+ {
993
+ next: (value) => {
994
+ console.log('Received:', value);
995
+ },
996
+ error: (error) => {
997
+ console.error('Error:', error.message);
998
+ },
999
+ complete: () => {
1000
+ console.log('Complete');
1001
+ }
1002
+ },
1003
+ 'ConsoleObserver'
1004
+ );
1005
+
1006
+ observable.notify(42);
1007
+ ```
1008
+
1009
+ ### 6.2 Logger with Context Propagation
1010
+
1011
+ ```typescript
1012
+ import { AsyncLocalStorage } from 'async_hooks';
1013
+ import winston from 'winston';
1014
+
1015
+ interface LogContext {
1016
+ traceId: string;
1017
+ userId?: string;
1018
+ operation?: string;
1019
+ }
1020
+
1021
+ class ContextualLogger {
1022
+ private static storage = new AsyncLocalStorage<LogContext>();
1023
+ private static baseLogger = winston.createLogger({
1024
+ level: 'info',
1025
+ format: winston.format.combine(
1026
+ winston.format.timestamp(),
1027
+ winston.format.json()
1028
+ ),
1029
+ transports: [new winston.transports.Console()]
1030
+ });
1031
+
1032
+ static runWithContext<T>(
1033
+ context: LogContext,
1034
+ fn: () => Promise<T>
1035
+ ): Promise<T> {
1036
+ return this.storage.run(context, fn);
1037
+ }
1038
+
1039
+ private static getContext(): LogContext {
1040
+ return this.storage.getStore() || { traceId: 'unknown' };
1041
+ }
1042
+
1043
+ static error(message: string, error?: Error): void {
1044
+ const context = this.getContext();
1045
+ this.baseLogger.error(message, {
1046
+ ...context,
1047
+ ...(error && {
1048
+ error: {
1049
+ name: error.name,
1050
+ message: error.message,
1051
+ stack: error.stack
1052
+ }
1053
+ })
1054
+ });
1055
+ }
1056
+
1057
+ static info(message: string, metadata?: Record<string, any>): void {
1058
+ const context = this.getContext();
1059
+ this.baseLogger.info(message, {
1060
+ ...context,
1061
+ ...metadata
1062
+ });
1063
+ }
1064
+ }
1065
+
1066
+ // Usage with observer pattern
1067
+ async function processWithObserver(data: any[]) {
1068
+ return ContextualLogger.runWithContext(
1069
+ { traceId: generateId(), operation: 'processData' },
1070
+ async () => {
1071
+ const observable = new Observable<any>();
1072
+
1073
+ observable.subscribe(
1074
+ {
1075
+ next: (value) => {
1076
+ ContextualLogger.info('Processing item', { itemId: value.id });
1077
+ // Process value
1078
+ },
1079
+ error: (error) => {
1080
+ ContextualLogger.error('Observer error', error);
1081
+ },
1082
+ complete: () => {
1083
+ ContextualLogger.info('Processing complete');
1084
+ }
1085
+ },
1086
+ 'ItemProcessor'
1087
+ );
1088
+
1089
+ for (const item of data) {
1090
+ observable.notify(item);
1091
+ }
1092
+ }
1093
+ );
1094
+ }
1095
+ ```
1096
+
1097
+ ---
1098
+
1099
+ ## Summary and Recommendations
1100
+
1101
+ ### Key Takeaways
1102
+
1103
+ 1. **Observer Pattern Error Handling**
1104
+ - Always wrap observer callbacks in try-catch
1105
+ - Isolate errors to prevent cascading failures
1106
+ - Provide error feedback through error() method
1107
+ - Support both sync and async observers
1108
+
1109
+ 2. **Context Propagation**
1110
+ - Use AsyncLocalStorage in Node.js for automatic propagation
1111
+ - Include correlation/trace IDs for distributed tracing
1112
+ - Make context immutable
1113
+ - Set context at application entry points
1114
+
1115
+ 3. **Structured Logging**
1116
+ - Replace console.error with a structured logging library
1117
+ - Use consistent field names and schemas
1118
+ - Include correlation IDs and metadata
1119
+ - Sanitize sensitive data
1120
+
1121
+ 4. **TypeScript-Specific Considerations**
1122
+ - Create typed error classes
1123
+ - Use type guards for error handling
1124
+ - Leverage utility types
1125
+ - Enable strict error checking in tsconfig
1126
+
1127
+ ### Implementation Roadmap
1128
+
1129
+ 1. **Phase 1: Setup Infrastructure**
1130
+ - Choose and install logging library (Winston or Pino recommended)
1131
+ - Create logger abstraction layer
1132
+ - Setup AsyncLocalStorage for context propagation
1133
+
1134
+ 2. **Phase 2: Create Error Types**
1135
+ - Define application error hierarchy
1136
+ - Create type-safe error classes
1137
+ - Implement error type guards
1138
+
1139
+ 3. **Phase 3: Migrate Observer Pattern**
1140
+ - Update observer interface with error handling
1141
+ - Implement safe notification with try-catch
1142
+ - Add structured logging to error handlers
1143
+
1144
+ 4. **Phase 4: Replace console.error**
1145
+ - Systematically find and replace console.error calls
1146
+ - Ensure all errors are logged with context
1147
+ - Add correlation IDs throughout application
1148
+
1149
+ 5. **Phase 5: Testing and Validation**
1150
+ - Test error isolation in observers
1151
+ - Verify context propagation
1152
+ - Validate log output structure
1153
+ - Performance testing
1154
+
1155
+ ### Additional Resources
1156
+
1157
+ **Documentation**
1158
+ - Winston: https://github.com/winstonjs/winston
1159
+ - Pino: https://getpino.io/
1160
+ - AsyncLocalStorage: https://nodejs.org/api/async_context.html
1161
+ - RxJS Error Handling: https://rxjs.dev/guide/error-handling
1162
+
1163
+ **Articles**
1164
+ - "The Twelve-Factor App - Logging": https://12factor.net/logs
1165
+ - "Structured Logging Best Practices": Various Medium/dev.to articles
1166
+ - "Observer Pattern in TypeScript": TypeScript documentation and patterns
1167
+
1168
+ ---
1169
+
1170
+ **Note:** Due to web search quota limitations (resets February 1, 2026), this research is based on established best practices and patterns. For the most current information and specific library documentation, please refer to the official documentation linked above.