@37signals/fizzy 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/dist/auth/cookie-auth.d.ts +25 -0
  2. package/dist/auth/cookie-auth.d.ts.map +1 -0
  3. package/dist/auth/cookie-auth.js +29 -0
  4. package/dist/auth/cookie-auth.js.map +1 -0
  5. package/dist/auth/magic-link.d.ts +66 -0
  6. package/dist/auth/magic-link.d.ts.map +1 -0
  7. package/dist/auth/magic-link.js +78 -0
  8. package/dist/auth/magic-link.js.map +1 -0
  9. package/dist/auth-strategy.d.ts +32 -0
  10. package/dist/auth-strategy.d.ts.map +1 -0
  11. package/dist/auth-strategy.js +29 -0
  12. package/dist/auth-strategy.js.map +1 -0
  13. package/dist/cache/etag-cache.d.ts +49 -0
  14. package/dist/cache/etag-cache.d.ts.map +1 -0
  15. package/dist/cache/etag-cache.js +95 -0
  16. package/dist/cache/etag-cache.js.map +1 -0
  17. package/dist/client.d.ts +92 -0
  18. package/dist/client.d.ts.map +1 -0
  19. package/dist/client.js +505 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/errors.d.ts +68 -0
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/errors.js +187 -0
  24. package/dist/errors.js.map +1 -0
  25. package/dist/generated/metadata.json +1272 -0
  26. package/dist/generated/openapi-stripped.json +12446 -0
  27. package/dist/generated/path-mapping.d.ts +8 -0
  28. package/dist/generated/path-mapping.d.ts.map +1 -0
  29. package/dist/generated/path-mapping.js +124 -0
  30. package/dist/generated/path-mapping.js.map +1 -0
  31. package/dist/generated/path-mapping.ts +135 -0
  32. package/dist/generated/schema.d.ts +10272 -0
  33. package/dist/generated/services/boards.d.ts +56 -0
  34. package/dist/generated/services/boards.d.ts.map +1 -0
  35. package/dist/generated/services/boards.js +100 -0
  36. package/dist/generated/services/boards.js.map +1 -0
  37. package/dist/generated/services/boards.ts +152 -0
  38. package/dist/generated/services/cards.d.ts +164 -0
  39. package/dist/generated/services/cards.d.ts.map +1 -0
  40. package/dist/generated/services/cards.js +353 -0
  41. package/dist/generated/services/cards.js.map +1 -0
  42. package/dist/generated/services/cards.ts +522 -0
  43. package/dist/generated/services/columns.d.ts +45 -0
  44. package/dist/generated/services/columns.d.ts.map +1 -0
  45. package/dist/generated/services/columns.js +77 -0
  46. package/dist/generated/services/columns.js.map +1 -0
  47. package/dist/generated/services/columns.ts +116 -0
  48. package/dist/generated/services/comments.d.ts +42 -0
  49. package/dist/generated/services/comments.d.ts.map +1 -0
  50. package/dist/generated/services/comments.js +77 -0
  51. package/dist/generated/services/comments.js.map +1 -0
  52. package/dist/generated/services/comments.ts +114 -0
  53. package/dist/generated/services/devices.d.ts +24 -0
  54. package/dist/generated/services/devices.d.ts.map +1 -0
  55. package/dist/generated/services/devices.js +36 -0
  56. package/dist/generated/services/devices.js.map +1 -0
  57. package/dist/generated/services/devices.ts +53 -0
  58. package/dist/generated/services/identity.d.ts +16 -0
  59. package/dist/generated/services/identity.d.ts.map +1 -0
  60. package/dist/generated/services/identity.js +21 -0
  61. package/dist/generated/services/identity.js.map +1 -0
  62. package/dist/generated/services/identity.ts +30 -0
  63. package/dist/generated/services/index.d.ts +17 -0
  64. package/dist/generated/services/index.d.ts.map +1 -0
  65. package/dist/generated/services/index.js +17 -0
  66. package/dist/generated/services/index.js.map +1 -0
  67. package/dist/generated/services/index.ts +16 -0
  68. package/dist/generated/services/miscellaneous.d.ts +136 -0
  69. package/dist/generated/services/miscellaneous.d.ts.map +1 -0
  70. package/dist/generated/services/miscellaneous.js +301 -0
  71. package/dist/generated/services/miscellaneous.js.map +1 -0
  72. package/dist/generated/services/miscellaneous.ts +443 -0
  73. package/dist/generated/services/notifications.d.ts +42 -0
  74. package/dist/generated/services/notifications.d.ts.map +1 -0
  75. package/dist/generated/services/notifications.js +75 -0
  76. package/dist/generated/services/notifications.js.map +1 -0
  77. package/dist/generated/services/notifications.ts +113 -0
  78. package/dist/generated/services/pins.d.ts +16 -0
  79. package/dist/generated/services/pins.d.ts.map +1 -0
  80. package/dist/generated/services/pins.js +21 -0
  81. package/dist/generated/services/pins.js.map +1 -0
  82. package/dist/generated/services/pins.ts +29 -0
  83. package/dist/generated/services/reactions.d.ts +45 -0
  84. package/dist/generated/services/reactions.d.ts.map +1 -0
  85. package/dist/generated/services/reactions.js +90 -0
  86. package/dist/generated/services/reactions.js.map +1 -0
  87. package/dist/generated/services/reactions.ts +129 -0
  88. package/dist/generated/services/sessions.d.ts +44 -0
  89. package/dist/generated/services/sessions.d.ts.map +1 -0
  90. package/dist/generated/services/sessions.js +73 -0
  91. package/dist/generated/services/sessions.js.map +1 -0
  92. package/dist/generated/services/sessions.ts +113 -0
  93. package/dist/generated/services/steps.d.ts +43 -0
  94. package/dist/generated/services/steps.d.ts.map +1 -0
  95. package/dist/generated/services/steps.js +77 -0
  96. package/dist/generated/services/steps.js.map +1 -0
  97. package/dist/generated/services/steps.ts +114 -0
  98. package/dist/generated/services/tags.d.ts +17 -0
  99. package/dist/generated/services/tags.d.ts.map +1 -0
  100. package/dist/generated/services/tags.js +21 -0
  101. package/dist/generated/services/tags.js.map +1 -0
  102. package/dist/generated/services/tags.ts +32 -0
  103. package/dist/generated/services/uploads.d.ts +22 -0
  104. package/dist/generated/services/uploads.d.ts.map +1 -0
  105. package/dist/generated/services/uploads.js +23 -0
  106. package/dist/generated/services/uploads.js.map +1 -0
  107. package/dist/generated/services/uploads.ts +38 -0
  108. package/dist/generated/services/users.d.ts +33 -0
  109. package/dist/generated/services/users.d.ts.map +1 -0
  110. package/dist/generated/services/users.js +61 -0
  111. package/dist/generated/services/users.js.map +1 -0
  112. package/dist/generated/services/users.ts +89 -0
  113. package/dist/generated/services/webhooks.d.ts +49 -0
  114. package/dist/generated/services/webhooks.d.ts.map +1 -0
  115. package/dist/generated/services/webhooks.js +90 -0
  116. package/dist/generated/services/webhooks.js.map +1 -0
  117. package/dist/generated/services/webhooks.ts +133 -0
  118. package/dist/hooks/gating.d.ts +35 -0
  119. package/dist/hooks/gating.d.ts.map +1 -0
  120. package/dist/hooks/gating.js +58 -0
  121. package/dist/hooks/gating.js.map +1 -0
  122. package/dist/hooks/otel.d.ts +49 -0
  123. package/dist/hooks/otel.d.ts.map +1 -0
  124. package/dist/hooks/otel.js +171 -0
  125. package/dist/hooks/otel.js.map +1 -0
  126. package/dist/hooks.d.ts +99 -0
  127. package/dist/hooks.d.ts.map +1 -0
  128. package/dist/hooks.js +130 -0
  129. package/dist/hooks.js.map +1 -0
  130. package/dist/index.d.ts +64 -0
  131. package/dist/index.d.ts.map +1 -0
  132. package/dist/index.js +97 -0
  133. package/dist/index.js.map +1 -0
  134. package/dist/pagination-utils.d.ts +22 -0
  135. package/dist/pagination-utils.d.ts.map +1 -0
  136. package/dist/pagination-utils.js +52 -0
  137. package/dist/pagination-utils.js.map +1 -0
  138. package/dist/pagination.d.ts +37 -0
  139. package/dist/pagination.d.ts.map +1 -0
  140. package/dist/pagination.js +30 -0
  141. package/dist/pagination.js.map +1 -0
  142. package/dist/resilience/bulkhead.d.ts +34 -0
  143. package/dist/resilience/bulkhead.d.ts.map +1 -0
  144. package/dist/resilience/bulkhead.js +65 -0
  145. package/dist/resilience/bulkhead.js.map +1 -0
  146. package/dist/resilience/circuit-breaker.d.ts +48 -0
  147. package/dist/resilience/circuit-breaker.d.ts.map +1 -0
  148. package/dist/resilience/circuit-breaker.js +74 -0
  149. package/dist/resilience/circuit-breaker.js.map +1 -0
  150. package/dist/resilience/index.d.ts +41 -0
  151. package/dist/resilience/index.d.ts.map +1 -0
  152. package/dist/resilience/index.js +46 -0
  153. package/dist/resilience/index.js.map +1 -0
  154. package/dist/resilience/rate-limiter.d.ts +38 -0
  155. package/dist/resilience/rate-limiter.d.ts.map +1 -0
  156. package/dist/resilience/rate-limiter.js +69 -0
  157. package/dist/resilience/rate-limiter.js.map +1 -0
  158. package/dist/security.d.ts +19 -0
  159. package/dist/security.d.ts.map +1 -0
  160. package/dist/security.js +55 -0
  161. package/dist/security.js.map +1 -0
  162. package/dist/services/base.d.ts +51 -0
  163. package/dist/services/base.d.ts.map +1 -0
  164. package/dist/services/base.js +146 -0
  165. package/dist/services/base.js.map +1 -0
  166. package/dist/webhooks/handler.d.ts +62 -0
  167. package/dist/webhooks/handler.d.ts.map +1 -0
  168. package/dist/webhooks/handler.js +204 -0
  169. package/dist/webhooks/handler.js.map +1 -0
  170. package/dist/webhooks/index.d.ts +3 -0
  171. package/dist/webhooks/index.d.ts.map +1 -0
  172. package/dist/webhooks/index.js +3 -0
  173. package/dist/webhooks/index.js.map +1 -0
  174. package/dist/webhooks/verify.d.ts +10 -0
  175. package/dist/webhooks/verify.d.ts.map +1 -0
  176. package/dist/webhooks/verify.js +23 -0
  177. package/dist/webhooks/verify.js.map +1 -0
  178. package/package.json +67 -0
  179. package/src/generated/metadata.json +1272 -0
  180. package/src/generated/openapi-stripped.json +12446 -0
  181. package/src/generated/path-mapping.ts +135 -0
  182. package/src/generated/schema.d.ts +10272 -0
  183. package/src/generated/services/boards.ts +152 -0
  184. package/src/generated/services/cards.ts +522 -0
  185. package/src/generated/services/columns.ts +116 -0
  186. package/src/generated/services/comments.ts +114 -0
  187. package/src/generated/services/devices.ts +53 -0
  188. package/src/generated/services/identity.ts +30 -0
  189. package/src/generated/services/index.ts +16 -0
  190. package/src/generated/services/miscellaneous.ts +443 -0
  191. package/src/generated/services/notifications.ts +113 -0
  192. package/src/generated/services/pins.ts +29 -0
  193. package/src/generated/services/reactions.ts +129 -0
  194. package/src/generated/services/sessions.ts +113 -0
  195. package/src/generated/services/steps.ts +114 -0
  196. package/src/generated/services/tags.ts +32 -0
  197. package/src/generated/services/uploads.ts +38 -0
  198. package/src/generated/services/users.ts +89 -0
  199. package/src/generated/services/webhooks.ts +133 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Circuit breaker for the Fizzy SDK.
3
+ *
4
+ * Prevents cascading failures by tracking error rates and temporarily
5
+ * stopping requests when the failure threshold is exceeded.
6
+ */
7
+ /**
8
+ * Circuit breaker implementation using the standard closed/open/half-open pattern.
9
+ */
10
+ export class CircuitBreaker {
11
+ state = "closed";
12
+ failureCount = 0;
13
+ successCount = 0;
14
+ lastFailureTime = 0;
15
+ failureThreshold;
16
+ resetTimeoutMs;
17
+ successThreshold;
18
+ constructor(options) {
19
+ this.failureThreshold = options?.failureThreshold ?? 5;
20
+ this.resetTimeoutMs = options?.resetTimeoutMs ?? 30_000;
21
+ this.successThreshold = options?.successThreshold ?? 1;
22
+ }
23
+ /** Current circuit state. */
24
+ get currentState() {
25
+ if (this.state === "open" && Date.now() - this.lastFailureTime >= this.resetTimeoutMs) {
26
+ this.state = "half-open";
27
+ }
28
+ return this.state;
29
+ }
30
+ /**
31
+ * Check if a request is allowed through the circuit.
32
+ * Returns true if the circuit is closed or half-open.
33
+ */
34
+ allowRequest() {
35
+ return this.currentState !== "open";
36
+ }
37
+ /**
38
+ * Record a successful request.
39
+ */
40
+ recordSuccess() {
41
+ if (this.state === "half-open") {
42
+ this.successCount++;
43
+ if (this.successCount >= this.successThreshold) {
44
+ this.state = "closed";
45
+ this.failureCount = 0;
46
+ this.successCount = 0;
47
+ }
48
+ }
49
+ else {
50
+ this.failureCount = 0;
51
+ }
52
+ }
53
+ /**
54
+ * Record a failed request.
55
+ */
56
+ recordFailure() {
57
+ this.failureCount++;
58
+ this.lastFailureTime = Date.now();
59
+ if (this.state === "half-open" || this.failureCount >= this.failureThreshold) {
60
+ this.state = "open";
61
+ this.successCount = 0;
62
+ }
63
+ }
64
+ /**
65
+ * Reset the circuit breaker to closed state.
66
+ */
67
+ reset() {
68
+ this.state = "closed";
69
+ this.failureCount = 0;
70
+ this.successCount = 0;
71
+ this.lastFailureTime = 0;
72
+ }
73
+ }
74
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/resilience/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH;;GAEG;AACH,MAAM,OAAO,cAAc;IACjB,KAAK,GAAiB,QAAQ,CAAC;IAC/B,YAAY,GAAG,CAAC,CAAC;IACjB,YAAY,GAAG,CAAC,CAAC;IACjB,eAAe,GAAG,CAAC,CAAC;IACX,gBAAgB,CAAS;IACzB,cAAc,CAAS;IACvB,gBAAgB,CAAS;IAE1C,YAAY,OAA+B;QACzC,IAAI,CAAC,gBAAgB,GAAG,OAAO,EAAE,gBAAgB,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,MAAM,CAAC;QACxD,IAAI,CAAC,gBAAgB,GAAG,OAAO,EAAE,gBAAgB,IAAI,CAAC,CAAC;IACzD,CAAC;IAED,6BAA6B;IAC7B,IAAI,YAAY;QACd,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACtF,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,YAAY,KAAK,MAAM,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,aAAa;QACX,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YAC/B,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC/C,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACtB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;gBACtB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa;QACX,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAElC,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC7E,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;YACpB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Resilience module for the Fizzy SDK.
3
+ *
4
+ * Composes circuit breaker, bulkhead, and rate limiter into a unified
5
+ * configuration and hooks integration.
6
+ */
7
+ import { CircuitBreaker, type CircuitBreakerOptions } from "./circuit-breaker.js";
8
+ import { Bulkhead, type BulkheadOptions } from "./bulkhead.js";
9
+ import { RateLimiter, type RateLimiterOptions } from "./rate-limiter.js";
10
+ import type { FizzyHooks } from "../hooks.js";
11
+ export { CircuitBreaker, type CircuitBreakerOptions } from "./circuit-breaker.js";
12
+ export { Bulkhead, type BulkheadOptions } from "./bulkhead.js";
13
+ export { RateLimiter, type RateLimiterOptions } from "./rate-limiter.js";
14
+ /**
15
+ * Unified resilience configuration.
16
+ */
17
+ export interface ResilienceConfig {
18
+ /** Circuit breaker options (false to disable) */
19
+ circuitBreaker?: CircuitBreakerOptions | false;
20
+ /** Bulkhead / concurrency limiter options (false to disable) */
21
+ bulkhead?: BulkheadOptions | false;
22
+ /** Rate limiter options (false to disable) */
23
+ rateLimiter?: RateLimiterOptions | false;
24
+ }
25
+ /**
26
+ * Active resilience components created from configuration.
27
+ */
28
+ export interface ResilienceComponents {
29
+ circuitBreaker?: CircuitBreaker;
30
+ bulkhead?: Bulkhead;
31
+ rateLimiter?: RateLimiter;
32
+ }
33
+ /**
34
+ * Create resilience components from configuration.
35
+ */
36
+ export declare function createResilienceComponents(config: ResilienceConfig): ResilienceComponents;
37
+ /**
38
+ * Creates FizzyHooks that track circuit breaker state from request results.
39
+ */
40
+ export declare function resilienceHooks(components: ResilienceComponents): FizzyHooks;
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resilience/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAA8B,MAAM,aAAa,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,cAAc,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IAC/C,gEAAgE;IAChE,QAAQ,CAAC,EAAE,eAAe,GAAG,KAAK,CAAC;IACnC,8CAA8C;IAC9C,WAAW,CAAC,EAAE,kBAAkB,GAAG,KAAK,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,gBAAgB,GAAG,oBAAoB,CAYzF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,oBAAoB,GAAG,UAAU,CAY5E"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Resilience module for the Fizzy SDK.
3
+ *
4
+ * Composes circuit breaker, bulkhead, and rate limiter into a unified
5
+ * configuration and hooks integration.
6
+ */
7
+ import { CircuitBreaker } from "./circuit-breaker.js";
8
+ import { Bulkhead } from "./bulkhead.js";
9
+ import { RateLimiter } from "./rate-limiter.js";
10
+ export { CircuitBreaker } from "./circuit-breaker.js";
11
+ export { Bulkhead } from "./bulkhead.js";
12
+ export { RateLimiter } from "./rate-limiter.js";
13
+ /**
14
+ * Create resilience components from configuration.
15
+ */
16
+ export function createResilienceComponents(config) {
17
+ return {
18
+ circuitBreaker: config.circuitBreaker !== false
19
+ ? new CircuitBreaker(config.circuitBreaker === undefined ? {} : config.circuitBreaker)
20
+ : undefined,
21
+ bulkhead: config.bulkhead !== false
22
+ ? new Bulkhead(config.bulkhead === undefined ? {} : config.bulkhead)
23
+ : undefined,
24
+ rateLimiter: config.rateLimiter !== false
25
+ ? new RateLimiter(config.rateLimiter === undefined ? {} : config.rateLimiter)
26
+ : undefined,
27
+ };
28
+ }
29
+ /**
30
+ * Creates FizzyHooks that track circuit breaker state from request results.
31
+ */
32
+ export function resilienceHooks(components) {
33
+ return {
34
+ onRequestEnd(_info, result) {
35
+ if (!components.circuitBreaker)
36
+ return;
37
+ if (result.statusCode >= 500) {
38
+ components.circuitBreaker.recordFailure();
39
+ }
40
+ else {
41
+ components.circuitBreaker.recordSuccess();
42
+ }
43
+ },
44
+ };
45
+ }
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resilience/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAA8B,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAwB,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AAGzE,OAAO,EAAE,cAAc,EAA8B,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAwB,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AAuBzE;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAwB;IACjE,OAAO;QACL,cAAc,EAAE,MAAM,CAAC,cAAc,KAAK,KAAK;YAC7C,CAAC,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC;YACtF,CAAC,CAAC,SAAS;QACb,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,KAAK;YACjC,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;YACpE,CAAC,CAAC,SAAS;QACb,WAAW,EAAE,MAAM,CAAC,WAAW,KAAK,KAAK;YACvC,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;YAC7E,CAAC,CAAC,SAAS;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,UAAgC;IAC9D,OAAO;QACL,YAAY,CAAC,KAAkB,EAAE,MAAqB;YACpD,IAAI,CAAC,UAAU,CAAC,cAAc;gBAAE,OAAO;YAEvC,IAAI,MAAM,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;gBAC7B,UAAU,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC;YAC5C,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC;YAC5C,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Token bucket rate limiter for the Fizzy SDK.
3
+ *
4
+ * Smooths request rates to stay within API rate limits.
5
+ * Tokens refill at a constant rate; each request consumes one token.
6
+ */
7
+ export interface RateLimiterOptions {
8
+ /** Maximum tokens in the bucket (default: 50) */
9
+ maxTokens?: number;
10
+ /** Token refill rate — tokens per second (default: 10) */
11
+ refillRate?: number;
12
+ }
13
+ /**
14
+ * Token bucket rate limiter.
15
+ */
16
+ export declare class RateLimiter {
17
+ private tokens;
18
+ private readonly maxTokens;
19
+ private readonly refillRate;
20
+ private lastRefillTime;
21
+ constructor(options?: RateLimiterOptions);
22
+ /** Current number of available tokens. */
23
+ get availableTokens(): number;
24
+ /**
25
+ * Try to consume a token. Returns true if a token was available.
26
+ */
27
+ tryAcquire(): boolean;
28
+ /**
29
+ * Wait until a token is available, then consume it.
30
+ */
31
+ acquire(): Promise<void>;
32
+ /**
33
+ * Estimated milliseconds until the next token becomes available.
34
+ */
35
+ msUntilNextToken(): number;
36
+ private refill;
37
+ }
38
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/resilience/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,CAAC,EAAE,kBAAkB;IAOxC,0CAA0C;IAC1C,IAAI,eAAe,IAAI,MAAM,CAG5B;IAED;;OAEG;IACH,UAAU,IAAI,OAAO;IASrB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAO1B,OAAO,CAAC,MAAM;CAUf"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Token bucket rate limiter for the Fizzy SDK.
3
+ *
4
+ * Smooths request rates to stay within API rate limits.
5
+ * Tokens refill at a constant rate; each request consumes one token.
6
+ */
7
+ /**
8
+ * Token bucket rate limiter.
9
+ */
10
+ export class RateLimiter {
11
+ tokens;
12
+ maxTokens;
13
+ refillRate;
14
+ lastRefillTime;
15
+ constructor(options) {
16
+ this.maxTokens = options?.maxTokens ?? 50;
17
+ this.refillRate = options?.refillRate ?? 10;
18
+ this.tokens = this.maxTokens;
19
+ this.lastRefillTime = Date.now();
20
+ }
21
+ /** Current number of available tokens. */
22
+ get availableTokens() {
23
+ this.refill();
24
+ return this.tokens;
25
+ }
26
+ /**
27
+ * Try to consume a token. Returns true if a token was available.
28
+ */
29
+ tryAcquire() {
30
+ this.refill();
31
+ if (this.tokens >= 1) {
32
+ this.tokens--;
33
+ return true;
34
+ }
35
+ return false;
36
+ }
37
+ /**
38
+ * Wait until a token is available, then consume it.
39
+ */
40
+ async acquire() {
41
+ if (this.tryAcquire())
42
+ return;
43
+ const waitMs = this.msUntilNextToken();
44
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
45
+ // Refill and take the token
46
+ this.refill();
47
+ this.tokens = Math.max(0, this.tokens - 1);
48
+ }
49
+ /**
50
+ * Estimated milliseconds until the next token becomes available.
51
+ */
52
+ msUntilNextToken() {
53
+ this.refill();
54
+ if (this.tokens >= 1)
55
+ return 0;
56
+ const deficit = 1 - this.tokens;
57
+ return Math.ceil((deficit / this.refillRate) * 1000);
58
+ }
59
+ refill() {
60
+ const now = Date.now();
61
+ const elapsed = (now - this.lastRefillTime) / 1000;
62
+ const newTokens = elapsed * this.refillRate;
63
+ if (newTokens > 0) {
64
+ this.tokens = Math.min(this.maxTokens, this.tokens + newTokens);
65
+ this.lastRefillTime = now;
66
+ }
67
+ }
68
+ }
69
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/resilience/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,MAAM,CAAS;IACN,SAAS,CAAS;IAClB,UAAU,CAAS;IAC5B,cAAc,CAAS;IAE/B,YAAY,OAA4B;QACtC,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACnC,CAAC;IAED,0CAA0C;IAC1C,IAAI,eAAe;QACjB,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO;QAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAE5D,4BAA4B;QAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QAChC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;IACvD,CAAC;IAEO,MAAM;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;QACnD,MAAM,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC;QAE5C,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;YAChE,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;QAC5B,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Security utilities for the Fizzy SDK.
3
+ *
4
+ * Provides helpers for safely logging HTTP requests without exposing
5
+ * sensitive information like tokens and cookies.
6
+ */
7
+ /**
8
+ * Returns a copy of the headers with sensitive values replaced by "[REDACTED]".
9
+ */
10
+ export declare function redactHeaders(headers: Headers): Record<string, string>;
11
+ /**
12
+ * Returns a copy of the header record with sensitive values replaced by "[REDACTED]".
13
+ */
14
+ export declare function redactHeadersRecord(headers: Record<string, string>): Record<string, string>;
15
+ /**
16
+ * Checks if a hostname represents localhost for development/testing purposes.
17
+ */
18
+ export declare function isLocalhost(hostname: string): boolean;
19
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAatE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAaxB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQrD"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Security utilities for the Fizzy SDK.
3
+ *
4
+ * Provides helpers for safely logging HTTP requests without exposing
5
+ * sensitive information like tokens and cookies.
6
+ */
7
+ const SENSITIVE_HEADERS = [
8
+ "authorization",
9
+ "cookie",
10
+ "set-cookie",
11
+ "x-csrf-token",
12
+ ];
13
+ /**
14
+ * Returns a copy of the headers with sensitive values replaced by "[REDACTED]".
15
+ */
16
+ export function redactHeaders(headers) {
17
+ const result = {};
18
+ headers.forEach((value, key) => {
19
+ const lowerKey = key.toLowerCase();
20
+ if (SENSITIVE_HEADERS.includes(lowerKey)) {
21
+ result[key] = "[REDACTED]";
22
+ }
23
+ else {
24
+ result[key] = value;
25
+ }
26
+ });
27
+ return result;
28
+ }
29
+ /**
30
+ * Returns a copy of the header record with sensitive values replaced by "[REDACTED]".
31
+ */
32
+ export function redactHeadersRecord(headers) {
33
+ const result = {};
34
+ for (const [key, value] of Object.entries(headers)) {
35
+ const lowerKey = key.toLowerCase();
36
+ if (SENSITIVE_HEADERS.includes(lowerKey)) {
37
+ result[key] = "[REDACTED]";
38
+ }
39
+ else {
40
+ result[key] = value;
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ /**
46
+ * Checks if a hostname represents localhost for development/testing purposes.
47
+ */
48
+ export function isLocalhost(hostname) {
49
+ const normalized = hostname.toLowerCase();
50
+ return (normalized === "localhost" ||
51
+ normalized === "127.0.0.1" ||
52
+ normalized === "::1" ||
53
+ normalized.endsWith(".localhost"));
54
+ }
55
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,iBAAiB,GAAG;IACxB,eAAe;IACf,QAAQ;IACR,YAAY;IACZ,cAAc;CACf,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC7B,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA+B;IAE/B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC1C,OAAO,CACL,UAAU,KAAK,WAAW;QAC1B,UAAU,KAAK,WAAW;QAC1B,UAAU,KAAK,KAAK;QACpB,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,CAClC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Base service class for Fizzy API services.
3
+ *
4
+ * Provides shared functionality for all service classes including:
5
+ * - Error handling with typed FizzyError
6
+ * - Hooks integration for observability
7
+ * - Automatic pagination via Link headers
8
+ */
9
+ import type { FizzyHooks, OperationInfo } from "../hooks.js";
10
+ import { FizzyError } from "../errors.js";
11
+ import { ListResult, type PaginationOptions } from "../pagination.js";
12
+ import type { paths } from "../generated/schema.js";
13
+ import type createClient from "openapi-fetch";
14
+ /**
15
+ * Raw client type from openapi-fetch.
16
+ */
17
+ export type RawClient = ReturnType<typeof createClient<paths>>;
18
+ /**
19
+ * Response type from openapi-fetch methods.
20
+ */
21
+ export interface FetchResponse<T> {
22
+ data?: T;
23
+ error?: unknown;
24
+ response: Response;
25
+ }
26
+ /**
27
+ * Abstract base class for all Fizzy API services.
28
+ */
29
+ export declare abstract class BaseService {
30
+ protected readonly client: RawClient;
31
+ protected readonly hooks?: FizzyHooks;
32
+ /**
33
+ * Authenticated fetch for pagination follow-up requests.
34
+ * Provided by createFizzyClient; falls back to unauthenticated fetch.
35
+ */
36
+ protected readonly fetchPage: (url: string) => Promise<Response>;
37
+ constructor(client: RawClient, hooks?: FizzyHooks, fetchPage?: (url: string) => Promise<Response>);
38
+ /**
39
+ * Executes an API request with error handling and hooks integration.
40
+ */
41
+ protected request<T>(info: OperationInfo, fn: () => Promise<FetchResponse<T>>): Promise<T>;
42
+ /**
43
+ * Executes a paginated API request, automatically following Link headers.
44
+ * Returns a ListResult<T> which extends Array<T>.
45
+ * Fizzy does not emit X-Total-Count.
46
+ */
47
+ protected requestPaginated<T>(info: OperationInfo, fn: () => Promise<FetchResponse<T[]>>, paginationOpts?: PaginationOptions): Promise<ListResult<T>>;
48
+ private followPagination;
49
+ protected handleError(response: Response, error?: unknown): Promise<FizzyError>;
50
+ }
51
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/services/base.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAqB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,YAAY,MAAM,eAAe,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAKD;;GAEG;AACH,8BAAsB,WAAW;IAC/B,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IACrC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAEtC;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAG/D,MAAM,EAAE,SAAS,EACjB,KAAK,CAAC,EAAE,UAAU,EAClB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC;IAOhD;;OAEG;cACa,OAAO,CAAC,CAAC,EACvB,IAAI,EAAE,aAAa,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAClC,OAAO,CAAC,CAAC,CAAC;IAgCb;;;;OAIG;cACa,gBAAgB,CAAC,CAAC,EAChC,IAAI,EAAE,aAAa,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EACrC,cAAc,CAAC,EAAE,iBAAiB,GACjC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YA6CX,gBAAgB;cAqCd,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;CAOtF"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Base service class for Fizzy API services.
3
+ *
4
+ * Provides shared functionality for all service classes including:
5
+ * - Error handling with typed FizzyError
6
+ * - Hooks integration for observability
7
+ * - Automatic pagination via Link headers
8
+ */
9
+ import { FizzyError, errorFromResponse } from "../errors.js";
10
+ import { ListResult } from "../pagination.js";
11
+ import { parseNextLink, resolveURL, isSameOrigin } from "../pagination-utils.js";
12
+ /** Maximum pages to follow as a safety cap against infinite loops. */
13
+ const MAX_PAGES = 10_000;
14
+ /**
15
+ * Abstract base class for all Fizzy API services.
16
+ */
17
+ export class BaseService {
18
+ client;
19
+ hooks;
20
+ /**
21
+ * Authenticated fetch for pagination follow-up requests.
22
+ * Provided by createFizzyClient; falls back to unauthenticated fetch.
23
+ */
24
+ fetchPage;
25
+ constructor(client, hooks, fetchPage) {
26
+ this.client = client;
27
+ this.hooks = hooks;
28
+ this.fetchPage = fetchPage ?? ((url) => fetch(url, { headers: { Accept: "application/json" } }));
29
+ }
30
+ /**
31
+ * Executes an API request with error handling and hooks integration.
32
+ */
33
+ async request(info, fn) {
34
+ const start = performance.now();
35
+ let result = { durationMs: 0 };
36
+ try {
37
+ this.hooks?.onOperationStart?.(info);
38
+ }
39
+ catch { /* hooks must not interrupt */ }
40
+ try {
41
+ const { data, error, response } = await fn();
42
+ result.durationMs = Math.round(performance.now() - start);
43
+ if (!response.ok || error) {
44
+ const fizzyError = await this.handleError(response, error);
45
+ result.error = fizzyError;
46
+ throw fizzyError;
47
+ }
48
+ if (response.status === 204 || data === undefined) {
49
+ return undefined;
50
+ }
51
+ return data;
52
+ }
53
+ catch (err) {
54
+ result.durationMs = Math.round(performance.now() - start);
55
+ if (err instanceof Error) {
56
+ result.error = err;
57
+ }
58
+ throw err;
59
+ }
60
+ finally {
61
+ try {
62
+ this.hooks?.onOperationEnd?.(info, result);
63
+ }
64
+ catch { /* hooks must not interrupt */ }
65
+ }
66
+ }
67
+ /**
68
+ * Executes a paginated API request, automatically following Link headers.
69
+ * Returns a ListResult<T> which extends Array<T>.
70
+ * Fizzy does not emit X-Total-Count.
71
+ */
72
+ async requestPaginated(info, fn, paginationOpts) {
73
+ const start = performance.now();
74
+ let result = { durationMs: 0 };
75
+ try {
76
+ this.hooks?.onOperationStart?.(info);
77
+ }
78
+ catch { /* hooks must not interrupt */ }
79
+ try {
80
+ const { data, error, response } = await fn();
81
+ result.durationMs = Math.round(performance.now() - start);
82
+ if (!response.ok || error) {
83
+ const fizzyError = await this.handleError(response, error);
84
+ result.error = fizzyError;
85
+ throw fizzyError;
86
+ }
87
+ const firstPageItems = data ?? [];
88
+ const maxItems = paginationOpts?.maxItems;
89
+ if (maxItems && maxItems > 0 && firstPageItems.length >= maxItems) {
90
+ const hasMore = firstPageItems.length > maxItems
91
+ || parseNextLink(response.headers.get("Link")) !== null;
92
+ result.durationMs = Math.round(performance.now() - start);
93
+ return new ListResult(firstPageItems.slice(0, maxItems), { truncated: hasMore });
94
+ }
95
+ const { items: allItems, truncated } = await this.followPagination(response, firstPageItems, maxItems);
96
+ result.durationMs = Math.round(performance.now() - start);
97
+ return new ListResult(allItems, { truncated });
98
+ }
99
+ catch (err) {
100
+ result.durationMs = Math.round(performance.now() - start);
101
+ if (err instanceof Error) {
102
+ result.error = err;
103
+ }
104
+ throw err;
105
+ }
106
+ finally {
107
+ try {
108
+ this.hooks?.onOperationEnd?.(info, result);
109
+ }
110
+ catch { /* hooks must not interrupt */ }
111
+ }
112
+ }
113
+ async followPagination(initialResponse, firstPageItems, maxItems) {
114
+ const allItems = [...firstPageItems];
115
+ let response = initialResponse;
116
+ const initialUrl = initialResponse.url;
117
+ for (let page = 1; page < MAX_PAGES; page++) {
118
+ const rawNextUrl = parseNextLink(response.headers.get("Link"));
119
+ if (!rawNextUrl)
120
+ break;
121
+ const nextUrl = resolveURL(response.url, rawNextUrl);
122
+ if (!isSameOrigin(nextUrl, initialUrl)) {
123
+ break;
124
+ }
125
+ response = await this.fetchPage(nextUrl);
126
+ if (!response.ok) {
127
+ throw await errorFromResponse(response, response.headers.get("X-Request-Id") ?? undefined);
128
+ }
129
+ const pageItems = (await response.json());
130
+ allItems.push(...pageItems);
131
+ if (maxItems && maxItems > 0 && allItems.length >= maxItems) {
132
+ return { items: allItems.slice(0, maxItems), truncated: true };
133
+ }
134
+ }
135
+ const hasMore = parseNextLink(response.headers.get("Link")) !== null;
136
+ return { items: allItems, truncated: hasMore };
137
+ }
138
+ async handleError(response, error) {
139
+ if (error instanceof FizzyError) {
140
+ return error;
141
+ }
142
+ const requestId = response.headers.get("X-Request-Id") ?? undefined;
143
+ return errorFromResponse(response, requestId);
144
+ }
145
+ }
146
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/services/base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /** Webhook event — raw JSON object from Fizzy. */
2
+ export interface WebhookEvent {
3
+ id?: number;
4
+ kind?: string;
5
+ [key: string]: unknown;
6
+ }
7
+ /** Handler function for webhook events. */
8
+ export type WebhookEventHandler = (event: WebhookEvent) => void | Promise<void>;
9
+ /** Middleware function that wraps event processing. Call next() to continue the chain. */
10
+ export type WebhookMiddleware = (event: WebhookEvent, next: () => Promise<void>) => Promise<void>;
11
+ /** Header accessor: either a record of headers or a function that retrieves a header by name. */
12
+ export type HeaderAccessor = Record<string, string | string[] | undefined> | ((name: string) => string | undefined);
13
+ export interface WebhookReceiverOptions {
14
+ /** HMAC secret for signature verification. If unset, verification is skipped. */
15
+ secret?: string;
16
+ /** HTTP header containing the signature (default: "x-fizzy-signature"). */
17
+ signatureHeader?: string;
18
+ /** Number of recent event IDs to track for deduplication (default: 1000, 0 to disable). */
19
+ dedupWindowSize?: number;
20
+ }
21
+ /** Error thrown when webhook signature verification fails. */
22
+ export declare class WebhookVerificationError extends Error {
23
+ constructor(message?: string);
24
+ }
25
+ /**
26
+ * Receives and routes webhook events from Fizzy.
27
+ *
28
+ * Framework-agnostic: works with raw body bytes and a header accessor.
29
+ */
30
+ export declare class WebhookReceiver {
31
+ private readonly secret?;
32
+ private readonly signatureHeader;
33
+ private readonly dedupWindowSize;
34
+ private readonly handlers;
35
+ private readonly anyHandlers;
36
+ private readonly middlewareChain;
37
+ private readonly dedupSeen;
38
+ private readonly dedupOrder;
39
+ private readonly dedupPending;
40
+ constructor(options?: WebhookReceiverOptions);
41
+ /**
42
+ * Register a handler for a specific event kind pattern.
43
+ * Supports exact match ("card_created") and glob patterns ("card_*", "*_created").
44
+ */
45
+ on(pattern: string, handler: WebhookEventHandler): this;
46
+ /** Register a handler that fires for all events. */
47
+ onAny(handler: WebhookEventHandler): this;
48
+ /** Add middleware to the processing chain. */
49
+ use(middleware: WebhookMiddleware): this;
50
+ /**
51
+ * Process a raw webhook request.
52
+ * Returns the parsed WebhookEvent.
53
+ * @throws {WebhookVerificationError} if signature verification fails
54
+ */
55
+ handleRequest(rawBody: string | Buffer, headers: HeaderAccessor): Promise<WebhookEvent>;
56
+ private getHeader;
57
+ private claim;
58
+ private commitSeen;
59
+ private releaseClaim;
60
+ private dispatchHandlers;
61
+ }
62
+ //# sourceMappingURL=handler.d.ts.map