@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
@@ -9,8 +9,19 @@ import type {
9
9
  OtlpSeverityEntry,
10
10
  OtlpSeverityText,
11
11
  } from '@posthog/types'
12
+ import type { Logger } from '../types'
12
13
  import type { LogSdkContext, ResolvedPostHogLogsConfig } from './types'
13
14
  import { isArray, isBoolean, isNull, isNullish, isUndefined } from '../utils'
15
+ import {
16
+ CIRCULAR_VALUE,
17
+ FUNCTION_VALUE,
18
+ MAX_JSON_SAFE_VALUE_DEPTH,
19
+ MAX_JSON_SAFE_VALUE_ITEMS,
20
+ MAX_JSON_SAFE_VALUE_NODES,
21
+ sanitizeString,
22
+ TRUNCATED_VALUE,
23
+ UNSERIALIZABLE_VALUE,
24
+ } from '../utils/json-utils'
14
25
 
15
26
  // ============================================================================
16
27
  // Severity mapping
@@ -39,49 +50,192 @@ export function getOtlpSeverityNumber(level: LogSeverityLevel): number {
39
50
  // OTLP AnyValue conversion
40
51
  // ============================================================================
41
52
 
42
- export function toOtlpAnyValue(value: LogAttributeValue): OtlpAnyValue {
53
+ // 2^63 — one past int64 max.
54
+ const INT64_RANGE_LIMIT = 9223372036854775808
55
+
56
+ const propertyIsEnumerable = Object.prototype.propertyIsEnumerable
57
+
58
+ interface EncodeState {
59
+ /** Containers on the current path, so a back-reference becomes a marker. */
60
+ ancestors: WeakSet<object>
61
+ remainingNodes: number
62
+ }
63
+
64
+ function newState(): EncodeState {
65
+ return { ancestors: new WeakSet(), remainingNodes: MAX_JSON_SAFE_VALUE_NODES }
66
+ }
67
+
68
+ export function toOtlpAnyValue(value: LogAttributeValue, logger?: Logger): OtlpAnyValue {
69
+ try {
70
+ return encodeAnyValue(value, logger, newState(), 0)
71
+ } catch {
72
+ // Runs inside `captureLog` and the metrics flush: an error escaping here
73
+ // surfaces in the caller's own code.
74
+ return { stringValue: UNSERIALIZABLE_VALUE }
75
+ }
76
+ }
77
+
78
+ export function toOtlpKeyValueList(attrs: Record<string, LogAttributeValue>, logger?: Logger): OtlpKeyValue[] {
79
+ try {
80
+ return encodeKeyValueList(attrs, logger, newState(), 0)
81
+ } catch {
82
+ return []
83
+ }
84
+ }
85
+
86
+ function encodeAnyValue(
87
+ value: LogAttributeValue,
88
+ logger: Logger | undefined,
89
+ state: EncodeState,
90
+ depth: number
91
+ ): OtlpAnyValue {
92
+ if (state.remainingNodes <= 0) {
93
+ return { stringValue: TRUNCATED_VALUE }
94
+ }
95
+ state.remainingNodes--
96
+
43
97
  if (isBoolean(value)) {
44
98
  return { boolValue: value }
45
99
  }
46
- // NOTE: typeof check (not core's isNumber) so NaN is included. core's
47
- // isNumber explicitly excludes NaN via the `x === x` guard, which would
48
- // route NaN through the JSON.stringify branch below — JSON has no
49
- // representation for non-finite floats and JSON.stringify turns them into
50
- // `null`, losing the value server-side. proto3 JSON mapping (which OTLP/HTTP
51
- // rides) requires the literal strings; we encode them as stringValue to keep
52
- // the human-readable signal regardless of which downstream parser sees them.
100
+ // typeof, not core's isNumber, which excludes NaN — proto3 JSON distinguishes
101
+ // a non-finite float from an ordinary string.
53
102
  if (typeof value === 'number') {
54
103
  if (!Number.isFinite(value)) {
55
104
  return { stringValue: String(value) }
56
105
  }
57
106
  if (Number.isInteger(value)) {
58
- return { intValue: value }
107
+ if (Number.isSafeInteger(value)) {
108
+ return { intValue: String(value) }
109
+ }
110
+ // Past MAX_SAFE_INTEGER only BigInt gives the double's exact decimal:
111
+ // `String(-(2**63))` lands 192 below int64 min, outside the field it is
112
+ // about to be parsed into. Without BigInt the value rides as a string,
113
+ // which is never range-checked.
114
+ if (typeof BigInt === 'undefined') {
115
+ return { stringValue: String(value) }
116
+ }
117
+ const decimal = BigInt(value).toString()
118
+ if (value >= INT64_RANGE_LIMIT || value < -INT64_RANGE_LIMIT) {
119
+ // An out-of-range intValue 400s the whole logs request; on the metrics
120
+ // path it is swallowed server-side and the metric just disappears.
121
+ logger?.debug(`Attribute ${decimal} is outside the int64 range; encoding it as a string`)
122
+ return { stringValue: decimal }
123
+ }
124
+ return { intValue: decimal }
59
125
  }
60
126
  return { doubleValue: value }
61
127
  }
62
128
  if (typeof value === 'string') {
63
- return { stringValue: value }
129
+ return { stringValue: sanitizeString(value) }
64
130
  }
65
- if (isArray(value)) {
66
- return { arrayValue: { values: value.map((v) => toOtlpAnyValue(v as LogAttributeValue)) } }
131
+ // `String(value)` would put a function's source text on the wire.
132
+ if (typeof value === 'function') {
133
+ return { stringValue: FUNCTION_VALUE }
67
134
  }
68
- // Objects fall back to JSON. OTLP supports kvlistValue but the encoder
69
- // stays flat for simplicity.
70
- try {
71
- return { stringValue: JSON.stringify(value) }
72
- } catch {
135
+ if (typeof value === 'symbol') {
73
136
  return { stringValue: String(value) }
74
137
  }
138
+ if (typeof value === 'object' && value !== null) {
139
+ if (state.ancestors.has(value)) {
140
+ return { stringValue: CIRCULAR_VALUE }
141
+ }
142
+ if (depth >= MAX_JSON_SAFE_VALUE_DEPTH) {
143
+ return { stringValue: TRUNCATED_VALUE }
144
+ }
145
+ if (value instanceof Date) {
146
+ const time = value.getTime()
147
+ const iso = Number.isFinite(time) ? value.toISOString() : String(value)
148
+ // An overridden toISOString can return a non-string, which the server
149
+ // refuses for the whole request.
150
+ return { stringValue: typeof iso === 'string' ? sanitizeString(iso) : String(iso) }
151
+ }
152
+ // Registered before the toJSON probe: a toJSON returning a structure that
153
+ // references its own object is a cycle like any other.
154
+ state.ancestors.add(value)
155
+ try {
156
+ // The representation a value defines for itself — dayjs, Decimal, an ORM
157
+ // document, and a cross-realm Date that fails the `instanceof` above.
158
+ try {
159
+ const toJSON = (value as { toJSON?: unknown }).toJSON
160
+ if (typeof toJSON === 'function') {
161
+ return encodeAnyValue(toJSON.call(value) as LogAttributeValue, logger, state, depth + 1)
162
+ }
163
+ } catch {
164
+ // A throwing toJSON falls through to the plain walk.
165
+ }
166
+ if (isArray(value)) {
167
+ return { arrayValue: { values: encodeArrayValues(value, logger, state, depth + 1) } }
168
+ }
169
+ return {
170
+ kvlistValue: {
171
+ values: encodeKeyValueList(value as Record<string, LogAttributeValue>, logger, state, depth + 1),
172
+ },
173
+ }
174
+ } finally {
175
+ // Siblings that reference the same object are duplication, not a cycle.
176
+ state.ancestors.delete(value)
177
+ }
178
+ }
179
+ return { stringValue: sanitizeString(String(value)) }
180
+ }
181
+
182
+ function encodeArrayValues(
183
+ values: unknown[],
184
+ logger: Logger | undefined,
185
+ state: EncodeState,
186
+ depth: number
187
+ ): OtlpAnyValue[] {
188
+ const result: OtlpAnyValue[] = []
189
+ const itemCount = Math.min(values.length, MAX_JSON_SAFE_VALUE_ITEMS)
190
+ let index = 0
191
+ for (; index < itemCount && state.remainingNodes > 0; index++) {
192
+ try {
193
+ const element = index in values ? values[index] : undefined
194
+ // Dropped, as iOS and Android do: proto3 JSON has no null AnyValue, and
195
+ // both `null` and `{}` here are rejected for the whole request.
196
+ if (isNullish(element)) {
197
+ continue
198
+ }
199
+ result.push(encodeAnyValue(element as LogAttributeValue, logger, state, depth))
200
+ } catch {
201
+ result.push({ stringValue: UNSERIALIZABLE_VALUE })
202
+ }
203
+ }
204
+ if (values.length > index) {
205
+ result.push({ stringValue: TRUNCATED_VALUE })
206
+ }
207
+ return result
75
208
  }
76
209
 
77
- export function toOtlpKeyValueList(attrs: Record<string, LogAttributeValue>): OtlpKeyValue[] {
210
+ function encodeKeyValueList(
211
+ attrs: Record<string, LogAttributeValue>,
212
+ logger: Logger | undefined,
213
+ state: EncodeState,
214
+ depth: number
215
+ ): OtlpKeyValue[] {
78
216
  const result: OtlpKeyValue[] = []
79
217
  for (const key in attrs) {
80
- const value = attrs[key]
81
- if (isNull(value) || isUndefined(value)) {
218
+ // for...in walks the prototype chain once own keys are exhausted. Skipped
219
+ // rather than broken out of: a proxy can yield keys in any order.
220
+ if (!propertyIsEnumerable.call(attrs, key)) {
82
221
  continue
83
222
  }
84
- result.push({ key, value: toOtlpAnyValue(value) })
223
+ if (result.length >= MAX_JSON_SAFE_VALUE_ITEMS || state.remainingNodes <= 0) {
224
+ // Reported rather than written into the attributes: a synthetic key would
225
+ // land in the user's own namespace and could collide with a real one.
226
+ logger?.debug('Attributes truncated: the value exceeds the OTLP encoder budget')
227
+ break
228
+ }
229
+ try {
230
+ const value = attrs[key]
231
+ if (isNull(value) || isUndefined(value)) {
232
+ continue
233
+ }
234
+ result.push({ key: sanitizeString(key), value: encodeAnyValue(value, logger, state, depth) })
235
+ } catch {
236
+ // A getter that throws costs its own key, not the whole record.
237
+ result.push({ key: sanitizeString(key), value: { stringValue: UNSERIALIZABLE_VALUE } })
238
+ }
85
239
  }
86
240
  return result
87
241
  }
@@ -111,7 +265,22 @@ function timestampToUnixNano(): string {
111
265
  *
112
266
  * User-provided `options.attributes` always wins on conflicts.
113
267
  */
114
- export function buildOtlpLogRecord(options: CaptureLogOptions, sdkContext: LogSdkContext): OtlpLogRecord {
268
+ // `body` is only typed as a string. An untyped caller — or a `beforeSend` that
269
+ // rewrites it — can pass anything, and `String()` throws on a value whose
270
+ // `toString` does, or on a null-prototype object.
271
+ function encodeBody(body: string): string {
272
+ try {
273
+ return sanitizeString(String(body))
274
+ } catch {
275
+ return UNSERIALIZABLE_VALUE
276
+ }
277
+ }
278
+
279
+ export function buildOtlpLogRecord(
280
+ options: CaptureLogOptions,
281
+ sdkContext: LogSdkContext,
282
+ logger?: Logger
283
+ ): OtlpLogRecord {
115
284
  const level: LogSeverityLevel = options.level || 'info'
116
285
  const { text: severityText, number: severityNumber } = OTLP_SEVERITY_MAP[level] || DEFAULT_OTLP_SEVERITY
117
286
  const now = timestampToUnixNano()
@@ -146,9 +315,28 @@ export function buildOtlpLogRecord(options: CaptureLogOptions, sdkContext: LogSd
146
315
  autoAttributes.feature_flags = sdkContext.activeFeatureFlags
147
316
  }
148
317
 
149
- const mergedAttributes = {
150
- ...autoAttributes,
151
- ...(options.attributes || {}),
318
+ // Read key by key rather than spreading: a getter over a disposed store or a
319
+ // revoked proxy throws on the read itself, before the encoder's guards see it.
320
+ const mergedAttributes: Record<string, LogAttributeValue> = { ...autoAttributes }
321
+ const userAttributes = options.attributes
322
+ if (userAttributes) {
323
+ let keys: string[] = []
324
+ try {
325
+ keys = Object.keys(userAttributes)
326
+ } catch {
327
+ keys = []
328
+ }
329
+ for (const key of keys) {
330
+ let value: LogAttributeValue
331
+ try {
332
+ value = userAttributes[key]
333
+ } catch {
334
+ value = UNSERIALIZABLE_VALUE
335
+ }
336
+ // defineProperty, not assignment: `attributes['__proto__'] = v` hits the
337
+ // prototype setter and the attribute vanishes.
338
+ Object.defineProperty(mergedAttributes, key, { value, enumerable: true, writable: true, configurable: true })
339
+ }
152
340
  }
153
341
 
154
342
  const record: OtlpLogRecord = {
@@ -156,8 +344,8 @@ export function buildOtlpLogRecord(options: CaptureLogOptions, sdkContext: LogSd
156
344
  observedTimeUnixNano: now,
157
345
  severityNumber,
158
346
  severityText,
159
- body: { stringValue: options.body },
160
- attributes: toOtlpKeyValueList(mergedAttributes),
347
+ body: { stringValue: encodeBody(options.body) },
348
+ attributes: toOtlpKeyValueList(mergedAttributes, logger),
161
349
  }
162
350
 
163
351
  if (options.trace_id) {
@@ -169,10 +169,24 @@ describe('PostHogMetrics', () => {
169
169
 
170
170
  const attrs = sentMetrics()[0].sum!.dataPoints[0].attributes
171
171
  expect(attrs).toContainEqual({ key: 'route', value: { stringValue: '/home' } })
172
- expect(attrs).toContainEqual({ key: 'retries', value: { intValue: 2 } })
172
+ expect(attrs).toContainEqual({ key: 'retries', value: { intValue: '2' } })
173
173
  expect(attrs).toContainEqual({ key: 'cached', value: { boolValue: true } })
174
174
  })
175
175
 
176
+ // The encoder is shared with logs, so the debug line it emits on the
177
+ // out-of-range path only reaches anyone if metrics passes its logger down.
178
+ it('encodes an out-of-int64 attribute as a string and reports it through the logger', async () => {
179
+ const metrics = createMetrics()
180
+ metrics.count('api_calls', 1, { attributes: { huge: 2 ** 63 } as any })
181
+ await metrics.flush()
182
+
183
+ const attrs = sentMetrics()[0].sum!.dataPoints[0].attributes
184
+ expect(attrs).toContainEqual({ key: 'huge', value: { stringValue: '9223372036854775808' } })
185
+ expect((logger.debug as jest.Mock).mock.calls.some((c) => String(c[0]).includes('outside the int64 range'))).toBe(
186
+ true
187
+ )
188
+ })
189
+
176
190
  it('stamps delta data points with a window: startTimeUnixNano <= timeUnixNano, both nano strings', async () => {
177
191
  const metrics = createMetrics()
178
192
  metrics.count('orders_created', 1)
@@ -374,7 +374,7 @@ export class PostHogMetrics {
374
374
  byMetric.set(metricKey, metric)
375
375
  }
376
376
 
377
- const attributes = toOtlpKeyValueList(state.attributes ?? {})
377
+ const attributes = toOtlpKeyValueList(state.attributes ?? {}, this._logger)
378
378
  const startNano = msToUnixNano(state.windowStartMs)
379
379
 
380
380
  if (state.type === 'count') {
@@ -17,6 +17,7 @@ import {
17
17
  FeatureFlagDetail,
18
18
  SurveyResponse,
19
19
  PostHogFetchResponse,
20
+ PostHogFetchBodyBytes,
20
21
  PostHogFetchOptions,
21
22
  PostHogPersistedProperty,
22
23
  PostHogQueueItem,
@@ -221,13 +222,12 @@ function isPostHogEventProperties(value: JsonType | undefined): value is PostHog
221
222
  }
222
223
 
223
224
  /**
224
- * Outcome of a logs batch send. Keeps HTTP error classification inside core
225
- * (single source of truth — same policy events already use in `_flush()`) so
225
+ * Outcome of a logs batch send. Keeps HTTP error classification inside core so
226
226
  * PostHogLogs doesn't need to know about specific error types.
227
227
  *
228
228
  * - ok → records are accepted; drop them from the queue
229
229
  * - too-large → 413; caller should halve batch size and retry same records
230
- * - retry-later → network error; caller keeps records and retries next cycle
230
+ * - retry-later → retryable network or HTTP error; caller keeps records and retries next cycle
231
231
  * - fatal → anything else (auth, malformed, etc.); caller drops the
232
232
  * batch and surfaces the error
233
233
  */
@@ -237,6 +237,17 @@ export type SendLogsBatchOutcome =
237
237
  | { kind: 'retry-later'; error: unknown }
238
238
  | { kind: 'fatal'; error: unknown }
239
239
 
240
+ /**
241
+ * Each signal keeps its own exported outcome type because each belongs to a
242
+ * separate host contract. The wrappers return this value directly, so one
243
+ * drifting out of shape fails to compile.
244
+ */
245
+ type SendOtlpBatchOutcome =
246
+ | { kind: 'ok' }
247
+ | { kind: 'too-large' }
248
+ | { kind: 'retry-later'; error: unknown }
249
+ | { kind: 'fatal'; error: unknown }
250
+
240
251
  export enum QuotaLimitedFeature {
241
252
  FeatureFlags = 'feature_flags',
242
253
  Recordings = 'recordings',
@@ -1447,7 +1458,7 @@ export abstract class PostHogCoreStateless {
1447
1458
  * Compresses an outgoing payload. Runtime-specific clients can override this
1448
1459
  * to avoid using the Web Streams compression implementation.
1449
1460
  */
1450
- protected compressPayload(payload: string): Promise<Blob | null> {
1461
+ protected compressPayload(payload: string): Promise<Blob | PostHogFetchBodyBytes | null> {
1451
1462
  return gzipCompress(payload, this.isDebug)
1452
1463
  }
1453
1464
 
@@ -1632,22 +1643,28 @@ export abstract class PostHogCoreStateless {
1632
1643
  }
1633
1644
 
1634
1645
  /**
1635
- * Sends a pre-built OTLP logs payload to `/i/v1/logs`. Returns a tagged
1636
- * outcome instead of throwing so PostHogLogs doesn't have to know about the
1637
- * core's error class hierarchy. Error classification lives here (single
1638
- * source of truth, same policy the events `_flush()` uses for its own
1639
- * 413 / network / fatal handling).
1646
+ * Shared implementation behind the OTLP senders, which differ only in path.
1647
+ * Returns a tagged outcome instead of throwing so the queue owners don't
1648
+ * have to know the core's error class hierarchy.
1640
1649
  *
1641
- * 413 is passed through as `too-large` (not auto-retried) so the caller can
1642
- * shrink `maxBatchRecordsPerPost` and retry the same records.
1650
+ * Exhausted 408/429/5xx stay `retry-later`, unlike the events `_flush()`
1651
+ * which drops anything that isn't a network error: every OTLP queue is
1652
+ * bounded and retried with backoff, so holding a batch through an outage can
1653
+ * neither grow without limit nor spin.
1643
1654
  */
1644
- async _sendLogsBatch(payload: OtlpLogsPayload): Promise<SendLogsBatchOutcome> {
1655
+ private async _sendOtlpBatch({
1656
+ path,
1657
+ payload,
1658
+ }: {
1659
+ path: 'logs' | 'metrics'
1660
+ payload: OtlpLogsPayload | OtlpMetricsPayload
1661
+ }): Promise<SendOtlpBatchOutcome> {
1645
1662
  if (this.disabled) {
1646
1663
  return { kind: 'fatal', error: new Error('The client is disabled') }
1647
1664
  }
1648
1665
 
1649
1666
  const serialized = JSON.stringify(payload)
1650
- const url = `${this.host}/i/v1/logs?token=${encodeURIComponent(this.apiKey)}`
1667
+ const url = `${this.host}/i/v1/${path}?token=${encodeURIComponent(this.apiKey)}`
1651
1668
 
1652
1669
  const gzippedPayload = !this.disableCompression ? await this.compressPayload(serialized) : null
1653
1670
  const fetchOptions: PostHogFetchOptions = {
@@ -1679,65 +1696,19 @@ export abstract class PostHogCoreStateless {
1679
1696
  if (isPostHogFetchContentTooLargeError(err)) {
1680
1697
  return { kind: 'too-large' }
1681
1698
  }
1682
- if (err instanceof PostHogFetchNetworkError) {
1699
+ if (isPostHogFetchRetryableError(err)) {
1683
1700
  return { kind: 'retry-later', error: err }
1684
1701
  }
1685
1702
  return { kind: 'fatal', error: err }
1686
1703
  }
1687
1704
  }
1688
1705
 
1689
- /**
1690
- * Sends a pre-built OTLP metrics payload to `/i/v1/metrics`. Same tagged
1691
- * outcome contract and error classification as `_sendLogsBatch` — this is
1692
- * the `MetricsHost._sendMetricsBatch` implementation, so `PostHogMetrics`
1693
- * can use any core-based SDK as its host.
1694
- */
1695
- async _sendMetricsBatch(payload: OtlpMetricsPayload): Promise<SendMetricsBatchOutcome> {
1696
- if (this.disabled) {
1697
- return { kind: 'fatal', error: new Error('The client is disabled') }
1698
- }
1699
-
1700
- const serialized = JSON.stringify(payload)
1701
- const url = `${this.host}/i/v1/metrics?token=${encodeURIComponent(this.apiKey)}`
1702
-
1703
- const gzippedPayload = !this.disableCompression ? await this.compressPayload(serialized) : null
1704
- const fetchOptions: PostHogFetchOptions = {
1705
- method: 'POST',
1706
- headers: {
1707
- ...this.getCustomHeaders(),
1708
- 'Content-Type': 'application/json',
1709
- ...(gzippedPayload !== null && { 'Content-Encoding': 'gzip' }),
1710
- },
1711
- body: gzippedPayload || serialized,
1712
- }
1706
+ async _sendLogsBatch(payload: OtlpLogsPayload): Promise<SendLogsBatchOutcome> {
1707
+ return this._sendOtlpBatch({ path: 'logs', payload })
1708
+ }
1713
1709
 
1714
- try {
1715
- await this.fetchWithRetry(
1716
- url,
1717
- fetchOptions,
1718
- { type: 'successful-write' },
1719
- {
1720
- retryCheck: (err) => {
1721
- if (isPostHogFetchContentTooLargeError(err)) {
1722
- return false
1723
- }
1724
- return isPostHogFetchRetryableError(err)
1725
- },
1726
- }
1727
- )
1728
- return { kind: 'ok' }
1729
- } catch (err) {
1730
- if (isPostHogFetchContentTooLargeError(err)) {
1731
- return { kind: 'too-large' }
1732
- }
1733
- // Exhausted retries on a retryable failure (network error, 408/429/5xx)
1734
- // still classify as retry-later so the window rides the next flush; only
1735
- // non-retryable HTTP errors (and 413 above) drop the batch.
1736
- if (isPostHogFetchRetryableError(err)) {
1737
- return { kind: 'retry-later', error: err }
1738
- }
1739
- return { kind: 'fatal', error: err }
1740
- }
1710
+ async _sendMetricsBatch(payload: OtlpMetricsPayload): Promise<SendMetricsBatchOutcome> {
1711
+ return this._sendOtlpBatch({ path: 'metrics', payload })
1741
1712
  }
1742
1713
 
1743
1714
  private fetchWithRetry<T>(
@@ -1766,12 +1737,16 @@ export abstract class PostHogCoreStateless {
1766
1737
  try {
1767
1738
  if (body instanceof Blob) {
1768
1739
  reqByteLength = body.size
1740
+ } else if (body instanceof Uint8Array) {
1741
+ reqByteLength = body.byteLength
1769
1742
  } else {
1770
1743
  reqByteLength = Buffer.byteLength(body, STRING_FORMAT)
1771
1744
  }
1772
1745
  } catch {
1773
1746
  if (body instanceof Blob) {
1774
1747
  reqByteLength = body.size
1748
+ } else if (body instanceof Uint8Array) {
1749
+ reqByteLength = body.byteLength
1775
1750
  } else {
1776
1751
  const encoded = new TextEncoder().encode(body)
1777
1752
  reqByteLength = encoded.length
@@ -53,8 +53,11 @@ interface FlagsAsyncOptions {
53
53
  }
54
54
 
55
55
  interface PendingFlagsRequest extends FlagsAsyncOptions {
56
- resolve: (value: PostHogFeatureFlagsResponse | undefined) => void
57
- reject: (reason?: unknown) => void
56
+ // every caller displaced from this slot, so none is settled against a request it did not make
57
+ waiters: {
58
+ resolve: (value: PostHogFeatureFlagsResponse | undefined) => void
59
+ reject: (reason?: unknown) => void
60
+ }[]
58
61
  }
59
62
 
60
63
  export abstract class PostHogCore extends PostHogCoreStateless {
@@ -651,16 +654,20 @@ export abstract class PostHogCore extends PostHogCoreStateless {
651
654
  return undefined
652
655
  }
653
656
  if (this._flagsResponsePromise) {
654
- // Queue the reload request instead of dropping it
655
- // This ensures that requests with $anon_distinct_id (from identify()) are not lost
657
+ // Queue rather than drop, so an identity-changing reload still reaches the server. Displaced
658
+ // callers are carried over rather than settled against the in-flight request: that request
659
+ // was issued before their context changed, so it cannot reflect it. Options are merged so
660
+ // the single queued request satisfies every caller behind it — one caller asking for the
661
+ // remote config or for $anon_distinct_id is enough for the re-issued request to carry it.
656
662
  this._logger.info('Feature flags are being loaded already, queuing reload.')
657
- // Resolve any existing pending promise with the in-flight request's result to avoid hanging promises
658
- if (this._pendingFlagsRequest) {
659
- this._flagsResponsePromise.then(this._pendingFlagsRequest.resolve).catch(this._pendingFlagsRequest.reject)
660
- }
661
- // Return a promise that resolves when the pending request completes
663
+ const pending = this._pendingFlagsRequest
662
664
  return new Promise((resolve, reject) => {
663
- this._pendingFlagsRequest = { sendAnonDistinctId, fetchConfig, triggerOnRemoteConfig, resolve, reject }
665
+ this._pendingFlagsRequest = {
666
+ sendAnonDistinctId: sendAnonDistinctId || !!pending?.sendAnonDistinctId,
667
+ fetchConfig: fetchConfig || !!pending?.fetchConfig,
668
+ triggerOnRemoteConfig: triggerOnRemoteConfig || !!pending?.triggerOnRemoteConfig,
669
+ waiters: [...(pending?.waiters ?? []), { resolve, reject }],
670
+ }
664
671
  })
665
672
  }
666
673
  return this._flagsAsync({ sendAnonDistinctId, fetchConfig, triggerOnRemoteConfig })
@@ -911,8 +918,8 @@ export abstract class PostHogCore extends PostHogCoreStateless {
911
918
  fetchConfig: pendingRequest.fetchConfig,
912
919
  triggerOnRemoteConfig: pendingRequest.triggerOnRemoteConfig,
913
920
  })
914
- .then(pendingRequest.resolve)
915
- .catch(pendingRequest.reject)
921
+ .then((res) => pendingRequest.waiters.forEach((w) => w.resolve(res)))
922
+ .catch((e) => pendingRequest.waiters.forEach((w) => w.reject(e)))
916
923
  }
917
924
  })
918
925
  return this._flagsResponsePromise
@@ -299,12 +299,14 @@ export enum PostHogPersistedProperty {
299
299
  DeviceId = 'device_id', // only used by posthog-react-native
300
300
  }
301
301
 
302
+ export type PostHogFetchBodyBytes = Uint8Array & { buffer: ArrayBuffer }
303
+
302
304
  export type PostHogFetchOptions = {
303
305
  method: 'GET' | 'POST' | 'PUT' | 'PATCH'
304
306
  mode?: 'no-cors'
305
307
  credentials?: 'omit'
306
308
  headers: { [key: string]: string }
307
- body?: string | Blob
309
+ body?: string | Blob | PostHogFetchBodyBytes
308
310
  signal?: AbortSignal
309
311
  }
310
312
 
@@ -3,7 +3,9 @@ import { FetchLike } from '../types'
3
3
  export * from './bot-detection'
4
4
  export * from './browser-utils'
5
5
  export * from './bucketed-rate-limiter'
6
- export * from './json-utils'
6
+ // Named rather than `export *`: the budgets, markers and `sanitizeString` are
7
+ // shared with the OTLP encoder but are not public API.
8
+ export { toJsonSafeValue } from './json-utils'
7
9
  export * from './number-utils'
8
10
  export * from './string-utils'
9
11
  export * from './type-utils'
@@ -1,10 +1,12 @@
1
- const MAX_JSON_SAFE_VALUE_DEPTH = 20
2
- const MAX_JSON_SAFE_VALUE_ITEMS = 1_000
3
- const MAX_JSON_SAFE_VALUE_NODES = 10_000
4
- const CIRCULAR_VALUE = '[Circular]'
5
- const TRUNCATED_VALUE = '[Truncated]'
6
- const UNSERIALIZABLE_VALUE = '[Unserializable]'
7
- const FUNCTION_VALUE = '[Function]'
1
+ /** Traversal budgets and markers, shared with the OTLP attribute encoder. Not
2
+ * public API — `utils/index.ts` re-exports `toJsonSafeValue` only. */
3
+ export const MAX_JSON_SAFE_VALUE_DEPTH = 20
4
+ export const MAX_JSON_SAFE_VALUE_ITEMS = 1_000
5
+ export const MAX_JSON_SAFE_VALUE_NODES = 10_000
6
+ export const CIRCULAR_VALUE = '[Circular]'
7
+ export const TRUNCATED_VALUE = '[Truncated]'
8
+ export const UNSERIALIZABLE_VALUE = '[Unserializable]'
9
+ export const FUNCTION_VALUE = '[Function]'
8
10
 
9
11
  const dateGetTime = Date.prototype.getTime
10
12
  const dateToISOString = Date.prototype.toISOString
@@ -15,7 +17,12 @@ interface JsonSafeValueConversionState {
15
17
  remainingNodes: number
16
18
  }
17
19
 
18
- function sanitizeString(value: string): string {
20
+ /**
21
+ * Replaces unpaired surrogates with U+FFFD. A lone surrogate survives
22
+ * `JSON.stringify` as a `\uD800`-style escape, which strict JSON parsers
23
+ * reject — for OTLP that means the whole request is refused.
24
+ */
25
+ export function sanitizeString(value: string): string {
19
26
  let output = ''
20
27
  for (let index = 0; index < value.length; index++) {
21
28
  const codeUnit = value.charCodeAt(index)
@@ -66,12 +66,21 @@ export interface Logger {
66
66
  }
67
67
  export interface OtlpAnyValue {
68
68
  stringValue?: string;
69
- intValue?: number;
69
+ /**
70
+ * proto3 JSON maps int64 to a string, which is the form the SDK emits.
71
+ * `number` stays valid because encoded records persist in the logs queue:
72
+ * one written by an earlier version rehydrates in the numeric form and is
73
+ * re-sent unchanged. The wire format accepts both.
74
+ */
75
+ intValue?: string | number;
70
76
  doubleValue?: number;
71
77
  boolValue?: boolean;
72
78
  arrayValue?: {
73
79
  values: OtlpAnyValue[];
74
80
  };
81
+ kvlistValue?: {
82
+ values: OtlpKeyValue[];
83
+ };
75
84
  }
76
85
  export interface OtlpKeyValue {
77
86
  key: string;
@@ -1 +1 @@
1
- {"version":3,"file":"capture-log.d.ts","sourceRoot":"","sources":["../src/capture-log.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capture-log.d.ts","sourceRoot":"","sources":["../src/capture-log.ts"],"names":[],"mappings":"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"}