@agent-native/core 0.114.8 → 0.114.10

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 (128) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +21 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +31 -3
  5. package/corpus/core/src/agent/engine/anthropic-engine.ts +20 -3
  6. package/corpus/core/src/agent/engine/builder-engine.ts +56 -9
  7. package/corpus/core/src/agent/engine/first-event-timeout.ts +64 -0
  8. package/corpus/core/src/client/AssistantChat.tsx +7 -3
  9. package/corpus/core/src/client/resources/ResourcesPanel.tsx +1 -1
  10. package/corpus/core/src/integrations/computer-supervision-store.ts +4 -4
  11. package/corpus/core/src/integrations/pending-tasks-store.ts +1 -1
  12. package/corpus/core/src/integrations/remote-commands-store.ts +5 -5
  13. package/corpus/core/src/integrations/remote-devices-store.ts +3 -3
  14. package/corpus/core/src/integrations/remote-push-store.ts +3 -3
  15. package/corpus/core/src/observability/traces.ts +38 -1
  16. package/corpus/core/src/server/action-routes.ts +23 -1
  17. package/corpus/core/src/server/http-response-telemetry.ts +6 -1
  18. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
  19. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  20. package/corpus/templates/analytics/actions/account-deep-dive.ts +41 -6
  21. package/corpus/templates/analytics/changelog/2026-07-20-account-deep-dives-finish-with-partial-data-when-hubspot-lo.md +6 -0
  22. package/corpus/templates/analytics/changelog/2026-07-20-dashboard-email-reports-now-include-an-image-when-a-single-p.md +6 -0
  23. package/corpus/templates/analytics/server/lib/dashboard-report.ts +11 -3
  24. package/corpus/templates/calendar/actions/create-event.ts +5 -0
  25. package/corpus/templates/calendar/app/components/ThemeToggle.tsx +4 -1
  26. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +0 -1
  27. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +309 -421
  28. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +349 -0
  29. package/corpus/templates/calendar/app/i18n-data.ts +110 -0
  30. package/corpus/templates/calendar/app/lib/event-form-utils.ts +6 -0
  31. package/corpus/templates/calendar/app/pages/CalendarView.tsx +3 -0
  32. package/corpus/templates/calendar/app/root.tsx +4 -2
  33. package/corpus/templates/calendar/changelog/2026-07-20-events-can-be-updated-inline-with-date-time-timezone-and-rep.md +6 -0
  34. package/corpus/templates/calendar/changelog/2026-07-20-public-booking-pages-no-longer-hydrate-with-a-theme-mismatch.md +6 -0
  35. package/corpus/templates/calendar/shared/api.ts +1 -0
  36. package/corpus/templates/clips/AGENTS.md +7 -0
  37. package/corpus/templates/clips/actions/create-recording.ts +51 -10
  38. package/corpus/templates/clips/actions/get-recording-player-data.ts +34 -5
  39. package/corpus/templates/clips/actions/lib/transcript-preview.ts +48 -0
  40. package/corpus/templates/clips/actions/list-recordings.ts +15 -4
  41. package/corpus/templates/clips/actions/regenerate-summary.ts +32 -0
  42. package/corpus/templates/clips/actions/search-recordings.ts +28 -6
  43. package/corpus/templates/clips/actions/view-screen.ts +54 -47
  44. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -5
  45. package/corpus/templates/clips/app/components/library/recording-card.tsx +29 -32
  46. package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +13 -0
  47. package/corpus/templates/clips/changelog/2026-07-20-agent-summaries-use-bounded-transcript-context.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-07-20-clip-summaries-now-finish-without-sending-a-long-transcript-.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-07-20-clips-agents-only-discover-recordings-you-own-or-have-alread.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-07-20-hosted-recordings-no-longer-start-with-an-impossible-buffered-upload.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-07-20-meeting-recordings-now-offer-a-cleaner-transcript-view-with-.md +6 -0
  52. package/corpus/templates/clips/changelog/2026-07-20-shared-clips-can-be-shared-with-limited-access-and-cards-sho.md +6 -0
  53. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +12 -8
  54. package/corpus/templates/clips/desktop/src/overlays/pill-logo.tsx +2 -15
  55. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +107 -340
  56. package/corpus/templates/clips/desktop/src/styles.css +27 -145
  57. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +6 -7
  58. package/corpus/templates/clips/server/lib/agent-recording-access.ts +73 -0
  59. package/corpus/templates/clips/server/plugins/agent-chat.ts +5 -2
  60. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +18 -0
  61. package/corpus/templates/plan/app/pages/PlansPage.tsx +10 -11
  62. package/corpus/templates/plan/changelog/2026-07-20-bridged-local-plans-now-load-comments-from-the-local-workspace.md +6 -0
  63. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  64. package/dist/agent/engine/ai-sdk-engine.js +27 -4
  65. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  66. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  67. package/dist/agent/engine/anthropic-engine.js +19 -4
  68. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  69. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  70. package/dist/agent/engine/builder-engine.js +40 -7
  71. package/dist/agent/engine/builder-engine.js.map +1 -1
  72. package/dist/agent/engine/first-event-timeout.d.ts +25 -0
  73. package/dist/agent/engine/first-event-timeout.d.ts.map +1 -0
  74. package/dist/agent/engine/first-event-timeout.js +49 -0
  75. package/dist/agent/engine/first-event-timeout.js.map +1 -0
  76. package/dist/client/AssistantChat.d.ts.map +1 -1
  77. package/dist/client/AssistantChat.js +7 -3
  78. package/dist/client/AssistantChat.js.map +1 -1
  79. package/dist/client/resources/ResourcesPanel.js +1 -1
  80. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  81. package/dist/collab/routes.d.ts +1 -1
  82. package/dist/collab/struct-routes.d.ts +1 -1
  83. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  84. package/dist/integrations/computer-supervision-store.js +4 -4
  85. package/dist/integrations/computer-supervision-store.js.map +1 -1
  86. package/dist/integrations/pending-tasks-store.js +1 -1
  87. package/dist/integrations/pending-tasks-store.js.map +1 -1
  88. package/dist/integrations/remote-commands-store.js +5 -5
  89. package/dist/integrations/remote-commands-store.js.map +1 -1
  90. package/dist/integrations/remote-devices-store.js +3 -3
  91. package/dist/integrations/remote-devices-store.js.map +1 -1
  92. package/dist/integrations/remote-push-store.js +3 -3
  93. package/dist/integrations/remote-push-store.js.map +1 -1
  94. package/dist/notifications/routes.d.ts +1 -1
  95. package/dist/observability/routes.d.ts +3 -3
  96. package/dist/observability/traces.d.ts.map +1 -1
  97. package/dist/observability/traces.js +23 -1
  98. package/dist/observability/traces.js.map +1 -1
  99. package/dist/progress/routes.d.ts +1 -1
  100. package/dist/resources/handlers.d.ts +1 -1
  101. package/dist/server/action-routes.d.ts.map +1 -1
  102. package/dist/server/action-routes.js +23 -1
  103. package/dist/server/action-routes.js.map +1 -1
  104. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  105. package/dist/server/http-response-telemetry.d.ts +2 -0
  106. package/dist/server/http-response-telemetry.d.ts.map +1 -1
  107. package/dist/server/http-response-telemetry.js +5 -1
  108. package/dist/server/http-response-telemetry.js.map +1 -1
  109. package/dist/server/transcribe-voice.d.ts +1 -1
  110. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
  111. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  112. package/package.json +2 -2
  113. package/src/agent/engine/ai-sdk-engine.ts +31 -3
  114. package/src/agent/engine/anthropic-engine.ts +20 -3
  115. package/src/agent/engine/builder-engine.ts +56 -9
  116. package/src/agent/engine/first-event-timeout.ts +64 -0
  117. package/src/client/AssistantChat.tsx +7 -3
  118. package/src/client/resources/ResourcesPanel.tsx +1 -1
  119. package/src/integrations/computer-supervision-store.ts +4 -4
  120. package/src/integrations/pending-tasks-store.ts +1 -1
  121. package/src/integrations/remote-commands-store.ts +5 -5
  122. package/src/integrations/remote-devices-store.ts +3 -3
  123. package/src/integrations/remote-push-store.ts +3 -3
  124. package/src/observability/traces.ts +38 -1
  125. package/src/server/action-routes.ts +23 -1
  126. package/src/server/http-response-telemetry.ts +6 -1
  127. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
  128. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"remote-devices-store.js","sourceRoot":"","sources":["../../src/integrations/remote-devices-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,OAAO,EACP,UAAU,EACV,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAQ5B,IAAI,YAAuC,CAAC;AAE5C,KAAK,UAAU,WAAW;IACxB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,CAAC,KAAK,IAAI,EAAE;YACzB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG;;;;;;;;;;;yBAWC,OAAO,EAAE;;uBAEX,OAAO,EAAE;uBACT,OAAO,EAAE;uBACT,OAAO,EAAE;;OAEzB,CAAC;YAEF,IAAI,UAAU,EAAE,EAAE,CAAC;gBACjB,0FAA0F;gBAC1F,MAAM,iBAAiB,CAAC,4BAA4B,EAAE,SAAS,CAAC,CAAC;gBACjE,MAAM,kBAAkB,CACtB,4BAA4B,EAC5B,UAAU,EACV,+EAA+E,CAChF,CAAC;gBACF,MAAM,kBAAkB,CACtB,4BAA4B,EAC5B,aAAa,EACb,kFAAkF,CACnF,CAAC;gBACF,MAAM,kBAAkB,CACtB,4BAA4B,EAC5B,WAAW,EACX,gFAAgF,CACjF,CAAC;gBACF,MAAM,kBAAkB,CACtB,4BAA4B,EAC5B,eAAe,EACf,oFAAoF,CACrF,CAAC;gBACF,MAAM,kBAAkB,CACtB,4BAA4B,EAC5B,YAAY,EACZ,8EAA8E,OAAO,EAAE,EAAE,CAC1F,CAAC;gBACF,MAAM,iBAAiB,CACrB,+BAA+B,EAC/B,kHAAkH,CACnH,CAAC;gBACF,MAAM,iBAAiB,CACrB,0BAA0B,EAC1B,wGAAwG,CACzG,CAAC;gBACF,OAAO;YACT,CAAC;YACD,sDAAsD;YACtD,MAAM,cAAc,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YACtD,MAAM,kBAAkB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAC7C,MAAM,kBAAkB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YAChD,MAAM,kBAAkB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAC9C,MAAM,kBAAkB,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YAClD,MAAM,kBAAkB,CAAC,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC;YAClD,MAAM,cAAc,CAAC,GAAG,EAAE,CACxB,MAAM,CAAC,OAAO,CACZ,kHAAkH,CACnH,CACF,CAAC;YACF,MAAM,cAAc,CAAC,GAAG,EAAE,CACxB,MAAM,CAAC,OAAO,CACZ,wGAAwG,CACzG,CACF,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACjB,sDAAsD;YACtD,YAAY,GAAG,SAAS,CAAC;YACzB,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,IAAY,EACZ,UAAkB;IAElB,MAAM,GAAG,GAAG,UAAU,EAAE;QACtB,CAAC,CAAC,mEAAmE,IAAI,IAAI,UAAU,EAAE;QACzF,CAAC,CAAC,qDAAqD,IAAI,IAAI,UAAU,EAAE,CAAC;IAC9E,IAAI,CAAC;QACH,MAAM,cAAc,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,sBAAsB,CAAC,GAAG,CAAC;YAAE,OAAO;QACxC,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAY;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAE,GAA0B,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,MAAM,CAAE,GAA6B,EAAE,OAAO,IAAI,GAAG,CAAC;SACnE,WAAW,EAAE;SACb,IAAI,EAAE,CAAC;IACV,OAAO,CACL,IAAI,KAAK,OAAO;QAChB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACnC,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,GAA4B;IAC/C,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAY;QACpB,UAAU,EAAE,GAAG,CAAC,WAAqB;QACrC,KAAK,EAAG,GAAG,CAAC,MAAwB,IAAI,IAAI;QAC5C,KAAK,EAAE,GAAG,CAAC,KAAe;QAC1B,QAAQ,EAAG,GAAG,CAAC,QAA0B,IAAI,IAAI;QACjD,UAAU,EAAG,GAAG,CAAC,WAA6B,IAAI,IAAI;QACtD,QAAQ,EAAG,GAAG,CAAC,SAA2B,IAAI,IAAI;QAClD,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAgC;QAC3E,eAAe,EAAE,GAAG,CAAC,iBAA2B;QAChD,UAAU,EACR,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,YAAsB,CAAC;QACtE,MAAM,EAAE,GAAG,CAAC,MAAgC;QAC5C,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAoB,CAAC;QAC3E,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC;QACtC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAoB;IACvD,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,MAAsC;IAEtC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACpD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACrD,OAAO,6BAA6B,CAAC,KAAK,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAQxC;IACC,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,EAAE,GAAG,iBAAiB,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,MAAM,KAAK,GAAG,OAAO,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;IACrC,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAErD,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE;;;wDAG+C;QACpD,IAAI,EAAE;YACJ,EAAE;YACF,KAAK,CAAC,UAAU;YAChB,KAAK,CAAC,KAAK,IAAI,IAAI;YACnB,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,eAAe;YACrC,sBAAsB,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC1C,sBAAsB,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC;YAC7C,sBAAsB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC;YAC3C,6BAA6B,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC7C,SAAS;YACT,GAAG;YACH,QAAQ;YACR,IAAI;YACJ,GAAG;YACH,GAAG;SACJ;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC5D,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,EAAU;IAEV,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;QACzC,GAAG,EAAE,+DAA+D;QACpE,IAAI,EAAE,CAAC,EAAE,CAAC;KACX,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAA4B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAI7C;IACC,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;QACzC,GAAG,EAAE;;;;kBAIS;QACd,IAAI,EAAE;YACJ,KAAK,CAAC,EAAE;YACR,KAAK,CAAC,UAAU;YAChB,KAAK,CAAC,KAAK,IAAI,IAAI;YACnB,KAAK,CAAC,KAAK,IAAI,IAAI;SACpB;KACF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAA4B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAK/C;IACC,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,GAA2B,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACxD,IAAI,KAAK,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;YACzC,GAAG,EAAE;mCACwB,YAAY;;oBAE3B;YACd,IAAI;SACL,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAA8B,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,IAAI,GAAkC;QAC1C,KAAK,CAAC,UAAU;QAChB,KAAK,CAAC,KAAK,IAAI,IAAI;QACnB,KAAK,CAAC,KAAK,IAAI,IAAI;KACpB,CAAC;IACF,IAAI,KAAK,CAAC,MAAM;QAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;QACzC,GAAG,EAAE;;gEAEuD,YAAY;;kBAE1D;QACd,IAAI;KACL,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAA8B,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,QAAmC;IAEnC,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE;;kBAES;QACd,IAAI,EAAE,CAAC,SAAS,CAAC;KAClB,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAA4B,CAAC,CAAC;IAC/D,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE;;uBAEc;QACnB,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAO/C;IACC,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAkC,EAAE,CAAC;IAC/C,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,eAAe,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAE3D,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACzB,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;QACxB,GAAG,EAAE;gBACO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;6CACW;QACzC,IAAI;KACL,CAAC,CAAC;IACH,OAAO,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,KAIhD;IACC,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;QACxB,GAAG,EAAE;;;;;;+DAMsD;QAC3D,IAAI,EAAE;YACJ,GAAG;YACH,GAAG;YACH,KAAK,CAAC,EAAE;YACR,KAAK,CAAC,UAAU;YAChB,KAAK,CAAC,KAAK,IAAI,IAAI;YACnB,KAAK,CAAC,KAAK,IAAI,IAAI;SACpB;KACF,CAAC,CAAC;IACH,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,EAAU;IACrD,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;QACvC,GAAG,EAAE;;;;6CAIoC;QACzC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;KACrB,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,YAAY,IAAK,MAAc,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAa;IACvD,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACvE,OAAO,UAAU,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAgC,EAChC,GAAW;IAEX,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAED,SAAS,SAAS,CAAC,KAAc,EAAE,QAAiB;IAClD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,QAAQ,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,6BAA6B,CACpC,QAAiD;IAEjD,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,MAAM,UAAU,GAAyB,EAAE,GAAG,QAAQ,EAAE,CAAC;IACzD,IAAI,QAAQ,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;QAChD,UAAU,CAAC,oBAAoB,GAAG,6BAA6B,CAC7D,QAAQ,CAAC,oBAAoB,CAC9B,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,GAAG,MAAM,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,6BAA6B,CACpC,KAAiC;IAEjC,MAAM,MAAM,GAA+B,EAAE,CAAC;IAC9C,IAAI,KAAK,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,CAAC,OAAO,GAAG;YACf,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI;YACvC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI;YACvC,QAAQ,EAAE,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;YAC7D,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SAC5D,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,CAAC,OAAO,GAAG;YACf,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI;YACvC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI;YACvC,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,aAAa,KAAK,IAAI;YACnD,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,aAAa,KAAK,IAAI;YACnD,QAAQ,EAAE,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;YAC7D,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SAC5D,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,MAAM,GAAG,KAAK,IAAI,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,SAAS,CAAC,UAAkB;IACnC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;IACzC,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,KAAiB;IACnC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;SACrB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SACjD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC","sourcesContent":["import {\n getDbExec,\n intType,\n isPostgres,\n retryOnDdlRace,\n} from \"../db/client.js\";\nimport {\n ensureColumnExists,\n ensureIndexExists,\n ensureTableExists,\n} from \"../db/ddl-guard.js\";\nimport type {\n PublicRemoteDevice,\n RemoteComputerCapabilities,\n RemoteDevice,\n RemoteDeviceMetadata,\n} from \"./remote-types.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createSql = `\n CREATE TABLE IF NOT EXISTS integration_remote_devices (\n id TEXT PRIMARY KEY,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n label TEXT NOT NULL,\n platform TEXT,\n app_version TEXT,\n host_name TEXT,\n metadata_json TEXT,\n device_token_hash TEXT NOT NULL,\n last_seen_at ${intType()},\n status TEXT NOT NULL,\n revoked_at ${intType()},\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n `;\n\n if (isPostgres()) {\n // PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout\n await ensureTableExists(\"integration_remote_devices\", createSql);\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"platform\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS platform TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"app_version\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS app_version TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"host_name\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS host_name TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"metadata_json\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS metadata_json TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"revoked_at\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS revoked_at ${intType()}`,\n );\n await ensureIndexExists(\n \"idx_remote_devices_token_hash\",\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_devices_token_hash ON integration_remote_devices(device_token_hash)`,\n );\n await ensureIndexExists(\n \"idx_remote_devices_owner\",\n `CREATE INDEX IF NOT EXISTS idx_remote_devices_owner ON integration_remote_devices(owner_email, org_id)`,\n );\n return;\n }\n // SQLite (local dev): keep existing behavior verbatim\n await retryOnDdlRace(() => client.execute(createSql));\n await addColumnIfMissing(\"platform\", \"TEXT\");\n await addColumnIfMissing(\"app_version\", \"TEXT\");\n await addColumnIfMissing(\"host_name\", \"TEXT\");\n await addColumnIfMissing(\"metadata_json\", \"TEXT\");\n await addColumnIfMissing(\"revoked_at\", intType());\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_devices_token_hash ON integration_remote_devices(device_token_hash)`,\n ),\n );\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_devices_owner ON integration_remote_devices(owner_email, org_id)`,\n ),\n );\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nasync function addColumnIfMissing(\n name: string,\n definition: string,\n): Promise<void> {\n const sql = isPostgres()\n ? `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS ${name} ${definition}`\n : `ALTER TABLE integration_remote_devices ADD COLUMN ${name} ${definition}`;\n try {\n await retryOnDdlRace(() => getDbExec().execute(sql));\n } catch (err) {\n if (isDuplicateColumnError(err)) return;\n throw err;\n }\n}\n\nfunction isDuplicateColumnError(err: unknown): boolean {\n const code = String((err as { code?: unknown })?.code ?? \"\");\n const message = String((err as { message?: unknown })?.message ?? err)\n .toLowerCase()\n .trim();\n return (\n code === \"42701\" ||\n message.includes(\"duplicate column\") ||\n message.includes(\"already exists\")\n );\n}\n\nfunction rowToDevice(row: Record<string, unknown>): RemoteDevice {\n return {\n id: row.id as string,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n label: row.label as string,\n platform: (row.platform as string | null) ?? null,\n appVersion: (row.app_version as string | null) ?? null,\n hostName: (row.host_name as string | null) ?? null,\n metadata: parseJson(row.metadata_json, null) as RemoteDeviceMetadata | null,\n deviceTokenHash: row.device_token_hash as string,\n lastSeenAt:\n row.last_seen_at == null ? null : Number(row.last_seen_at as number),\n status: row.status as RemoteDevice[\"status\"],\n revokedAt: row.revoked_at == null ? null : Number(row.revoked_at as number),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nexport function toPublicRemoteDevice(device: RemoteDevice): PublicRemoteDevice {\n return {\n id: device.id,\n ownerEmail: device.ownerEmail,\n orgId: device.orgId,\n label: device.label,\n platform: device.platform,\n appVersion: device.appVersion,\n hostName: device.hostName,\n metadata: device.metadata,\n lastSeenAt: device.lastSeenAt,\n status: device.status,\n revokedAt: device.revokedAt,\n createdAt: device.createdAt,\n updatedAt: device.updatedAt,\n };\n}\n\nexport function getRemoteComputerCapabilities(\n device: Pick<RemoteDevice, \"metadata\">,\n): RemoteComputerCapabilities | null {\n const value = device.metadata?.computerCapabilities;\n if (!value || typeof value !== \"object\") return null;\n return normalizeComputerCapabilities(value);\n}\n\nexport async function createRemoteDevice(input: {\n ownerEmail: string;\n orgId?: string | null;\n label: string;\n platform?: string | null;\n appVersion?: string | null;\n hostName?: string | null;\n metadata?: RemoteDeviceMetadata | null;\n}): Promise<{ device: RemoteDevice; token: string }> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const id = `remote-device-${now}-${randomHex(8)}`;\n const token = `anr_${randomHex(32)}`;\n const tokenHash = await hashRemoteDeviceToken(token);\n\n await client.execute({\n sql: `INSERT INTO integration_remote_devices\n (id, owner_email, org_id, label, platform, app_version, host_name, metadata_json,\n device_token_hash, last_seen_at, status, revoked_at, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n input.ownerEmail,\n input.orgId ?? null,\n input.label.trim() || \"Remote device\",\n sanitizeOptionalString(input.platform, 80),\n sanitizeOptionalString(input.appVersion, 120),\n sanitizeOptionalString(input.hostName, 200),\n serializeRemoteDeviceMetadata(input.metadata),\n tokenHash,\n now,\n \"active\",\n null,\n now,\n now,\n ],\n });\n\n const device = await getRemoteDevice(id);\n if (!device) throw new Error(\"remote device insert failed\");\n return { device, token };\n}\n\nexport async function getRemoteDevice(\n id: string,\n): Promise<RemoteDevice | null> {\n await ensureTable();\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices WHERE id = ? LIMIT 1`,\n args: [id],\n });\n return rows[0] ? rowToDevice(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function getRemoteDeviceForOwner(input: {\n id: string;\n ownerEmail: string;\n orgId?: string | null;\n}): Promise<RemoteDevice | null> {\n await ensureTable();\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE id = ?\n AND owner_email = ?\n AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)\n LIMIT 1`,\n args: [\n input.id,\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ],\n });\n return rows[0] ? rowToDevice(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function listRemoteDevicesForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n status?: RemoteDevice[\"status\"];\n limit?: number;\n}): Promise<RemoteDevice[]> {\n await ensureTable();\n const limit = Math.max(1, Math.min(input.limit ?? 50, 100));\n const statusClause = input.status ? \" AND status = ?\" : \"\";\n if (!Object.prototype.hasOwnProperty.call(input, \"orgId\")) {\n const args: Array<string | number> = [input.ownerEmail];\n if (input.status) args.push(input.status);\n args.push(limit);\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE owner_email = ?${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args,\n });\n return rows.map((row) => rowToDevice(row as Record<string, unknown>));\n }\n const args: Array<string | number | null> = [\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ];\n if (input.status) args.push(input.status);\n args.push(limit);\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE owner_email = ?\n AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args,\n });\n return rows.map((row) => rowToDevice(row as Record<string, unknown>));\n}\n\nexport async function authenticateRemoteDeviceToken(\n rawToken: string | null | undefined,\n): Promise<RemoteDevice | null> {\n if (!rawToken) return null;\n await ensureTable();\n const tokenHash = await hashRemoteDeviceToken(rawToken);\n const now = Date.now();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE device_token_hash = ? AND status = 'active'\n LIMIT 1`,\n args: [tokenHash],\n });\n if (!rows[0]) return null;\n const device = rowToDevice(rows[0] as Record<string, unknown>);\n await client.execute({\n sql: `UPDATE integration_remote_devices\n SET last_seen_at = ?, updated_at = ?\n WHERE id = ?`,\n args: [now, now, device.id],\n });\n return { ...device, lastSeenAt: now, updatedAt: now };\n}\n\nexport async function updateRemoteDeviceDetails(input: {\n id: string;\n label?: string | null;\n platform?: string | null;\n appVersion?: string | null;\n hostName?: string | null;\n metadata?: RemoteDeviceMetadata | null;\n}): Promise<RemoteDevice | null> {\n await ensureTable();\n const now = Date.now();\n const updates: string[] = [];\n const args: Array<string | number | null> = [];\n if (input.label !== undefined) {\n updates.push(\"label = ?\");\n args.push(sanitizeOptionalString(input.label, 200) ?? \"Remote device\");\n }\n if (input.platform !== undefined) {\n updates.push(\"platform = ?\");\n args.push(sanitizeOptionalString(input.platform, 80));\n }\n if (input.appVersion !== undefined) {\n updates.push(\"app_version = ?\");\n args.push(sanitizeOptionalString(input.appVersion, 120));\n }\n if (input.hostName !== undefined) {\n updates.push(\"host_name = ?\");\n args.push(sanitizeOptionalString(input.hostName, 200));\n }\n if (input.metadata !== undefined) {\n updates.push(\"metadata_json = ?\");\n args.push(serializeRemoteDeviceMetadata(input.metadata));\n }\n if (updates.length === 0) return getRemoteDevice(input.id);\n\n updates.push(\"updated_at = ?\");\n args.push(now, input.id);\n await getDbExec().execute({\n sql: `UPDATE integration_remote_devices\n SET ${updates.join(\", \")}\n WHERE id = ? AND status = 'active'`,\n args,\n });\n return getRemoteDevice(input.id);\n}\n\nexport async function revokeRemoteDeviceForOwner(input: {\n id: string;\n ownerEmail: string;\n orgId?: string | null;\n}): Promise<RemoteDevice | null> {\n await ensureTable();\n const now = Date.now();\n await getDbExec().execute({\n sql: `UPDATE integration_remote_devices\n SET status = 'inactive',\n revoked_at = COALESCE(revoked_at, ?),\n updated_at = ?\n WHERE id = ?\n AND owner_email = ?\n AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)`,\n args: [\n now,\n now,\n input.id,\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ],\n });\n return getRemoteDeviceForOwner(input);\n}\n\nexport async function unregisterRemoteDevice(id: string): Promise<boolean> {\n await ensureTable();\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_devices\n SET status = 'inactive',\n revoked_at = COALESCE(revoked_at, ?),\n updated_at = ?\n WHERE id = ? AND status = 'active'`,\n args: [now, now, id],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) > 0;\n}\n\nexport async function hashRemoteDeviceToken(token: string): Promise<string> {\n const bytes = new TextEncoder().encode(token);\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return bytesToHex(new Uint8Array(digest));\n}\n\nfunction sanitizeOptionalString(\n value: string | null | undefined,\n max: number,\n): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, max) : null;\n}\n\nfunction parseJson(value: unknown, fallback: unknown): unknown {\n if (value == null) return fallback;\n try {\n return JSON.parse(String(value));\n } catch {\n return fallback;\n }\n}\n\nfunction serializeRemoteDeviceMetadata(\n metadata: RemoteDeviceMetadata | null | undefined,\n): string | null {\n if (!metadata) return null;\n const normalized: RemoteDeviceMetadata = { ...metadata };\n if (metadata.computerCapabilities !== undefined) {\n normalized.computerCapabilities = normalizeComputerCapabilities(\n metadata.computerCapabilities,\n );\n }\n const json = JSON.stringify(normalized);\n if (new TextEncoder().encode(json).byteLength > 32_768) {\n throw new Error(\"Remote device metadata exceeds 32 KiB\");\n }\n if (/\"data:[^\"]*\"/i.test(json) || looksLikeLargeBase64(json)) {\n throw new Error(\"Remote device metadata cannot contain binary payloads\");\n }\n return json;\n}\n\nfunction normalizeComputerCapabilities(\n value: RemoteComputerCapabilities,\n): RemoteComputerCapabilities {\n const result: RemoteComputerCapabilities = {};\n if (value.browser && typeof value.browser === \"object\") {\n result.browser = {\n observe: value.browser.observe === true,\n control: value.browser.control === true,\n provider: sanitizeOptionalString(value.browser.provider, 120),\n version: sanitizeOptionalString(value.browser.version, 120),\n };\n }\n if (value.desktop && typeof value.desktop === \"object\") {\n result.desktop = {\n observe: value.desktop.observe === true,\n control: value.desktop.control === true,\n accessibility: value.desktop.accessibility === true,\n screenCapture: value.desktop.screenCapture === true,\n provider: sanitizeOptionalString(value.desktop.provider, 120),\n version: sanitizeOptionalString(value.desktop.version, 120),\n };\n }\n return result;\n}\n\nfunction looksLikeLargeBase64(value: string): boolean {\n return value.length > 4_096 && /[A-Za-z0-9+/]{4_096,}={0,2}/.test(value);\n}\n\nfunction randomHex(byteLength: number): string {\n const bytes = new Uint8Array(byteLength);\n globalThis.crypto.getRandomValues(bytes);\n return bytesToHex(bytes);\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n"]}
1
+ {"version":3,"file":"remote-devices-store.js","sourceRoot":"","sources":["../../src/integrations/remote-devices-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getDbExec,\n intType,\n isPostgres,\n retryOnDdlRace,\n} from \"../db/client.js\";\nimport {\n ensureColumnExists,\n ensureIndexExists,\n ensureTableExists,\n} from \"../db/ddl-guard.js\";\nimport type {\n PublicRemoteDevice,\n RemoteComputerCapabilities,\n RemoteDevice,\n RemoteDeviceMetadata,\n} from \"./remote-types.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createSql = `\n CREATE TABLE IF NOT EXISTS integration_remote_devices (\n id TEXT PRIMARY KEY,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n label TEXT NOT NULL,\n platform TEXT,\n app_version TEXT,\n host_name TEXT,\n metadata_json TEXT,\n device_token_hash TEXT NOT NULL,\n last_seen_at ${intType()},\n status TEXT NOT NULL,\n revoked_at ${intType()},\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n `;\n\n if (isPostgres()) {\n // PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout\n await ensureTableExists(\"integration_remote_devices\", createSql);\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"platform\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS platform TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"app_version\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS app_version TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"host_name\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS host_name TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"metadata_json\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS metadata_json TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_devices\",\n \"revoked_at\",\n `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS revoked_at ${intType()}`,\n );\n await ensureIndexExists(\n \"idx_remote_devices_token_hash\",\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_devices_token_hash ON integration_remote_devices(device_token_hash)`,\n );\n await ensureIndexExists(\n \"idx_remote_devices_owner\",\n `CREATE INDEX IF NOT EXISTS idx_remote_devices_owner ON integration_remote_devices(owner_email, org_id)`,\n );\n return;\n }\n // SQLite (local dev): keep existing behavior verbatim\n await retryOnDdlRace(() => client.execute(createSql));\n await addColumnIfMissing(\"platform\", \"TEXT\");\n await addColumnIfMissing(\"app_version\", \"TEXT\");\n await addColumnIfMissing(\"host_name\", \"TEXT\");\n await addColumnIfMissing(\"metadata_json\", \"TEXT\");\n await addColumnIfMissing(\"revoked_at\", intType());\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_devices_token_hash ON integration_remote_devices(device_token_hash)`,\n ),\n );\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_devices_owner ON integration_remote_devices(owner_email, org_id)`,\n ),\n );\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nasync function addColumnIfMissing(\n name: string,\n definition: string,\n): Promise<void> {\n const sql = isPostgres()\n ? `ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS ${name} ${definition}`\n : `ALTER TABLE integration_remote_devices ADD COLUMN ${name} ${definition}`;\n try {\n await retryOnDdlRace(() => getDbExec().execute(sql));\n } catch (err) {\n if (isDuplicateColumnError(err)) return;\n throw err;\n }\n}\n\nfunction isDuplicateColumnError(err: unknown): boolean {\n const code = String((err as { code?: unknown })?.code ?? \"\");\n const message = String((err as { message?: unknown })?.message ?? err)\n .toLowerCase()\n .trim();\n return (\n code === \"42701\" ||\n message.includes(\"duplicate column\") ||\n message.includes(\"already exists\")\n );\n}\n\nfunction rowToDevice(row: Record<string, unknown>): RemoteDevice {\n return {\n id: row.id as string,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n label: row.label as string,\n platform: (row.platform as string | null) ?? null,\n appVersion: (row.app_version as string | null) ?? null,\n hostName: (row.host_name as string | null) ?? null,\n metadata: parseJson(row.metadata_json, null) as RemoteDeviceMetadata | null,\n deviceTokenHash: row.device_token_hash as string,\n lastSeenAt:\n row.last_seen_at == null ? null : Number(row.last_seen_at as number),\n status: row.status as RemoteDevice[\"status\"],\n revokedAt: row.revoked_at == null ? null : Number(row.revoked_at as number),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nexport function toPublicRemoteDevice(device: RemoteDevice): PublicRemoteDevice {\n return {\n id: device.id,\n ownerEmail: device.ownerEmail,\n orgId: device.orgId,\n label: device.label,\n platform: device.platform,\n appVersion: device.appVersion,\n hostName: device.hostName,\n metadata: device.metadata,\n lastSeenAt: device.lastSeenAt,\n status: device.status,\n revokedAt: device.revokedAt,\n createdAt: device.createdAt,\n updatedAt: device.updatedAt,\n };\n}\n\nexport function getRemoteComputerCapabilities(\n device: Pick<RemoteDevice, \"metadata\">,\n): RemoteComputerCapabilities | null {\n const value = device.metadata?.computerCapabilities;\n if (!value || typeof value !== \"object\") return null;\n return normalizeComputerCapabilities(value);\n}\n\nexport async function createRemoteDevice(input: {\n ownerEmail: string;\n orgId?: string | null;\n label: string;\n platform?: string | null;\n appVersion?: string | null;\n hostName?: string | null;\n metadata?: RemoteDeviceMetadata | null;\n}): Promise<{ device: RemoteDevice; token: string }> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const id = `remote-device-${now}-${randomHex(8)}`;\n const token = `anr_${randomHex(32)}`;\n const tokenHash = await hashRemoteDeviceToken(token);\n\n await client.execute({\n sql: `INSERT INTO integration_remote_devices\n (id, owner_email, org_id, label, platform, app_version, host_name, metadata_json,\n device_token_hash, last_seen_at, status, revoked_at, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n input.ownerEmail,\n input.orgId ?? null,\n input.label.trim() || \"Remote device\",\n sanitizeOptionalString(input.platform, 80),\n sanitizeOptionalString(input.appVersion, 120),\n sanitizeOptionalString(input.hostName, 200),\n serializeRemoteDeviceMetadata(input.metadata),\n tokenHash,\n now,\n \"active\",\n null,\n now,\n now,\n ],\n });\n\n const device = await getRemoteDevice(id);\n if (!device) throw new Error(\"remote device insert failed\");\n return { device, token };\n}\n\nexport async function getRemoteDevice(\n id: string,\n): Promise<RemoteDevice | null> {\n await ensureTable();\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices WHERE id = ? LIMIT 1`,\n args: [id],\n });\n return rows[0] ? rowToDevice(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function getRemoteDeviceForOwner(input: {\n id: string;\n ownerEmail: string;\n orgId?: string | null;\n}): Promise<RemoteDevice | null> {\n await ensureTable();\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE id = ?\n AND owner_email = ?\n AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)\n LIMIT 1`,\n args: [\n input.id,\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ],\n });\n return rows[0] ? rowToDevice(rows[0] as Record<string, unknown>) : null;\n}\n\nexport async function listRemoteDevicesForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n status?: RemoteDevice[\"status\"];\n limit?: number;\n}): Promise<RemoteDevice[]> {\n await ensureTable();\n const limit = Math.max(1, Math.min(input.limit ?? 50, 100));\n const statusClause = input.status ? \" AND status = ?\" : \"\";\n if (!Object.prototype.hasOwnProperty.call(input, \"orgId\")) {\n const args: Array<string | number> = [input.ownerEmail];\n if (input.status) args.push(input.status);\n args.push(limit);\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE owner_email = ?${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args,\n });\n return rows.map((row) => rowToDevice(row as Record<string, unknown>));\n }\n const args: Array<string | number | null> = [\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ];\n if (input.status) args.push(input.status);\n args.push(limit);\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE owner_email = ?\n AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args,\n });\n return rows.map((row) => rowToDevice(row as Record<string, unknown>));\n}\n\nexport async function authenticateRemoteDeviceToken(\n rawToken: string | null | undefined,\n): Promise<RemoteDevice | null> {\n if (!rawToken) return null;\n await ensureTable();\n const tokenHash = await hashRemoteDeviceToken(rawToken);\n const now = Date.now();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM integration_remote_devices\n WHERE device_token_hash = ? AND status = 'active'\n LIMIT 1`,\n args: [tokenHash],\n });\n if (!rows[0]) return null;\n const device = rowToDevice(rows[0] as Record<string, unknown>);\n await client.execute({\n sql: `UPDATE integration_remote_devices\n SET last_seen_at = ?, updated_at = ?\n WHERE id = ?`,\n args: [now, now, device.id],\n });\n return { ...device, lastSeenAt: now, updatedAt: now };\n}\n\nexport async function updateRemoteDeviceDetails(input: {\n id: string;\n label?: string | null;\n platform?: string | null;\n appVersion?: string | null;\n hostName?: string | null;\n metadata?: RemoteDeviceMetadata | null;\n}): Promise<RemoteDevice | null> {\n await ensureTable();\n const now = Date.now();\n const updates: string[] = [];\n const args: Array<string | number | null> = [];\n if (input.label !== undefined) {\n updates.push(\"label = ?\");\n args.push(sanitizeOptionalString(input.label, 200) ?? \"Remote device\");\n }\n if (input.platform !== undefined) {\n updates.push(\"platform = ?\");\n args.push(sanitizeOptionalString(input.platform, 80));\n }\n if (input.appVersion !== undefined) {\n updates.push(\"app_version = ?\");\n args.push(sanitizeOptionalString(input.appVersion, 120));\n }\n if (input.hostName !== undefined) {\n updates.push(\"host_name = ?\");\n args.push(sanitizeOptionalString(input.hostName, 200));\n }\n if (input.metadata !== undefined) {\n updates.push(\"metadata_json = ?\");\n args.push(serializeRemoteDeviceMetadata(input.metadata));\n }\n if (updates.length === 0) return getRemoteDevice(input.id);\n\n updates.push(\"updated_at = ?\");\n args.push(now, input.id);\n await getDbExec().execute({\n sql: `UPDATE integration_remote_devices\n SET ${updates.join(\", \")}\n WHERE id = ? AND status = 'active'`,\n args,\n });\n return getRemoteDevice(input.id);\n}\n\nexport async function revokeRemoteDeviceForOwner(input: {\n id: string;\n ownerEmail: string;\n orgId?: string | null;\n}): Promise<RemoteDevice | null> {\n await ensureTable();\n const now = Date.now();\n await getDbExec().execute({\n sql: `UPDATE integration_remote_devices\n SET status = 'inactive',\n revoked_at = COALESCE(revoked_at, ?),\n updated_at = ?\n WHERE id = ?\n AND owner_email = ?\n AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)`,\n args: [\n now,\n now,\n input.id,\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ],\n });\n return getRemoteDeviceForOwner(input);\n}\n\nexport async function unregisterRemoteDevice(id: string): Promise<boolean> {\n await ensureTable();\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_devices\n SET status = 'inactive',\n revoked_at = COALESCE(revoked_at, ?),\n updated_at = ?\n WHERE id = ? AND status = 'active'`,\n args: [now, now, id],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) > 0;\n}\n\nexport async function hashRemoteDeviceToken(token: string): Promise<string> {\n const bytes = new TextEncoder().encode(token);\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return bytesToHex(new Uint8Array(digest));\n}\n\nfunction sanitizeOptionalString(\n value: string | null | undefined,\n max: number,\n): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, max) : null;\n}\n\nfunction parseJson(value: unknown, fallback: unknown): unknown {\n if (value == null) return fallback;\n try {\n return JSON.parse(String(value));\n } catch {\n return fallback;\n }\n}\n\nfunction serializeRemoteDeviceMetadata(\n metadata: RemoteDeviceMetadata | null | undefined,\n): string | null {\n if (!metadata) return null;\n const normalized: RemoteDeviceMetadata = { ...metadata };\n if (metadata.computerCapabilities !== undefined) {\n normalized.computerCapabilities = normalizeComputerCapabilities(\n metadata.computerCapabilities,\n );\n }\n const json = JSON.stringify(normalized);\n if (new TextEncoder().encode(json).byteLength > 32_768) {\n throw new Error(\"Remote device metadata exceeds 32 KiB\");\n }\n if (/\"data:[^\"]*\"/i.test(json) || looksLikeLargeBase64(json)) {\n throw new Error(\"Remote device metadata cannot contain binary payloads\");\n }\n return json;\n}\n\nfunction normalizeComputerCapabilities(\n value: RemoteComputerCapabilities,\n): RemoteComputerCapabilities {\n const result: RemoteComputerCapabilities = {};\n if (value.browser && typeof value.browser === \"object\") {\n result.browser = {\n observe: value.browser.observe === true,\n control: value.browser.control === true,\n provider: sanitizeOptionalString(value.browser.provider, 120),\n version: sanitizeOptionalString(value.browser.version, 120),\n };\n }\n if (value.desktop && typeof value.desktop === \"object\") {\n result.desktop = {\n observe: value.desktop.observe === true,\n control: value.desktop.control === true,\n accessibility: value.desktop.accessibility === true,\n screenCapture: value.desktop.screenCapture === true,\n provider: sanitizeOptionalString(value.desktop.provider, 120),\n version: sanitizeOptionalString(value.desktop.version, 120),\n };\n }\n return result;\n}\n\nfunction looksLikeLargeBase64(value: string): boolean {\n return value.length > 4_096 && /[A-Za-z0-9+/]{4_096,}={0,2}/.test(value);\n}\n\nfunction randomHex(byteLength: number): string {\n const bytes = new Uint8Array(byteLength);\n globalThis.crypto.getRandomValues(bytes);\n return bytesToHex(bytes);\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n"]}
@@ -226,7 +226,7 @@ export async function listRemotePushRegistrationsForOwner(input) {
226
226
  const { rows } = await getDbExec().execute({
227
227
  sql: `SELECT * FROM integration_remote_push_registrations
228
228
  WHERE owner_email = ?
229
- AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)${statusClause}
229
+ AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)${statusClause}
230
230
  ORDER BY COALESCE(last_seen_at, updated_at) DESC
231
231
  LIMIT ?`,
232
232
  args: [input.ownerEmail, input.orgId ?? null, input.orgId ?? null, limit],
@@ -243,7 +243,7 @@ export async function unregisterRemotePushRegistrationForOwner(input) {
243
243
  sql: `UPDATE integration_remote_push_registrations
244
244
  SET status = 'inactive', updated_at = ?
245
245
  WHERE owner_email = ?
246
- AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)
246
+ AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)
247
247
  AND (${input.id ? "id = ?" : "0 = 1"} OR ${tokenHash ? "token_hash = ?" : "0 = 1"})`,
248
248
  args: [
249
249
  now,
@@ -309,7 +309,7 @@ export async function listRemotePushNotificationsForOwner(input) {
309
309
  const { rows } = await getDbExec().execute({
310
310
  sql: `SELECT * FROM integration_remote_push_notifications
311
311
  WHERE owner_email = ?
312
- AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)${statusClause}
312
+ AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)${statusClause}
313
313
  ORDER BY created_at DESC
314
314
  LIMIT ?`,
315
315
  args,
@@ -1 +1 @@
1
- {"version":3,"file":"remote-push-store.js","sourceRoot":"","sources":["../../src/integrations/remote-push-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getDbExec,\n isPostgres,\n intType,\n retryOnDdlRace,\n} from \"../db/client.js\";\nimport {\n ensureColumnExists,\n ensureIndexExists,\n ensureTableExists,\n} from \"../db/ddl-guard.js\";\nimport { isDuplicateColumnError } from \"../db/migrations.js\";\nimport type {\n PublicRemotePushRegistration,\n RemotePushNotification,\n RemotePushRegistration,\n} from \"./remote-types.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\n// Build the CREATE SQL lazily (not at module scope) so intType() runs at\n// RUNTIME, not import time — a module-scope call breaks any consumer whose\n// db/client mock doesn't stub intType (e.g. db-admin specs).\nfunction buildCreateRegistrationsSql(): string {\n return `\n CREATE TABLE IF NOT EXISTS integration_remote_push_registrations (\n id TEXT PRIMARY KEY,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n provider TEXT NOT NULL,\n platform TEXT,\n client_device_id TEXT,\n label TEXT,\n token TEXT NOT NULL,\n token_hash TEXT NOT NULL,\n status TEXT NOT NULL,\n last_seen_at ${intType()},\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n`;\n}\n\nfunction buildCreateNotificationsSql(): string {\n return `\n CREATE TABLE IF NOT EXISTS integration_remote_push_notifications (\n id TEXT PRIMARY KEY,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n registration_id TEXT NOT NULL,\n payload_json TEXT NOT NULL,\n status TEXT NOT NULL,\n attempts ${intType()} NOT NULL DEFAULT 0,\n provider_ticket_id TEXT,\n next_attempt_at ${intType()} NOT NULL DEFAULT 0,\n last_error TEXT,\n delivered_at ${intType()},\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n`;\n}\n\nasync function ensureTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createRegistrationsSql = buildCreateRegistrationsSql();\n const createNotificationsSql = buildCreateNotificationsSql();\n if (isPostgres()) {\n // PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout\n await ensureTableExists(\n \"integration_remote_push_registrations\",\n createRegistrationsSql,\n );\n await ensureIndexExists(\n \"idx_remote_push_token_hash\",\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_push_token_hash ON integration_remote_push_registrations(token_hash)`,\n );\n await ensureIndexExists(\n \"idx_remote_push_owner\",\n `CREATE INDEX IF NOT EXISTS idx_remote_push_owner ON integration_remote_push_registrations(owner_email, org_id, status)`,\n );\n await ensureTableExists(\n \"integration_remote_push_notifications\",\n createNotificationsSql,\n );\n await ensureIndexExists(\n \"idx_remote_push_notifications_owner\",\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_owner ON integration_remote_push_notifications(owner_email, org_id, status, created_at)`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"provider_ticket_id\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS provider_ticket_id TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"next_attempt_at\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS next_attempt_at ${intType()} NOT NULL DEFAULT 0`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"last_error\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS last_error TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"delivered_at\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS delivered_at ${intType()}`,\n );\n await ensureIndexExists(\n \"idx_remote_push_notifications_delivery\",\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_delivery ON integration_remote_push_notifications(status, next_attempt_at, updated_at)`,\n );\n return;\n }\n // SQLite (local dev): keep existing behavior\n await retryOnDdlRace(() => client.execute(createRegistrationsSql));\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_push_token_hash ON integration_remote_push_registrations(token_hash)`,\n ),\n );\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_push_owner ON integration_remote_push_registrations(owner_email, org_id, status)`,\n ),\n );\n\n await retryOnDdlRace(() => client.execute(createNotificationsSql));\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_owner ON integration_remote_push_notifications(owner_email, org_id, status, created_at)`,\n ),\n );\n await addNotificationColumnIfMissing(\"provider_ticket_id\", \"TEXT\");\n await addNotificationColumnIfMissing(\n \"next_attempt_at\",\n `${intType()} NOT NULL DEFAULT 0`,\n );\n await addNotificationColumnIfMissing(\"last_error\", \"TEXT\");\n await addNotificationColumnIfMissing(\"delivered_at\", intType());\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_delivery ON integration_remote_push_notifications(status, next_attempt_at, updated_at)`,\n ),\n );\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nasync function addNotificationColumnIfMissing(\n name: string,\n definition: string,\n): Promise<void> {\n try {\n await retryOnDdlRace(() =>\n getDbExec().execute(\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN ${name} ${definition}`,\n ),\n );\n } catch (error) {\n if (!isDuplicateColumnError(error)) throw error;\n }\n}\n\nfunction rowToRegistration(\n row: Record<string, unknown>,\n): RemotePushRegistration {\n return {\n id: row.id as string,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n provider: row.provider as string,\n platform: (row.platform as string | null) ?? null,\n clientDeviceId: (row.client_device_id as string | null) ?? null,\n label: (row.label as string | null) ?? null,\n token: row.token as string,\n tokenHash: row.token_hash as string,\n status: row.status as RemotePushRegistration[\"status\"],\n lastSeenAt:\n row.last_seen_at == null ? null : Number(row.last_seen_at as number),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nfunction rowToNotification(\n row: Record<string, unknown>,\n): RemotePushNotification {\n const storedStatus = String(row.status ?? \"pending\");\n const status =\n storedStatus === \"delivered\" || storedStatus === \"failed\"\n ? storedStatus\n : \"pending\";\n return {\n id: row.id as string,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n registrationId: row.registration_id as string,\n payload: parseJson(row.payload_json, null),\n status,\n attempts: Number(row.attempts ?? 0),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nexport function toPublicRemotePushRegistration(\n registration: RemotePushRegistration,\n): PublicRemotePushRegistration {\n return {\n id: registration.id,\n ownerEmail: registration.ownerEmail,\n orgId: registration.orgId,\n provider: registration.provider,\n platform: registration.platform,\n clientDeviceId: registration.clientDeviceId,\n label: registration.label,\n status: registration.status,\n lastSeenAt: registration.lastSeenAt,\n createdAt: registration.createdAt,\n updatedAt: registration.updatedAt,\n };\n}\n\nexport async function upsertRemotePushRegistration(input: {\n ownerEmail: string;\n orgId?: string | null;\n provider: string;\n token: string;\n platform?: string | null;\n clientDeviceId?: string | null;\n label?: string | null;\n}): Promise<RemotePushRegistration> {\n await ensureTables();\n const client = getDbExec();\n const now = Date.now();\n const tokenHash = await hashToken(input.token);\n const provider = sanitizeString(input.provider, 80) ?? \"unknown\";\n const platform = sanitizeString(input.platform, 80);\n const clientDeviceId = sanitizeString(input.clientDeviceId, 200);\n const label = sanitizeString(input.label, 200);\n\n const existing = await getRemotePushRegistrationByTokenHash(tokenHash);\n if (existing) {\n await client.execute({\n sql: `UPDATE integration_remote_push_registrations\n SET owner_email = ?,\n org_id = ?,\n provider = ?,\n platform = ?,\n client_device_id = ?,\n label = ?,\n token = ?,\n status = 'active',\n last_seen_at = ?,\n updated_at = ?\n WHERE token_hash = ?`,\n args: [\n input.ownerEmail,\n input.orgId ?? null,\n provider,\n platform,\n clientDeviceId,\n label,\n input.token,\n now,\n now,\n tokenHash,\n ],\n });\n const updated = await getRemotePushRegistrationByTokenHash(tokenHash);\n if (!updated) throw new Error(\"remote push registration update failed\");\n return updated;\n }\n\n const id = `remote-push-${now}-${randomHex(8)}`;\n await client.execute({\n sql: `INSERT INTO integration_remote_push_registrations\n (id, owner_email, org_id, provider, platform, client_device_id, label,\n token, token_hash, status, last_seen_at, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n input.ownerEmail,\n input.orgId ?? null,\n provider,\n platform,\n clientDeviceId,\n label,\n input.token,\n tokenHash,\n \"active\",\n now,\n now,\n now,\n ],\n });\n const registration = await getRemotePushRegistrationByTokenHash(tokenHash);\n if (!registration) throw new Error(\"remote push registration insert failed\");\n return registration;\n}\n\nexport async function listRemotePushRegistrationsForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n includeInactive?: boolean;\n limit?: number;\n}): Promise<RemotePushRegistration[]> {\n await ensureTables();\n const limit = Math.max(1, Math.min(input.limit ?? 50, 100));\n const statusClause = input.includeInactive ? \"\" : \" AND status = 'active'\";\n if (!Object.prototype.hasOwnProperty.call(input, \"orgId\")) {\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_registrations\n WHERE owner_email = ?${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args: [input.ownerEmail, limit],\n });\n return rows.map((row) => rowToRegistration(row as Record<string, unknown>));\n }\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_registrations\n WHERE owner_email = ?\n AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args: [input.ownerEmail, input.orgId ?? null, input.orgId ?? null, limit],\n });\n return rows.map((row) => rowToRegistration(row as Record<string, unknown>));\n}\n\nexport async function unregisterRemotePushRegistrationForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n id?: string | null;\n token?: string | null;\n}): Promise<boolean> {\n await ensureTables();\n const tokenHash = input.token ? await hashToken(input.token) : null;\n if (!input.id && !tokenHash) return false;\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_registrations\n SET status = 'inactive', updated_at = ?\n WHERE owner_email = ?\n AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)\n AND (${input.id ? \"id = ?\" : \"0 = 1\"} OR ${\n tokenHash ? \"token_hash = ?\" : \"0 = 1\"\n })`,\n args: [\n now,\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ...(input.id ? [input.id] : []),\n ...(tokenHash ? [tokenHash] : []),\n ],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) > 0;\n}\n\nexport async function queueRemotePushNotifications(input: {\n ownerEmail: string;\n orgId?: string | null;\n payload: unknown;\n}): Promise<{ queued: number }> {\n await ensureTables();\n const registrations = await listRemotePushRegistrationsForOwner({\n ownerEmail: input.ownerEmail,\n orgId: input.orgId ?? null,\n limit: 100,\n });\n if (registrations.length === 0) return { queued: 0 };\n\n const client = getDbExec();\n const now = Date.now();\n const payload = JSON.stringify(input.payload ?? null);\n const values = registrations.map(\n () => \"(?, ?, ?, ?, ?, 'pending', 0, ?, ?, ?)\",\n );\n const args = registrations.flatMap((registration) => [\n `remote-push-notification-${now}-${randomHex(8)}`,\n input.ownerEmail,\n input.orgId ?? null,\n registration.id,\n payload,\n now,\n now,\n now,\n ]);\n const result = await client.execute({\n sql: `INSERT INTO integration_remote_push_notifications\n (id, owner_email, org_id, registration_id, payload_json, status,\n attempts, next_attempt_at, created_at, updated_at)\n VALUES ${values.join(\", \")}`,\n args,\n });\n return {\n queued: result.rowsAffected ?? (result as any).rowCount ?? 0,\n };\n}\n\nexport async function listRemotePushNotificationsForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n status?: RemotePushNotification[\"status\"];\n limit?: number;\n}): Promise<RemotePushNotification[]> {\n await ensureTables();\n const limit = Math.max(1, Math.min(input.limit ?? 50, 100));\n const statusClause = input.status\n ? input.status === \"pending\"\n ? \" AND status IN ('pending', 'sending', 'sent', 'checking')\"\n : \" AND status = ?\"\n : \"\";\n const args: Array<string | number | null> = [\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ];\n if (input.status && input.status !== \"pending\") args.push(input.status);\n args.push(limit);\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_notifications\n WHERE owner_email = ?\n AND ((org_id IS NULL AND ? IS NULL) OR org_id = ?)${statusClause}\n ORDER BY created_at DESC\n LIMIT ?`,\n args,\n });\n return rows.map((row) => rowToNotification(row as Record<string, unknown>));\n}\n\nexport interface ClaimedRemotePushDelivery {\n id: string;\n registrationId: string;\n provider: string;\n token: string;\n payload: unknown;\n phase: \"send\" | \"receipt\";\n providerTicketId: string | null;\n attempts: number;\n}\n\nexport async function claimNextRemotePushDelivery(input?: {\n now?: number;\n staleAfterMs?: number;\n}): Promise<ClaimedRemotePushDelivery | null> {\n await ensureTables();\n const client = getDbExec();\n const now = input?.now ?? Date.now();\n const staleBefore = now - Math.max(30_000, input?.staleAfterMs ?? 120_000);\n const { rows } = await client.execute({\n sql: `SELECT n.id, n.registration_id, n.payload_json, n.status, n.attempts,\n n.provider_ticket_id, n.updated_at, r.provider, r.token\n FROM integration_remote_push_notifications n\n INNER JOIN integration_remote_push_registrations r\n ON r.id = n.registration_id\n WHERE r.status = 'active'\n AND (\n (n.status IN ('pending', 'sent') AND n.next_attempt_at <= ?)\n OR (n.status IN ('sending', 'checking') AND n.updated_at <= ?)\n )\n ORDER BY n.created_at ASC\n LIMIT 1`,\n args: [now, staleBefore],\n });\n const row = rows[0] as Record<string, unknown> | undefined;\n if (!row) return null;\n\n const previousStatus = String(row.status ?? \"pending\");\n const providerTicketId = sanitizeString(\n row.provider_ticket_id as string | null,\n 200,\n );\n const phase =\n (previousStatus === \"sent\" || previousStatus === \"checking\") &&\n providerTicketId\n ? \"receipt\"\n : \"send\";\n const claimedStatus = phase === \"receipt\" ? \"checking\" : \"sending\";\n const result = await client.execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ? AND status = ? AND updated_at = ?`,\n args: [\n claimedStatus,\n now,\n row.id as string,\n previousStatus,\n Number(row.updated_at),\n ],\n });\n if ((result.rowsAffected ?? (result as any).rowCount ?? 0) !== 1) return null;\n\n return {\n id: row.id as string,\n registrationId: row.registration_id as string,\n provider: String(row.provider ?? \"unknown\"),\n token: row.token as string,\n payload: parseJson(row.payload_json, null),\n phase,\n providerTicketId,\n attempts: Number(row.attempts ?? 0) + 1,\n };\n}\n\nexport async function markRemotePushTicketAccepted(input: {\n id: string;\n providerTicketId: string;\n checkAfter: number;\n}): Promise<boolean> {\n await ensureTables();\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'sent', provider_ticket_id = ?, next_attempt_at = ?,\n last_error = NULL, updated_at = ?\n WHERE id = ? AND status = 'sending'`,\n args: [input.providerTicketId, input.checkAfter, now, input.id],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function markRemotePushDelivered(id: string): Promise<boolean> {\n await ensureTables();\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'delivered', last_error = NULL, delivered_at = ?,\n updated_at = ?\n WHERE id = ? AND status = 'checking'`,\n args: [now, now, id],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function retryRemotePushDelivery(input: {\n id: string;\n phase: \"send\" | \"receipt\";\n retryAt: number;\n errorCode: string;\n resend?: boolean;\n}): Promise<boolean> {\n await ensureTables();\n const currentStatus = input.phase === \"receipt\" ? \"checking\" : \"sending\";\n const retryStatus =\n input.phase === \"receipt\" && !input.resend ? \"sent\" : \"pending\";\n const clearTicketClause = input.resend ? \", provider_ticket_id = NULL\" : \"\";\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = ?, next_attempt_at = ?, last_error = ?${clearTicketClause},\n updated_at = ?\n WHERE id = ? AND status = ?`,\n args: [\n retryStatus,\n input.retryAt,\n sanitizeString(input.errorCode, 160) ?? \"temporary_error\",\n Date.now(),\n input.id,\n currentStatus,\n ],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function failRemotePushDelivery(input: {\n id: string;\n phase: \"send\" | \"receipt\";\n errorCode: string;\n}): Promise<boolean> {\n await ensureTables();\n const currentStatus = input.phase === \"receipt\" ? \"checking\" : \"sending\";\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'failed', last_error = ?, updated_at = ?\n WHERE id = ? AND status = ?`,\n args: [\n sanitizeString(input.errorCode, 160) ?? \"delivery_failed\",\n Date.now(),\n input.id,\n currentStatus,\n ],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function deactivateRemotePushRegistration(\n registrationId: string,\n): Promise<boolean> {\n await ensureTables();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: `UPDATE integration_remote_push_registrations\n SET status = 'inactive', updated_at = ?\n WHERE id = ? AND status = 'active'`,\n args: [now, registrationId],\n });\n await client.execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'failed', last_error = 'registration_inactive',\n updated_at = ?\n WHERE registration_id = ?\n AND status IN ('pending', 'sending', 'sent', 'checking')`,\n args: [now, registrationId],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nasync function getRemotePushRegistrationByTokenHash(\n tokenHash: string,\n): Promise<RemotePushRegistration | null> {\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_registrations\n WHERE token_hash = ?\n LIMIT 1`,\n args: [tokenHash],\n });\n return rows[0] ? rowToRegistration(rows[0] as Record<string, unknown>) : null;\n}\n\nasync function hashToken(token: string): Promise<string> {\n const bytes = new TextEncoder().encode(token);\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(digest))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction randomHex(byteLength: number): string {\n const bytes = new Uint8Array(byteLength);\n globalThis.crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction sanitizeString(\n value: string | null | undefined,\n max: number,\n): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, max) : null;\n}\n\nfunction parseJson(value: unknown, fallback: unknown): unknown {\n if (value == null) return fallback;\n try {\n return JSON.parse(String(value));\n } catch {\n return fallback;\n }\n}\n"]}
1
+ {"version":3,"file":"remote-push-store.js","sourceRoot":"","sources":["../../src/integrations/remote-push-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getDbExec,\n isPostgres,\n intType,\n retryOnDdlRace,\n} from \"../db/client.js\";\nimport {\n ensureColumnExists,\n ensureIndexExists,\n ensureTableExists,\n} from \"../db/ddl-guard.js\";\nimport { isDuplicateColumnError } from \"../db/migrations.js\";\nimport type {\n PublicRemotePushRegistration,\n RemotePushNotification,\n RemotePushRegistration,\n} from \"./remote-types.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\n// Build the CREATE SQL lazily (not at module scope) so intType() runs at\n// RUNTIME, not import time — a module-scope call breaks any consumer whose\n// db/client mock doesn't stub intType (e.g. db-admin specs).\nfunction buildCreateRegistrationsSql(): string {\n return `\n CREATE TABLE IF NOT EXISTS integration_remote_push_registrations (\n id TEXT PRIMARY KEY,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n provider TEXT NOT NULL,\n platform TEXT,\n client_device_id TEXT,\n label TEXT,\n token TEXT NOT NULL,\n token_hash TEXT NOT NULL,\n status TEXT NOT NULL,\n last_seen_at ${intType()},\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n`;\n}\n\nfunction buildCreateNotificationsSql(): string {\n return `\n CREATE TABLE IF NOT EXISTS integration_remote_push_notifications (\n id TEXT PRIMARY KEY,\n owner_email TEXT NOT NULL,\n org_id TEXT,\n registration_id TEXT NOT NULL,\n payload_json TEXT NOT NULL,\n status TEXT NOT NULL,\n attempts ${intType()} NOT NULL DEFAULT 0,\n provider_ticket_id TEXT,\n next_attempt_at ${intType()} NOT NULL DEFAULT 0,\n last_error TEXT,\n delivered_at ${intType()},\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n`;\n}\n\nasync function ensureTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createRegistrationsSql = buildCreateRegistrationsSql();\n const createNotificationsSql = buildCreateNotificationsSql();\n if (isPostgres()) {\n // PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout\n await ensureTableExists(\n \"integration_remote_push_registrations\",\n createRegistrationsSql,\n );\n await ensureIndexExists(\n \"idx_remote_push_token_hash\",\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_push_token_hash ON integration_remote_push_registrations(token_hash)`,\n );\n await ensureIndexExists(\n \"idx_remote_push_owner\",\n `CREATE INDEX IF NOT EXISTS idx_remote_push_owner ON integration_remote_push_registrations(owner_email, org_id, status)`,\n );\n await ensureTableExists(\n \"integration_remote_push_notifications\",\n createNotificationsSql,\n );\n await ensureIndexExists(\n \"idx_remote_push_notifications_owner\",\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_owner ON integration_remote_push_notifications(owner_email, org_id, status, created_at)`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"provider_ticket_id\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS provider_ticket_id TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"next_attempt_at\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS next_attempt_at ${intType()} NOT NULL DEFAULT 0`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"last_error\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS last_error TEXT`,\n );\n await ensureColumnExists(\n \"integration_remote_push_notifications\",\n \"delivered_at\",\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN IF NOT EXISTS delivered_at ${intType()}`,\n );\n await ensureIndexExists(\n \"idx_remote_push_notifications_delivery\",\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_delivery ON integration_remote_push_notifications(status, next_attempt_at, updated_at)`,\n );\n return;\n }\n // SQLite (local dev): keep existing behavior\n await retryOnDdlRace(() => client.execute(createRegistrationsSql));\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_push_token_hash ON integration_remote_push_registrations(token_hash)`,\n ),\n );\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_push_owner ON integration_remote_push_registrations(owner_email, org_id, status)`,\n ),\n );\n\n await retryOnDdlRace(() => client.execute(createNotificationsSql));\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_owner ON integration_remote_push_notifications(owner_email, org_id, status, created_at)`,\n ),\n );\n await addNotificationColumnIfMissing(\"provider_ticket_id\", \"TEXT\");\n await addNotificationColumnIfMissing(\n \"next_attempt_at\",\n `${intType()} NOT NULL DEFAULT 0`,\n );\n await addNotificationColumnIfMissing(\"last_error\", \"TEXT\");\n await addNotificationColumnIfMissing(\"delivered_at\", intType());\n await retryOnDdlRace(() =>\n client.execute(\n `CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_delivery ON integration_remote_push_notifications(status, next_attempt_at, updated_at)`,\n ),\n );\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nasync function addNotificationColumnIfMissing(\n name: string,\n definition: string,\n): Promise<void> {\n try {\n await retryOnDdlRace(() =>\n getDbExec().execute(\n `ALTER TABLE integration_remote_push_notifications ADD COLUMN ${name} ${definition}`,\n ),\n );\n } catch (error) {\n if (!isDuplicateColumnError(error)) throw error;\n }\n}\n\nfunction rowToRegistration(\n row: Record<string, unknown>,\n): RemotePushRegistration {\n return {\n id: row.id as string,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n provider: row.provider as string,\n platform: (row.platform as string | null) ?? null,\n clientDeviceId: (row.client_device_id as string | null) ?? null,\n label: (row.label as string | null) ?? null,\n token: row.token as string,\n tokenHash: row.token_hash as string,\n status: row.status as RemotePushRegistration[\"status\"],\n lastSeenAt:\n row.last_seen_at == null ? null : Number(row.last_seen_at as number),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nfunction rowToNotification(\n row: Record<string, unknown>,\n): RemotePushNotification {\n const storedStatus = String(row.status ?? \"pending\");\n const status =\n storedStatus === \"delivered\" || storedStatus === \"failed\"\n ? storedStatus\n : \"pending\";\n return {\n id: row.id as string,\n ownerEmail: row.owner_email as string,\n orgId: (row.org_id as string | null) ?? null,\n registrationId: row.registration_id as string,\n payload: parseJson(row.payload_json, null),\n status,\n attempts: Number(row.attempts ?? 0),\n createdAt: Number(row.created_at ?? 0),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nexport function toPublicRemotePushRegistration(\n registration: RemotePushRegistration,\n): PublicRemotePushRegistration {\n return {\n id: registration.id,\n ownerEmail: registration.ownerEmail,\n orgId: registration.orgId,\n provider: registration.provider,\n platform: registration.platform,\n clientDeviceId: registration.clientDeviceId,\n label: registration.label,\n status: registration.status,\n lastSeenAt: registration.lastSeenAt,\n createdAt: registration.createdAt,\n updatedAt: registration.updatedAt,\n };\n}\n\nexport async function upsertRemotePushRegistration(input: {\n ownerEmail: string;\n orgId?: string | null;\n provider: string;\n token: string;\n platform?: string | null;\n clientDeviceId?: string | null;\n label?: string | null;\n}): Promise<RemotePushRegistration> {\n await ensureTables();\n const client = getDbExec();\n const now = Date.now();\n const tokenHash = await hashToken(input.token);\n const provider = sanitizeString(input.provider, 80) ?? \"unknown\";\n const platform = sanitizeString(input.platform, 80);\n const clientDeviceId = sanitizeString(input.clientDeviceId, 200);\n const label = sanitizeString(input.label, 200);\n\n const existing = await getRemotePushRegistrationByTokenHash(tokenHash);\n if (existing) {\n await client.execute({\n sql: `UPDATE integration_remote_push_registrations\n SET owner_email = ?,\n org_id = ?,\n provider = ?,\n platform = ?,\n client_device_id = ?,\n label = ?,\n token = ?,\n status = 'active',\n last_seen_at = ?,\n updated_at = ?\n WHERE token_hash = ?`,\n args: [\n input.ownerEmail,\n input.orgId ?? null,\n provider,\n platform,\n clientDeviceId,\n label,\n input.token,\n now,\n now,\n tokenHash,\n ],\n });\n const updated = await getRemotePushRegistrationByTokenHash(tokenHash);\n if (!updated) throw new Error(\"remote push registration update failed\");\n return updated;\n }\n\n const id = `remote-push-${now}-${randomHex(8)}`;\n await client.execute({\n sql: `INSERT INTO integration_remote_push_registrations\n (id, owner_email, org_id, provider, platform, client_device_id, label,\n token, token_hash, status, last_seen_at, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n input.ownerEmail,\n input.orgId ?? null,\n provider,\n platform,\n clientDeviceId,\n label,\n input.token,\n tokenHash,\n \"active\",\n now,\n now,\n now,\n ],\n });\n const registration = await getRemotePushRegistrationByTokenHash(tokenHash);\n if (!registration) throw new Error(\"remote push registration insert failed\");\n return registration;\n}\n\nexport async function listRemotePushRegistrationsForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n includeInactive?: boolean;\n limit?: number;\n}): Promise<RemotePushRegistration[]> {\n await ensureTables();\n const limit = Math.max(1, Math.min(input.limit ?? 50, 100));\n const statusClause = input.includeInactive ? \"\" : \" AND status = 'active'\";\n if (!Object.prototype.hasOwnProperty.call(input, \"orgId\")) {\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_registrations\n WHERE owner_email = ?${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args: [input.ownerEmail, limit],\n });\n return rows.map((row) => rowToRegistration(row as Record<string, unknown>));\n }\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_registrations\n WHERE owner_email = ?\n AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)${statusClause}\n ORDER BY COALESCE(last_seen_at, updated_at) DESC\n LIMIT ?`,\n args: [input.ownerEmail, input.orgId ?? null, input.orgId ?? null, limit],\n });\n return rows.map((row) => rowToRegistration(row as Record<string, unknown>));\n}\n\nexport async function unregisterRemotePushRegistrationForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n id?: string | null;\n token?: string | null;\n}): Promise<boolean> {\n await ensureTables();\n const tokenHash = input.token ? await hashToken(input.token) : null;\n if (!input.id && !tokenHash) return false;\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_registrations\n SET status = 'inactive', updated_at = ?\n WHERE owner_email = ?\n AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)\n AND (${input.id ? \"id = ?\" : \"0 = 1\"} OR ${\n tokenHash ? \"token_hash = ?\" : \"0 = 1\"\n })`,\n args: [\n now,\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ...(input.id ? [input.id] : []),\n ...(tokenHash ? [tokenHash] : []),\n ],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) > 0;\n}\n\nexport async function queueRemotePushNotifications(input: {\n ownerEmail: string;\n orgId?: string | null;\n payload: unknown;\n}): Promise<{ queued: number }> {\n await ensureTables();\n const registrations = await listRemotePushRegistrationsForOwner({\n ownerEmail: input.ownerEmail,\n orgId: input.orgId ?? null,\n limit: 100,\n });\n if (registrations.length === 0) return { queued: 0 };\n\n const client = getDbExec();\n const now = Date.now();\n const payload = JSON.stringify(input.payload ?? null);\n const values = registrations.map(\n () => \"(?, ?, ?, ?, ?, 'pending', 0, ?, ?, ?)\",\n );\n const args = registrations.flatMap((registration) => [\n `remote-push-notification-${now}-${randomHex(8)}`,\n input.ownerEmail,\n input.orgId ?? null,\n registration.id,\n payload,\n now,\n now,\n now,\n ]);\n const result = await client.execute({\n sql: `INSERT INTO integration_remote_push_notifications\n (id, owner_email, org_id, registration_id, payload_json, status,\n attempts, next_attempt_at, created_at, updated_at)\n VALUES ${values.join(\", \")}`,\n args,\n });\n return {\n queued: result.rowsAffected ?? (result as any).rowCount ?? 0,\n };\n}\n\nexport async function listRemotePushNotificationsForOwner(input: {\n ownerEmail: string;\n orgId?: string | null;\n status?: RemotePushNotification[\"status\"];\n limit?: number;\n}): Promise<RemotePushNotification[]> {\n await ensureTables();\n const limit = Math.max(1, Math.min(input.limit ?? 50, 100));\n const statusClause = input.status\n ? input.status === \"pending\"\n ? \" AND status IN ('pending', 'sending', 'sent', 'checking')\"\n : \" AND status = ?\"\n : \"\";\n const args: Array<string | number | null> = [\n input.ownerEmail,\n input.orgId ?? null,\n input.orgId ?? null,\n ];\n if (input.status && input.status !== \"pending\") args.push(input.status);\n args.push(limit);\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_notifications\n WHERE owner_email = ?\n AND ((org_id IS NULL AND CAST(? AS TEXT) IS NULL) OR org_id = ?)${statusClause}\n ORDER BY created_at DESC\n LIMIT ?`,\n args,\n });\n return rows.map((row) => rowToNotification(row as Record<string, unknown>));\n}\n\nexport interface ClaimedRemotePushDelivery {\n id: string;\n registrationId: string;\n provider: string;\n token: string;\n payload: unknown;\n phase: \"send\" | \"receipt\";\n providerTicketId: string | null;\n attempts: number;\n}\n\nexport async function claimNextRemotePushDelivery(input?: {\n now?: number;\n staleAfterMs?: number;\n}): Promise<ClaimedRemotePushDelivery | null> {\n await ensureTables();\n const client = getDbExec();\n const now = input?.now ?? Date.now();\n const staleBefore = now - Math.max(30_000, input?.staleAfterMs ?? 120_000);\n const { rows } = await client.execute({\n sql: `SELECT n.id, n.registration_id, n.payload_json, n.status, n.attempts,\n n.provider_ticket_id, n.updated_at, r.provider, r.token\n FROM integration_remote_push_notifications n\n INNER JOIN integration_remote_push_registrations r\n ON r.id = n.registration_id\n WHERE r.status = 'active'\n AND (\n (n.status IN ('pending', 'sent') AND n.next_attempt_at <= ?)\n OR (n.status IN ('sending', 'checking') AND n.updated_at <= ?)\n )\n ORDER BY n.created_at ASC\n LIMIT 1`,\n args: [now, staleBefore],\n });\n const row = rows[0] as Record<string, unknown> | undefined;\n if (!row) return null;\n\n const previousStatus = String(row.status ?? \"pending\");\n const providerTicketId = sanitizeString(\n row.provider_ticket_id as string | null,\n 200,\n );\n const phase =\n (previousStatus === \"sent\" || previousStatus === \"checking\") &&\n providerTicketId\n ? \"receipt\"\n : \"send\";\n const claimedStatus = phase === \"receipt\" ? \"checking\" : \"sending\";\n const result = await client.execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = ?, attempts = attempts + 1, updated_at = ?\n WHERE id = ? AND status = ? AND updated_at = ?`,\n args: [\n claimedStatus,\n now,\n row.id as string,\n previousStatus,\n Number(row.updated_at),\n ],\n });\n if ((result.rowsAffected ?? (result as any).rowCount ?? 0) !== 1) return null;\n\n return {\n id: row.id as string,\n registrationId: row.registration_id as string,\n provider: String(row.provider ?? \"unknown\"),\n token: row.token as string,\n payload: parseJson(row.payload_json, null),\n phase,\n providerTicketId,\n attempts: Number(row.attempts ?? 0) + 1,\n };\n}\n\nexport async function markRemotePushTicketAccepted(input: {\n id: string;\n providerTicketId: string;\n checkAfter: number;\n}): Promise<boolean> {\n await ensureTables();\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'sent', provider_ticket_id = ?, next_attempt_at = ?,\n last_error = NULL, updated_at = ?\n WHERE id = ? AND status = 'sending'`,\n args: [input.providerTicketId, input.checkAfter, now, input.id],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function markRemotePushDelivered(id: string): Promise<boolean> {\n await ensureTables();\n const now = Date.now();\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'delivered', last_error = NULL, delivered_at = ?,\n updated_at = ?\n WHERE id = ? AND status = 'checking'`,\n args: [now, now, id],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function retryRemotePushDelivery(input: {\n id: string;\n phase: \"send\" | \"receipt\";\n retryAt: number;\n errorCode: string;\n resend?: boolean;\n}): Promise<boolean> {\n await ensureTables();\n const currentStatus = input.phase === \"receipt\" ? \"checking\" : \"sending\";\n const retryStatus =\n input.phase === \"receipt\" && !input.resend ? \"sent\" : \"pending\";\n const clearTicketClause = input.resend ? \", provider_ticket_id = NULL\" : \"\";\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = ?, next_attempt_at = ?, last_error = ?${clearTicketClause},\n updated_at = ?\n WHERE id = ? AND status = ?`,\n args: [\n retryStatus,\n input.retryAt,\n sanitizeString(input.errorCode, 160) ?? \"temporary_error\",\n Date.now(),\n input.id,\n currentStatus,\n ],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function failRemotePushDelivery(input: {\n id: string;\n phase: \"send\" | \"receipt\";\n errorCode: string;\n}): Promise<boolean> {\n await ensureTables();\n const currentStatus = input.phase === \"receipt\" ? \"checking\" : \"sending\";\n const result = await getDbExec().execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'failed', last_error = ?, updated_at = ?\n WHERE id = ? AND status = ?`,\n args: [\n sanitizeString(input.errorCode, 160) ?? \"delivery_failed\",\n Date.now(),\n input.id,\n currentStatus,\n ],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nexport async function deactivateRemotePushRegistration(\n registrationId: string,\n): Promise<boolean> {\n await ensureTables();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: `UPDATE integration_remote_push_registrations\n SET status = 'inactive', updated_at = ?\n WHERE id = ? AND status = 'active'`,\n args: [now, registrationId],\n });\n await client.execute({\n sql: `UPDATE integration_remote_push_notifications\n SET status = 'failed', last_error = 'registration_inactive',\n updated_at = ?\n WHERE registration_id = ?\n AND status IN ('pending', 'sending', 'sent', 'checking')`,\n args: [now, registrationId],\n });\n return (result.rowsAffected ?? (result as any).rowCount ?? 0) === 1;\n}\n\nasync function getRemotePushRegistrationByTokenHash(\n tokenHash: string,\n): Promise<RemotePushRegistration | null> {\n const { rows } = await getDbExec().execute({\n sql: `SELECT * FROM integration_remote_push_registrations\n WHERE token_hash = ?\n LIMIT 1`,\n args: [tokenHash],\n });\n return rows[0] ? rowToRegistration(rows[0] as Record<string, unknown>) : null;\n}\n\nasync function hashToken(token: string): Promise<string> {\n const bytes = new TextEncoder().encode(token);\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(digest))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction randomHex(byteLength: number): string {\n const bytes = new Uint8Array(byteLength);\n globalThis.crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction sanitizeString(\n value: string | null | undefined,\n max: number,\n): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, max) : null;\n}\n\nfunction parseJson(value: unknown, fallback: unknown): unknown {\n if (value == null) return fallback;\n try {\n return JSON.parse(String(value));\n } catch {\n return fallback;\n }\n}\n"]}
@@ -28,7 +28,7 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
28
28
  } | {
29
29
  count?: undefined;
30
30
  updated?: undefined;
31
- error?: undefined;
32
31
  ok: boolean;
32
+ error?: undefined;
33
33
  }>>;
34
34
  //# sourceMappingURL=routes.d.ts.map
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ error?: undefined;
44
45
  summary: import("./types.js").TraceSummary;
45
46
  spans: import("./types.js").TraceSpan[];
46
47
  id?: undefined;
47
- error?: undefined;
48
48
  ok?: undefined;
49
49
  } | {
50
+ error?: undefined;
50
51
  summary?: undefined;
51
52
  spans?: undefined;
52
53
  id: string;
53
- error?: undefined;
54
54
  ok?: undefined;
55
55
  } | {
56
56
  summary?: undefined;
@@ -59,10 +59,10 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
59
59
  error: any;
60
60
  ok?: undefined;
61
61
  } | {
62
+ error?: undefined;
62
63
  summary?: undefined;
63
64
  spans?: undefined;
64
65
  id?: undefined;
65
66
  ok: boolean;
66
- error?: undefined;
67
67
  }>>;
68
68
  //# sourceMappingURL=routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"traces.d.ts","sourceRoot":"","sources":["../../src/observability/traces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAGxE,OAAO,KAAK,EAA2B,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAmK/E;;;wEAGwE;AACxE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AAoBD,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAc3E;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,YAAY,EAAE,CAAC,QAAQ,EAAE;QACvB,MAAM,EAAE,GAAG,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,GAAG,EAAE,CAAC;QACb,QAAQ,EAAE,GAAG,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;QACtC,MAAM,EAAE,WAAW,CAAC;QACpB,eAAe,CAAC,EAAE,GAAG,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9B,QAAQ,EAAE;QACR,MAAM,EAAE,GAAG,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,GAAG,EAAE,CAAC;QACb,QAAQ,EAAE,GAAG,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;QACtC,MAAM,EAAE,WAAW,CAAC;QACpB,eAAe,CAAC,EAAE,GAAG,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;iBAGa;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,KAAK,CAAC;QAC5B,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,KAAK,GAAG,KAAK,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAC3B;QACE,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;QAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KAC3C,GACD,IAAI,GACJ,SAAS,CAAC;CACf,GAAG,OAAO,CAAC,cAAc,CAAC,CA0f1B"}
1
+ {"version":3,"file":"traces.d.ts","sourceRoot":"","sources":["../../src/observability/traces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAGxE,OAAO,KAAK,EAA2B,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAiM/E;;;wEAGwE;AACxE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AAoBD,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAc3E;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,YAAY,EAAE,CAAC,QAAQ,EAAE;QACvB,MAAM,EAAE,GAAG,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,GAAG,EAAE,CAAC;QACb,QAAQ,EAAE,GAAG,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;QACtC,MAAM,EAAE,WAAW,CAAC;QACpB,eAAe,CAAC,EAAE,GAAG,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9B,QAAQ,EAAE;QACR,MAAM,EAAE,GAAG,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,GAAG,EAAE,CAAC;QACb,QAAQ,EAAE,GAAG,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;QACtC,MAAM,EAAE,WAAW,CAAC;QACpB,eAAe,CAAC,EAAE,GAAG,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;iBAGa;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,KAAK,CAAC;QAC5B,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,KAAK,GAAG,KAAK,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAC3B;QACE,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;QAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KAC3C,GACD,IAAI,GACJ,SAAS,CAAC;CACf,GAAG,OAAO,CAAC,cAAc,CAAC,CAigB1B"}
@@ -22,6 +22,22 @@ function costUsdFromCenticents(value) {
22
22
  return Math.round((value / 10_000) * 1_000_000) / 1_000_000;
23
23
  }
24
24
  const MAX_TRACKED_GENERATION_TOOL_CALLS = 50;
25
+ const MAX_TOOL_ERROR_MESSAGE_LENGTH = 500;
26
+ const STANDALONE_API_KEY_PATTERN = /\b(?:sk-(?:proj-|ant-)?[A-Za-z0-9_-]{8,}|(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{8,}|AIza[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9]{16,})\b/g;
27
+ function truncateToolErrorMessage(value) {
28
+ return value.length > MAX_TOOL_ERROR_MESSAGE_LENGTH
29
+ ? `${value.slice(0, MAX_TOOL_ERROR_MESSAGE_LENGTH)}…`
30
+ : value;
31
+ }
32
+ function redactToolErrorMessage(value) {
33
+ const credentialName = "authorization|cookie|api[_ -]?key|password|secret|token|access[_ -]?token|refresh[_ -]?token";
34
+ const labeledCredential = `(["']?\\b(?:${credentialName})\\b["']?\\s*[:=]\\s*["']?)`;
35
+ return value
36
+ .replace(new RegExp(`${labeledCredential}(?:Bearer|Basic)\\s+[^"'\\s,;)}\\]]+`, "gi"), "$1[REDACTED]")
37
+ .replace(new RegExp(`${labeledCredential}[^"'\\s,;)}\\[\\]]+`, "gi"), "$1[REDACTED]")
38
+ .replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "[REDACTED]")
39
+ .replace(STANDALONE_API_KEY_PATTERN, "[REDACTED]");
40
+ }
25
41
  function emitLlmGenerationTrackingEvent(args) {
26
42
  const provider = llmProviderFromEngine(args.engineName, args.model);
27
43
  const costUsd = costUsdFromCenticents(args.costCentsX100);
@@ -297,6 +313,9 @@ export async function instrumentAgentLoop(opts) {
297
313
  : explicitError
298
314
  ? "tool_error"
299
315
  : "legacy_inferred_error",
316
+ error_message: isError && config.captureToolResults
317
+ ? truncateToolErrorMessage(redactToolErrorMessage(event.result))
318
+ : undefined,
300
319
  });
301
320
  }
302
321
  // Finalize the OTel tool span. If the span promise hasn't resolved yet
@@ -385,6 +404,7 @@ export async function instrumentAgentLoop(opts) {
385
404
  for (const [counter, pending] of pendingTools) {
386
405
  toolCallCount += 1;
387
406
  failedTools += 1;
407
+ const interruptedMessage = "Tool call interrupted before completion";
388
408
  if (counter < MAX_TRACKED_GENERATION_TOOL_CALLS) {
389
409
  generationToolCalls.set(counter, {
390
410
  name: pending.toolName,
@@ -392,9 +412,11 @@ export async function instrumentAgentLoop(opts) {
392
412
  duration_ms: Math.max(0, runEnd - pending.startMs),
393
413
  status: "error",
394
414
  error_class: "interrupted",
415
+ error_message: config.captureToolResults
416
+ ? interruptedMessage
417
+ : undefined,
395
418
  });
396
419
  }
397
- const interruptedMessage = "Tool call interrupted before completion";
398
420
  if (pending.otelSpan) {
399
421
  openOtelToolSpans.delete(pending.otelSpan);
400
422
  endAgentSpan(pending.otelSpan, {