@zuplo/cli 7.4.4 → 7.4.6

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 (229) hide show
  1. package/dist/common/settings.d.ts +1 -0
  2. package/dist/common/settings.d.ts.map +1 -1
  3. package/dist/common/settings.js +3 -0
  4. package/dist/common/settings.js.map +1 -1
  5. package/dist/deploy/classify-build-probe.d.ts +14 -0
  6. package/dist/deploy/classify-build-probe.d.ts.map +1 -0
  7. package/dist/deploy/classify-build-probe.js +35 -0
  8. package/dist/deploy/classify-build-probe.js.map +1 -0
  9. package/dist/deploy/classify-build-probe.test.d.ts +2 -0
  10. package/dist/deploy/classify-build-probe.test.d.ts.map +1 -0
  11. package/dist/deploy/classify-build-probe.test.js +51 -0
  12. package/dist/deploy/classify-build-probe.test.js.map +1 -0
  13. package/dist/deploy/handler.js +20 -5
  14. package/dist/deploy/handler.js.map +1 -1
  15. package/dist/deploy/poll-deployment.d.ts +8 -4
  16. package/dist/deploy/poll-deployment.d.ts.map +1 -1
  17. package/dist/deploy/poll-deployment.js +32 -4
  18. package/dist/deploy/poll-deployment.js.map +1 -1
  19. package/dist/deploy/poll-deployment.test.d.ts +2 -0
  20. package/dist/deploy/poll-deployment.test.d.ts.map +1 -0
  21. package/dist/deploy/poll-deployment.test.js +158 -0
  22. package/dist/deploy/poll-deployment.test.js.map +1 -0
  23. package/dist/tsconfig.tsbuildinfo +1 -1
  24. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jwks/remote.d.ts +4 -4
  25. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jws/general/verify.d.ts +3 -3
  26. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jwt/encrypt.d.ts +8 -14
  27. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jwt/sign.d.ts +8 -14
  28. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -15
  29. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +30 -8
  30. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +8 -4
  31. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +6 -13
  32. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwe/general/decrypt.js +19 -19
  33. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwe/general/encrypt.js +27 -20
  34. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwk/embedded.js +15 -1
  35. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwk/thumbprint.js +11 -5
  36. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwks/local.js +45 -53
  37. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwks/remote.js +82 -103
  38. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jws/compact/sign.js +10 -9
  39. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jws/flattened/sign.js +2 -1
  40. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jws/flattened/verify.js +8 -7
  41. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jws/general/sign.js +5 -3
  42. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jws/general/verify.js +51 -21
  43. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwt/decrypt.js +7 -9
  44. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwt/encrypt.js +21 -50
  45. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwt/sign.js +8 -41
  46. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwt/unsecured.js +21 -42
  47. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/key/generate_key_pair.js +6 -2
  48. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/key/generate_secret.js +7 -6
  49. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/key/import.js +16 -12
  50. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/asn1.js +7 -2
  51. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/content_encryption.js +7 -15
  52. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/deflate.js +8 -0
  53. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/helpers.js +1 -1
  54. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +85 -28
  55. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +40 -12
  56. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/jwk_metadata.js +20 -0
  57. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/jws_sign.js +47 -36
  58. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/jws_verify.js +77 -45
  59. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +82 -47
  60. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/key.js +24 -9
  61. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/key_management.js +10 -4
  62. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/key_options.js +6 -0
  63. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/options.js +26 -0
  64. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/lib/type_checks.js +11 -13
  65. package/node_modules/@modelcontextprotocol/client/node_modules/jose/package.json +1 -1
  66. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwks/remote.d.ts +4 -4
  67. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jws/general/verify.d.ts +3 -3
  68. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/encrypt.d.ts +8 -14
  69. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/sign.d.ts +8 -14
  70. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -15
  71. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +30 -8
  72. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +8 -4
  73. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +6 -13
  74. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/general/decrypt.js +19 -19
  75. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwe/general/encrypt.js +27 -20
  76. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwk/embedded.js +15 -1
  77. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwk/thumbprint.js +11 -5
  78. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwks/local.js +45 -53
  79. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwks/remote.js +82 -103
  80. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/compact/sign.js +10 -9
  81. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/flattened/sign.js +2 -1
  82. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/flattened/verify.js +8 -7
  83. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/general/sign.js +5 -3
  84. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jws/general/verify.js +51 -21
  85. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwt/decrypt.js +7 -9
  86. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwt/encrypt.js +21 -50
  87. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwt/sign.js +8 -41
  88. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwt/unsecured.js +21 -42
  89. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/key/generate_key_pair.js +6 -2
  90. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/key/generate_secret.js +7 -6
  91. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/key/import.js +16 -12
  92. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/asn1.js +7 -2
  93. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/content_encryption.js +7 -15
  94. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/deflate.js +8 -0
  95. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/helpers.js +1 -1
  96. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +85 -28
  97. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +40 -12
  98. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwk_metadata.js +20 -0
  99. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jws_sign.js +47 -36
  100. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jws_verify.js +77 -45
  101. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +82 -47
  102. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key.js +24 -9
  103. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key_management.js +10 -4
  104. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/key_options.js +6 -0
  105. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/options.js +26 -0
  106. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/lib/type_checks.js +11 -13
  107. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/package.json +1 -1
  108. package/node_modules/@posthog/core/dist/logs/index.js +1 -1
  109. package/node_modules/@posthog/core/dist/logs/index.mjs +1 -1
  110. package/node_modules/@posthog/core/dist/logs/logs-utils.d.ts +4 -13
  111. package/node_modules/@posthog/core/dist/logs/logs-utils.d.ts.map +1 -1
  112. package/node_modules/@posthog/core/dist/logs/logs-utils.js +160 -26
  113. package/node_modules/@posthog/core/dist/logs/logs-utils.mjs +160 -26
  114. package/node_modules/@posthog/core/dist/metrics/index.js +1 -1
  115. package/node_modules/@posthog/core/dist/metrics/index.mjs +1 -1
  116. package/node_modules/@posthog/core/dist/posthog-core-stateless.d.ts +12 -18
  117. package/node_modules/@posthog/core/dist/posthog-core-stateless.d.ts.map +1 -1
  118. package/node_modules/@posthog/core/dist/posthog-core-stateless.js +15 -47
  119. package/node_modules/@posthog/core/dist/posthog-core-stateless.mjs +15 -47
  120. package/node_modules/@posthog/core/dist/posthog-core.d.ts.map +1 -1
  121. package/node_modules/@posthog/core/dist/posthog-core.js +12 -7
  122. package/node_modules/@posthog/core/dist/posthog-core.mjs +12 -7
  123. package/node_modules/@posthog/core/dist/types.d.ts +4 -1
  124. package/node_modules/@posthog/core/dist/types.d.ts.map +1 -1
  125. package/node_modules/@posthog/core/dist/utils/index.d.ts +1 -1
  126. package/node_modules/@posthog/core/dist/utils/index.d.ts.map +1 -1
  127. package/node_modules/@posthog/core/dist/utils/index.js +14 -24
  128. package/node_modules/@posthog/core/dist/utils/index.mjs +2 -2
  129. package/node_modules/@posthog/core/dist/utils/json-utils.d.ts +15 -0
  130. package/node_modules/@posthog/core/dist/utils/json-utils.d.ts.map +1 -1
  131. package/node_modules/@posthog/core/dist/utils/json-utils.js +24 -0
  132. package/node_modules/@posthog/core/dist/utils/json-utils.mjs +1 -1
  133. package/node_modules/@posthog/core/package.json +2 -2
  134. package/node_modules/@posthog/core/src/logs/index.spec.ts +77 -0
  135. package/node_modules/@posthog/core/src/logs/index.ts +2 -2
  136. package/node_modules/@posthog/core/src/logs/logs-utils.spec.ts +314 -9
  137. package/node_modules/@posthog/core/src/logs/logs-utils.ts +215 -27
  138. package/node_modules/@posthog/core/src/metrics/index.spec.ts +15 -1
  139. package/node_modules/@posthog/core/src/metrics/index.ts +1 -1
  140. package/node_modules/@posthog/core/src/posthog-core-stateless.ts +40 -65
  141. package/node_modules/@posthog/core/src/posthog-core.ts +19 -12
  142. package/node_modules/@posthog/core/src/types.ts +3 -1
  143. package/node_modules/@posthog/core/src/utils/index.ts +3 -1
  144. package/node_modules/@posthog/core/src/utils/json-utils.ts +15 -8
  145. package/node_modules/@posthog/types/dist/capture-log.d.ts +10 -1
  146. package/node_modules/@posthog/types/dist/capture-log.d.ts.map +1 -1
  147. package/node_modules/@posthog/types/dist/index.d.ts +1 -1
  148. package/node_modules/@posthog/types/dist/index.d.ts.map +1 -1
  149. package/node_modules/@posthog/types/dist/posthog-config.d.ts +20 -5
  150. package/node_modules/@posthog/types/dist/posthog-config.d.ts.map +1 -1
  151. package/node_modules/@posthog/types/package.json +1 -1
  152. package/node_modules/@posthog/types/src/capture-log.ts +8 -1
  153. package/node_modules/@posthog/types/src/index.ts +1 -0
  154. package/node_modules/@posthog/types/src/posthog-config.ts +21 -5
  155. package/node_modules/@zuplo/core/customer.cli.minified.js +1 -1
  156. package/node_modules/@zuplo/core/index.minified.js +1 -1
  157. package/node_modules/@zuplo/core/package.json +1 -1
  158. package/node_modules/@zuplo/graphql/package.json +1 -1
  159. package/node_modules/@zuplo/openapi-tools/package.json +1 -1
  160. package/node_modules/@zuplo/otel/package.json +1 -1
  161. package/node_modules/@zuplo/runtime/out/esm/{chunk-IZE65N7D.js → chunk-CUK3VROF.js} +2 -2
  162. package/node_modules/@zuplo/runtime/out/esm/{chunk-4CDML74A.js → chunk-K4TBJG47.js} +2 -2
  163. package/node_modules/@zuplo/runtime/out/esm/{chunk-4VE55TG3.js → chunk-S4EBLGSU.js} +2 -2
  164. package/node_modules/@zuplo/runtime/out/esm/{chunk-4POCC75H.js → chunk-XF3IIUDX.js} +4 -4
  165. package/node_modules/@zuplo/runtime/out/esm/{chunk-4POCC75H.js.map → chunk-XF3IIUDX.js.map} +1 -1
  166. package/node_modules/@zuplo/runtime/out/esm/chunk-ZPOD3IK4.js +403 -0
  167. package/node_modules/@zuplo/runtime/out/esm/chunk-ZPOD3IK4.js.map +1 -0
  168. package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
  169. package/node_modules/@zuplo/runtime/out/esm/internal/index.js +1 -1
  170. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
  171. package/node_modules/@zuplo/runtime/out/esm/mocks/index.js +1 -1
  172. package/node_modules/@zuplo/runtime/out/esm/sdks/aws/index.js +1 -1
  173. package/node_modules/@zuplo/runtime/package.json +1 -1
  174. package/node_modules/fast-uri/index.js +201 -48
  175. package/node_modules/fast-uri/lib/schemes.js +9 -4
  176. package/node_modules/fast-uri/lib/utils.js +388 -91
  177. package/node_modules/fast-uri/package.json +1 -1
  178. package/node_modules/fast-uri/test/component-safe-serialization.test.js +105 -0
  179. package/node_modules/fast-uri/test/equal.test.js +31 -3
  180. package/node_modules/fast-uri/test/fixtures/uri-js-parse.json +2 -0
  181. package/node_modules/fast-uri/test/ipv6-canonical.test.js +34 -0
  182. package/node_modules/fast-uri/test/ipv6-validation.test.js +90 -0
  183. package/node_modules/fast-uri/test/malformed-percent.test.js +77 -0
  184. package/node_modules/fast-uri/test/malformed-urn.test.js +61 -0
  185. package/node_modules/fast-uri/test/parse.test.js +7 -3
  186. package/node_modules/fast-uri/test/query-fragment-normalization.test.js +33 -0
  187. package/node_modules/fast-uri/test/reserved-path-normalization.test.js +109 -0
  188. package/node_modules/fast-uri/test/scheme-validation.test.js +124 -0
  189. package/node_modules/fast-uri/test/security-normalization.test.js +101 -0
  190. package/node_modules/fast-uri/test/security.test.js +75 -3
  191. package/node_modules/fast-uri/test/urn-full-input.test.js +29 -0
  192. package/node_modules/fast-uri/test/websocket-query-preservation.test.js +24 -0
  193. package/node_modules/hono/dist/cjs/client/client.js +25 -11
  194. package/node_modules/hono/dist/cjs/client/utils.js +3 -0
  195. package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +36 -2
  196. package/node_modules/hono/dist/cjs/jsx/dom/render.js +2 -0
  197. package/node_modules/hono/dist/cjs/middleware/etag/index.js +1 -1
  198. package/node_modules/hono/dist/cjs/request.js +8 -4
  199. package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +10 -3
  200. package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +47 -83
  201. package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +2 -1
  202. package/node_modules/hono/dist/cjs/router/trie-router/node.js +4 -3
  203. package/node_modules/hono/dist/cjs/router/utils.js +27 -0
  204. package/node_modules/hono/dist/cjs/utils/cookie.js +1 -1
  205. package/node_modules/hono/dist/cjs/utils/stream.js +7 -1
  206. package/node_modules/hono/dist/client/client.js +25 -11
  207. package/node_modules/hono/dist/client/utils.js +3 -0
  208. package/node_modules/hono/dist/helper/accepts/accepts.js +36 -2
  209. package/node_modules/hono/dist/jsx/dom/render.js +2 -0
  210. package/node_modules/hono/dist/middleware/etag/index.js +1 -1
  211. package/node_modules/hono/dist/request.js +8 -4
  212. package/node_modules/hono/dist/router/reg-exp-router/node.js +6 -2
  213. package/node_modules/hono/dist/router/reg-exp-router/router.js +53 -84
  214. package/node_modules/hono/dist/router/reg-exp-router/trie.js +2 -1
  215. package/node_modules/hono/dist/router/trie-router/node.js +4 -3
  216. package/node_modules/hono/dist/router/utils.js +5 -0
  217. package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +3 -0
  218. package/node_modules/hono/dist/types/router/utils.d.ts +1 -0
  219. package/node_modules/hono/dist/utils/cookie.js +1 -1
  220. package/node_modules/hono/dist/utils/stream.js +7 -1
  221. package/node_modules/hono/package.json +1 -1
  222. package/package.json +11 -11
  223. package/node_modules/@zuplo/runtime/out/esm/chunk-4SX4HBWT.js +0 -409
  224. package/node_modules/@zuplo/runtime/out/esm/chunk-4SX4HBWT.js.map +0 -1
  225. /package/node_modules/@zuplo/runtime/out/esm/{chunk-IZE65N7D.js.map → chunk-CUK3VROF.js.map} +0 -0
  226. /package/node_modules/@zuplo/runtime/out/esm/{chunk-4CDML74A.js.map → chunk-K4TBJG47.js.map} +0 -0
  227. /package/node_modules/@zuplo/runtime/out/esm/{chunk-4VE55TG3.js.map → chunk-S4EBLGSU.js.map} +0 -0
  228. /package/node_modules/@zuplo/runtime/out/esm/{chunk-4POCC75H.js.LEGAL.txt → chunk-XF3IIUDX.js.LEGAL.txt} +0 -0
  229. /package/node_modules/@zuplo/runtime/out/esm/{chunk-4SX4HBWT.js.LEGAL.txt → chunk-ZPOD3IK4.js.LEGAL.txt} +0 -0
@@ -1,4 +1,5 @@
1
1
  import { PostHogPersistedProperty } from '../types'
2
+ import { createTestClient, PostHogCoreTestClient } from '../testing'
2
3
  import type { Logger } from '../types'
3
4
  import { PostHogLogs } from './index'
4
5
  import type { BufferedLogEntry, ResolvedPostHogLogsConfig } from './types'
@@ -80,6 +81,82 @@ const getContextFor = (instance: any) => (): { distinctId?: string; sessionId?:
80
81
  sessionId: instance.getSessionId() || undefined,
81
82
  })
82
83
 
84
+ // Drives a real core host rather than a stubbed `_sendLogsBatch`, so the sender's
85
+ // error classification and the queue bookkeeping are exercised together.
86
+ describe('PostHogLogs over the core sender', () => {
87
+ const createLogsOverCore = (status: number): { logs: PostHogLogs; client: PostHogCoreTestClient } => {
88
+ const [client, mocks] = createTestClient('TEST_API_KEY', {
89
+ fetchRetryCount: 0,
90
+ preloadFeatureFlags: false,
91
+ })
92
+ mocks.fetch.mockResolvedValue({
93
+ status,
94
+ text: () => Promise.resolve('err'),
95
+ json: () => Promise.resolve({ status: 'err' }),
96
+ })
97
+ const logs = new PostHogLogs(
98
+ client,
99
+ resolveForTest(),
100
+ createMockLogger(),
101
+ () => ({ distinctId: 'user-123' }),
102
+ immediateOnReady
103
+ )
104
+ return { logs, client }
105
+ }
106
+
107
+ const queueOf = (client: PostHogCoreTestClient): BufferedLogEntry[] =>
108
+ client.getPersistedProperty<BufferedLogEntry[]>(PostHogPersistedProperty.LogsQueue) ?? []
109
+
110
+ it.each([408, 429, 500, 503])('keeps records queued when the endpoint answers %i', async (status) => {
111
+ const { logs, client } = createLogsOverCore(status)
112
+ logs.captureLog({ body: 'keep me' })
113
+
114
+ await expect(logs.flush()).rejects.toHaveProperty('name', 'PostHogFetchHttpError')
115
+
116
+ expect(queueOf(client)).toHaveLength(1)
117
+ })
118
+
119
+ it('retains and resends records after transport retries are exhausted', async () => {
120
+ jest.useRealTimers()
121
+ const [client, mocks] = createTestClient('TEST_API_KEY', {
122
+ fetchRetryCount: 2,
123
+ fetchRetryDelay: 1,
124
+ preloadFeatureFlags: false,
125
+ })
126
+ const unavailableResponse = { status: 503, text: async () => 'unavailable', json: async () => ({}) }
127
+ mocks.fetch
128
+ .mockResolvedValueOnce(unavailableResponse)
129
+ .mockResolvedValueOnce(unavailableResponse)
130
+ .mockResolvedValueOnce(unavailableResponse)
131
+ .mockResolvedValueOnce({ status: 200, text: async () => 'ok', json: async () => ({}) })
132
+ const logs = new PostHogLogs(
133
+ client,
134
+ resolveForTest(),
135
+ createMockLogger(),
136
+ () => ({ distinctId: 'user-123' }),
137
+ immediateOnReady
138
+ )
139
+
140
+ logs.captureLog({ body: 'retry me' })
141
+ await expect(logs.flush()).rejects.toHaveProperty('name', 'PostHogFetchHttpError')
142
+ expect(mocks.fetch).toHaveBeenCalledTimes(3)
143
+ expect(queueOf(client)).toHaveLength(1)
144
+
145
+ await expect(logs.flush()).resolves.toBeUndefined()
146
+ expect(mocks.fetch).toHaveBeenCalledTimes(4)
147
+ expect(queueOf(client)).toHaveLength(0)
148
+ })
149
+
150
+ it('drops the batch when the endpoint answers 401', async () => {
151
+ const { logs, client } = createLogsOverCore(401)
152
+ logs.captureLog({ body: 'unauthorized' })
153
+
154
+ await expect(logs.flush()).rejects.toHaveProperty('name', 'PostHogFetchHttpError')
155
+
156
+ expect(queueOf(client)).toHaveLength(0)
157
+ })
158
+ })
159
+
83
160
  describe('PostHogLogs', () => {
84
161
  let mockInstance: any
85
162
  let logger: Logger
@@ -119,7 +119,7 @@ export class PostHogLogs {
119
119
  // Build before deferring so attributes reflect state at capture time, not
120
120
  // at drain time (identity/session changes between capture and drain must
121
121
  // not corrupt recorded attributes).
122
- const record = buildOtlpLogRecord(filtered, this._getContext())
122
+ const record = buildOtlpLogRecord(filtered, this._getContext(), this._logger)
123
123
  const entry: BufferedLogEntry = { record }
124
124
 
125
125
  this._onReady(() => this._enqueue(entry))
@@ -262,7 +262,7 @@ export class PostHogLogs {
262
262
  }
263
263
 
264
264
  if (outcome.kind === 'retry-later') {
265
- // Network error: keep records in the queue for the next flush cycle
265
+ // Transient failure: keep records in the queue for the next flush cycle
266
266
  // and surface the error so the caller can log/react.
267
267
  throw outcome.error
268
268
  }
@@ -1,4 +1,4 @@
1
- import type { CaptureLogOptions, LogSeverityLevel } from '@posthog/types'
1
+ import type { CaptureLogOptions, LogAttributeValue, LogSeverityLevel } from '@posthog/types'
2
2
  import type { LogSdkContext } from './types'
3
3
  import {
4
4
  buildOtlpLogRecord,
@@ -69,10 +69,36 @@ describe('logs-utils', () => {
69
69
  expect(toOtlpAnyValue('hello')).toEqual({ stringValue: 'hello' })
70
70
  })
71
71
 
72
- it('converts integers', () => {
73
- expect(toOtlpAnyValue(42)).toEqual({ intValue: 42 })
74
- expect(toOtlpAnyValue(0)).toEqual({ intValue: 0 })
75
- expect(toOtlpAnyValue(-7)).toEqual({ intValue: -7 })
72
+ it('converts integers to decimal strings', () => {
73
+ expect(toOtlpAnyValue(42)).toEqual({ intValue: '42' })
74
+ expect(toOtlpAnyValue(0)).toEqual({ intValue: '0' })
75
+ expect(toOtlpAnyValue(-7)).toEqual({ intValue: '-7' })
76
+ })
77
+
78
+ // Spec: outside int64 it is a stringValue, never an intValue.
79
+ it('converts integers outside int64 to stringValue', () => {
80
+ expect(toOtlpAnyValue(2 ** 63)).toEqual({ stringValue: '9223372036854775808' })
81
+ expect(toOtlpAnyValue(-(2 ** 64))).toEqual({ stringValue: '-18446744073709551616' })
82
+ expect(toOtlpAnyValue(1e21)).toEqual({ stringValue: '1000000000000000000000' })
83
+ })
84
+
85
+ it('logs a debug line when an integer falls outside int64', () => {
86
+ const logger = { debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), critical: jest.fn() }
87
+ toOtlpAnyValue(2 ** 63, logger as any)
88
+ expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('outside the int64 range'))
89
+ })
90
+
91
+ it('keeps int64 min as intValue', () => {
92
+ // In range, but `String` renders it 192 below int64 min, so the decimal
93
+ // has to come from BigInt.
94
+ expect(toOtlpAnyValue(-(2 ** 63))).toEqual({ intValue: '-9223372036854775808' })
95
+ })
96
+
97
+ it('keeps large in-range integers exact', () => {
98
+ expect(toOtlpAnyValue(Number.MAX_SAFE_INTEGER)).toEqual({ intValue: '9007199254740991' })
99
+ // The largest double below 2^63 — no double exists between the two.
100
+ expect(toOtlpAnyValue(9223372036854774784)).toEqual({ intValue: '9223372036854774784' })
101
+ expect(toOtlpAnyValue(2 ** 62)).toEqual({ intValue: '4611686018427387904' })
76
102
  })
77
103
 
78
104
  it('converts floats to doubleValue', () => {
@@ -108,16 +134,295 @@ describe('logs-utils', () => {
108
134
  it('converts mixed primitive arrays recursively', () => {
109
135
  expect(toOtlpAnyValue([1, 'x', true])).toEqual({
110
136
  arrayValue: {
111
- values: [{ intValue: 1 }, { stringValue: 'x' }, { boolValue: true }],
137
+ values: [{ intValue: '1' }, { stringValue: 'x' }, { boolValue: true }],
112
138
  },
113
139
  })
114
140
  })
115
141
 
116
- it('JSON-stringifies plain objects', () => {
142
+ it('converts plain objects to kvlistValue', () => {
117
143
  expect(toOtlpAnyValue({ a: 1, b: 'two' })).toEqual({
118
- stringValue: '{"a":1,"b":"two"}',
144
+ kvlistValue: {
145
+ values: [
146
+ { key: 'a', value: { intValue: '1' } },
147
+ { key: 'b', value: { stringValue: 'two' } },
148
+ ],
149
+ },
150
+ })
151
+ })
152
+
153
+ it('converts nested objects recursively', () => {
154
+ expect(toOtlpAnyValue({ outer: { inner: 1 } })).toEqual({
155
+ kvlistValue: {
156
+ values: [
157
+ {
158
+ key: 'outer',
159
+ value: { kvlistValue: { values: [{ key: 'inner', value: { intValue: '1' } }] } },
160
+ },
161
+ ],
162
+ },
163
+ })
164
+ })
165
+
166
+ it('drops null and undefined keys inside objects', () => {
167
+ expect(toOtlpAnyValue({ kept: 1, gone: null, alsoGone: undefined })).toEqual({
168
+ kvlistValue: { values: [{ key: 'kept', value: { intValue: '1' } }] },
169
+ })
170
+ })
171
+
172
+ // Not in LogAttributeValue, but reachable at runtime from untyped callers.
173
+ it('encodes Dates as ISO strings', () => {
174
+ expect(toOtlpAnyValue(new Date('2026-08-20T10:00:00.000Z') as unknown as LogAttributeValue)).toEqual({
175
+ stringValue: '2026-08-20T10:00:00.000Z',
176
+ })
177
+ })
178
+
179
+ it('marks circular references instead of recursing', () => {
180
+ const cyclic: Record<string, unknown> = { name: 'root' }
181
+ cyclic.self = cyclic
182
+ expect(toOtlpAnyValue(cyclic)).toEqual({
183
+ kvlistValue: {
184
+ values: [
185
+ { key: 'name', value: { stringValue: 'root' } },
186
+ { key: 'self', value: { stringValue: '[Circular]' } },
187
+ ],
188
+ },
189
+ })
190
+ })
191
+
192
+ // An escaping error would surface in the caller's application code.
193
+ it('does not throw on an object nested past the depth cap', () => {
194
+ let deep: Record<string, unknown> = { end: true }
195
+ for (let i = 0; i < 25000; i++) {
196
+ deep = { next: deep }
197
+ }
198
+ expect(() => toOtlpAnyValue(deep)).not.toThrow()
199
+ })
200
+
201
+ it('truncates at exactly 20 levels instead of recursing', () => {
202
+ let deep: Record<string, unknown> = { end: true }
203
+ for (let i = 0; i < 25; i++) {
204
+ deep = { next: deep }
205
+ }
206
+ const encoded = JSON.stringify(toOtlpAnyValue(deep))
207
+ expect(encoded).toContain('[Truncated]')
208
+ expect(encoded.split('"next"').length - 1).toBe(20)
209
+ })
210
+
211
+ it('marks a throwing getter without losing the rest of the object', () => {
212
+ const attrs = {
213
+ ok: 1,
214
+ get bad(): number {
215
+ throw new Error('getter blew up')
216
+ },
217
+ }
218
+ expect(() => toOtlpKeyValueList(attrs)).not.toThrow()
219
+ expect(toOtlpKeyValueList(attrs)).toEqual([
220
+ { key: 'ok', value: { intValue: '1' } },
221
+ { key: 'bad', value: { stringValue: '[Unserializable]' } },
222
+ ])
223
+ })
224
+
225
+ // for...in walks the prototype chain once own keys are exhausted.
226
+ it('ignores inherited enumerable properties', () => {
227
+ const inherited: Record<string, unknown> = Object.create({ fromPrototype: 'leaked' })
228
+ inherited.own = 1
229
+ expect(toOtlpAnyValue(inherited)).toEqual({
230
+ kvlistValue: { values: [{ key: 'own', value: { intValue: '1' } }] },
119
231
  })
120
232
  })
233
+
234
+ // `String(fn)` would put the function's source text on the wire.
235
+ it('marks function and symbol values instead of stringifying them', () => {
236
+ expect(toOtlpAnyValue({ handler: () => 1, retries: 2 } as unknown as LogAttributeValue)).toEqual({
237
+ kvlistValue: {
238
+ values: [
239
+ { key: 'handler', value: { stringValue: '[Function]' } },
240
+ { key: 'retries', value: { intValue: '2' } },
241
+ ],
242
+ },
243
+ })
244
+ expect(toOtlpAnyValue({ sym: Symbol('x') } as unknown as LogAttributeValue)).toEqual({
245
+ kvlistValue: { values: [{ key: 'sym', value: { stringValue: 'Symbol(x)' } }] },
246
+ })
247
+ })
248
+
249
+ // dayjs, Decimal, ORM documents.
250
+ it('honours toJSON', () => {
251
+ const wrapped = { toJSON: () => ({ amount: 5 }) }
252
+ expect(toOtlpAnyValue(wrapped as unknown as LogAttributeValue)).toEqual({
253
+ kvlistValue: { values: [{ key: 'amount', value: { intValue: '5' } }] },
254
+ })
255
+ })
256
+
257
+ it('falls back to the plain walk when toJSON throws', () => {
258
+ const wrapped = {
259
+ kept: 1,
260
+ toJSON: () => {
261
+ throw new Error('nope')
262
+ },
263
+ }
264
+ expect(toOtlpAnyValue(wrapped as unknown as LogAttributeValue)).toEqual({
265
+ kvlistValue: {
266
+ values: [
267
+ { key: 'kept', value: { intValue: '1' } },
268
+ { key: 'toJSON', value: { stringValue: '[Function]' } },
269
+ ],
270
+ },
271
+ })
272
+ })
273
+
274
+ // A toJSON returning its own object is a cycle like any other.
275
+ it('marks a cycle that runs through toJSON', () => {
276
+ const cyclic: Record<string, unknown> = {}
277
+ cyclic.toJSON = () => ({ inner: cyclic })
278
+ expect(toOtlpAnyValue(cyclic)).toEqual({
279
+ kvlistValue: { values: [{ key: 'inner', value: { stringValue: '[Circular]' } }] },
280
+ })
281
+ })
282
+
283
+ // Both `null` and `{}` here are rejected for the whole request; iOS and
284
+ // Android drop them too.
285
+ it('drops holes and nullish elements from arrays', () => {
286
+ // eslint-disable-next-line no-sparse-arrays
287
+ expect(toOtlpAnyValue([1, , 3])).toEqual({
288
+ arrayValue: { values: [{ intValue: '1' }, { intValue: '3' }] },
289
+ })
290
+ expect(toOtlpAnyValue([1, null, undefined, 3])).toEqual({
291
+ arrayValue: { values: [{ intValue: '1' }, { intValue: '3' }] },
292
+ })
293
+ })
294
+
295
+ it('stops encoding array items once the node budget is spent', () => {
296
+ const row: Record<string, number> = {}
297
+ for (let i = 0; i < 20; i++) {
298
+ row[`k${i}`] = i
299
+ }
300
+ const wide = Array.from({ length: 1000 }, () => ({ ...row }))
301
+ const values = toOtlpAnyValue(wide).arrayValue!.values
302
+ expect(values[values.length - 1]).toEqual({ stringValue: '[Truncated]' })
303
+ // One marker, not one per unencodable item.
304
+ expect(values.filter((v) => v.stringValue === '[Truncated]')).toHaveLength(1)
305
+ })
306
+
307
+ it('caps a shared object graph instead of expanding it', () => {
308
+ let graph: Record<string, unknown> = { leaf: true }
309
+ for (let i = 0; i < 20; i++) {
310
+ graph = { a: graph, b: graph }
311
+ }
312
+ const encoded = JSON.stringify(toOtlpAnyValue(graph))
313
+ expect(encoded).toContain('[Truncated]')
314
+ expect(encoded.length).toBeLessThan(1_000_000)
315
+ })
316
+
317
+ it('caps a very wide object without inventing an attribute key', () => {
318
+ const wide: Record<string, number> = {}
319
+ for (let i = 0; i < 5000; i++) {
320
+ wide[`k${i}`] = i
321
+ }
322
+ const logger = { debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), critical: jest.fn() }
323
+ const values = toOtlpAnyValue(wide, logger as any).kvlistValue!.values
324
+ expect(values).toHaveLength(1000)
325
+ expect(values.every((v) => v.key.startsWith('k'))).toBe(true)
326
+ expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('truncated'))
327
+ })
328
+
329
+ // Why the encoder does not delegate to toJsonSafeValue: that maps them to null.
330
+ it('keeps non-finite floats as strings inside nested objects', () => {
331
+ expect(toOtlpAnyValue({ nested: { ratio: NaN } })).toEqual({
332
+ kvlistValue: {
333
+ values: [
334
+ {
335
+ key: 'nested',
336
+ value: { kvlistValue: { values: [{ key: 'ratio', value: { stringValue: 'NaN' } }] } },
337
+ },
338
+ ],
339
+ },
340
+ })
341
+ })
342
+
343
+ // A lone surrogate survives JSON.stringify as a \uD800 escape, which the
344
+ // server rejects for the whole request.
345
+ it('replaces unpaired surrogates in values and keys', () => {
346
+ expect(toOtlpAnyValue('ok\ud83d')).toEqual({ stringValue: 'ok\ufffd' })
347
+ expect(toOtlpAnyValue({ nested: 'ok\ud83d' })).toEqual({
348
+ kvlistValue: { values: [{ key: 'nested', value: { stringValue: 'ok\ufffd' } }] },
349
+ })
350
+ expect(toOtlpKeyValueList({ 'key\ud83d': 1 })).toEqual([{ key: 'key\ufffd', value: { intValue: '1' } }])
351
+ })
352
+
353
+ it('encodes empty containers with an explicit values array', () => {
354
+ expect(toOtlpAnyValue({})).toEqual({ kvlistValue: { values: [] } })
355
+ expect(toOtlpAnyValue([])).toEqual({ arrayValue: { values: [] } })
356
+ })
357
+
358
+ it('keeps a Date whose toISOString is overridden out of the wire format', () => {
359
+ const broken = new Date('2026-08-20T10:00:00.000Z')
360
+
361
+ ;(broken as any).toISOString = () => ({})
362
+ expect(typeof toOtlpAnyValue(broken as unknown as LogAttributeValue).stringValue).toBe('string')
363
+ })
364
+
365
+ it('encodes sibling references to one object twice, not as circular', () => {
366
+ const shared = { id: 1 }
367
+ expect(toOtlpAnyValue({ a: shared, b: shared })).toEqual({
368
+ kvlistValue: {
369
+ values: [
370
+ { key: 'a', value: { kvlistValue: { values: [{ key: 'id', value: { intValue: '1' } }] } } },
371
+ { key: 'b', value: { kvlistValue: { values: [{ key: 'id', value: { intValue: '1' } }] } } },
372
+ ],
373
+ },
374
+ })
375
+ })
376
+ })
377
+
378
+ describe('buildOtlpLogRecord attribute reads', () => {
379
+ // Reading `options.attributes` happens before the encoder's per-key guard.
380
+ it('marks an attribute whose getter throws without dropping the record', () => {
381
+ const attributes = {
382
+ ok: 1,
383
+ get bad(): number {
384
+ throw new Error('disposed store')
385
+ },
386
+ }
387
+ const record = buildOtlpLogRecord({ body: 'x', attributes }, {})
388
+ expect(record.attributes).toContainEqual({ key: 'ok', value: { intValue: '1' } })
389
+ expect(record.attributes).toContainEqual({ key: 'bad', value: { stringValue: '[Unserializable]' } })
390
+ })
391
+
392
+ // Plain assignment hits the prototype setter and the attribute vanishes.
393
+ it('keeps an attribute literally named __proto__', () => {
394
+ const attributes = JSON.parse('{"__proto__": {"a": 1}, "normal": "n"}')
395
+ const record = buildOtlpLogRecord({ body: 'x', attributes }, {})
396
+ expect(record.attributes.map((a) => a.key)).toContain('__proto__')
397
+ })
398
+
399
+ it('coerces a non-string body', () => {
400
+ // A non-string stringValue is refused for the whole request.
401
+ const record = buildOtlpLogRecord({ body: 12345 as unknown as string }, {})
402
+ expect(record.body).toEqual({ stringValue: '12345' })
403
+ })
404
+
405
+ // `String()` throws on these, and buildOtlpLogRecord is called straight from
406
+ // captureLog — beforeSend can also hand back any body.
407
+ it('marks a body that cannot be coerced to a string', () => {
408
+ const throwing = {
409
+ toString() {
410
+ throw new Error('boom')
411
+ },
412
+ } as unknown as string
413
+ expect(() => buildOtlpLogRecord({ body: throwing }, {})).not.toThrow()
414
+ expect(buildOtlpLogRecord({ body: throwing }, {}).body).toEqual({ stringValue: '[Unserializable]' })
415
+ expect(buildOtlpLogRecord({ body: Object.create(null) }, {}).body).toEqual({
416
+ stringValue: '[Unserializable]',
417
+ })
418
+ })
419
+
420
+ it('keeps the record when the attributes object itself cannot be read', () => {
421
+ const revocable = Proxy.revocable({ a: 1 }, {})
422
+ revocable.revoke()
423
+
424
+ expect(buildOtlpLogRecord({ body: 'x', attributes: revocable.proxy }, {}).body).toEqual({ stringValue: 'x' })
425
+ })
121
426
  })
122
427
 
123
428
  describe('toOtlpKeyValueList', () => {
@@ -130,7 +435,7 @@ describe('logs-utils', () => {
130
435
  })
131
436
  ).toEqual([
132
437
  { key: 'name', value: { stringValue: 'test' } },
133
- { key: 'count', value: { intValue: 5 } },
438
+ { key: 'count', value: { intValue: '5' } },
134
439
  { key: 'active', value: { boolValue: true } },
135
440
  ])
136
441
  })