@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 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/webhooks/handler.ts"],"names":[],"mappings":"AAEA,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,2CAA2C;AAC3C,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhF,0FAA0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAElG,iGAAiG;AACjG,MAAM,MAAM,cAAc,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAC7C,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,8DAA8D;AAC9D,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,SAA8B;CAIlD;AAED;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA2B;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;gBAEtC,OAAO,CAAC,EAAE,sBAAsB;IAM5C;;;OAGG;IACH,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAUvD,oDAAoD;IACpD,KAAK,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAKzC,8CAA8C;IAC9C,GAAG,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAKxC;;;;OAIG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,YAAY,CAAC;IAsCxB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,YAAY;YAIN,gBAAgB;CAe/B"}
@@ -0,0 +1,204 @@
1
+ import { verifyWebhookSignature } from "./verify.js";
2
+ /** Error thrown when webhook signature verification fails. */
3
+ export class WebhookVerificationError extends Error {
4
+ constructor(message = "invalid webhook signature") {
5
+ super(message);
6
+ this.name = "WebhookVerificationError";
7
+ }
8
+ }
9
+ /**
10
+ * Receives and routes webhook events from Fizzy.
11
+ *
12
+ * Framework-agnostic: works with raw body bytes and a header accessor.
13
+ */
14
+ export class WebhookReceiver {
15
+ secret;
16
+ signatureHeader;
17
+ dedupWindowSize;
18
+ handlers = new Map();
19
+ anyHandlers = [];
20
+ middlewareChain = [];
21
+ dedupSeen = new Set();
22
+ dedupOrder = [];
23
+ dedupPending = new Set();
24
+ constructor(options) {
25
+ this.secret = options?.secret;
26
+ this.signatureHeader = options?.signatureHeader ?? "x-fizzy-signature";
27
+ this.dedupWindowSize = options?.dedupWindowSize ?? 1000;
28
+ }
29
+ /**
30
+ * Register a handler for a specific event kind pattern.
31
+ * Supports exact match ("card_created") and glob patterns ("card_*", "*_created").
32
+ */
33
+ on(pattern, handler) {
34
+ const existing = this.handlers.get(pattern);
35
+ if (existing) {
36
+ existing.push(handler);
37
+ }
38
+ else {
39
+ this.handlers.set(pattern, [handler]);
40
+ }
41
+ return this;
42
+ }
43
+ /** Register a handler that fires for all events. */
44
+ onAny(handler) {
45
+ this.anyHandlers.push(handler);
46
+ return this;
47
+ }
48
+ /** Add middleware to the processing chain. */
49
+ use(middleware) {
50
+ this.middlewareChain.push(middleware);
51
+ return this;
52
+ }
53
+ /**
54
+ * Process a raw webhook request.
55
+ * Returns the parsed WebhookEvent.
56
+ * @throws {WebhookVerificationError} if signature verification fails
57
+ */
58
+ async handleRequest(rawBody, headers) {
59
+ if (this.secret) {
60
+ const sig = this.getHeader(headers, this.signatureHeader);
61
+ if (!sig || !verifyWebhookSignature(rawBody, sig, this.secret)) {
62
+ throw new WebhookVerificationError();
63
+ }
64
+ }
65
+ const bodyStr = typeof rawBody === "string" ? rawBody : rawBody.toString("utf8");
66
+ const eventIdStr = extractIdString(bodyStr);
67
+ const event = JSON.parse(bodyStr);
68
+ if (!this.claim(eventIdStr)) {
69
+ return event;
70
+ }
71
+ try {
72
+ const runHandlers = async () => {
73
+ await this.dispatchHandlers(event);
74
+ };
75
+ let chain = runHandlers;
76
+ for (let i = this.middlewareChain.length - 1; i >= 0; i--) {
77
+ const mw = this.middlewareChain[i];
78
+ const next = chain;
79
+ chain = () => mw(event, next);
80
+ }
81
+ await chain();
82
+ this.commitSeen(eventIdStr);
83
+ }
84
+ catch (err) {
85
+ this.releaseClaim(eventIdStr);
86
+ throw err;
87
+ }
88
+ return event;
89
+ }
90
+ getHeader(headers, name) {
91
+ if (typeof headers === "function") {
92
+ return headers(name);
93
+ }
94
+ const val = headers[name] ?? headers[name.toLowerCase()];
95
+ if (Array.isArray(val))
96
+ return val[0];
97
+ return val;
98
+ }
99
+ claim(eventIdStr) {
100
+ if (this.dedupWindowSize <= 0 || !eventIdStr)
101
+ return true;
102
+ if (this.dedupSeen.has(eventIdStr) || this.dedupPending.has(eventIdStr))
103
+ return false;
104
+ this.dedupPending.add(eventIdStr);
105
+ return true;
106
+ }
107
+ commitSeen(eventIdStr) {
108
+ if (this.dedupWindowSize <= 0 || !eventIdStr)
109
+ return;
110
+ this.dedupPending.delete(eventIdStr);
111
+ if (this.dedupOrder.length >= this.dedupWindowSize) {
112
+ const oldest = this.dedupOrder.shift();
113
+ this.dedupSeen.delete(oldest);
114
+ }
115
+ this.dedupSeen.add(eventIdStr);
116
+ this.dedupOrder.push(eventIdStr);
117
+ }
118
+ releaseClaim(eventIdStr) {
119
+ if (eventIdStr)
120
+ this.dedupPending.delete(eventIdStr);
121
+ }
122
+ async dispatchHandlers(event) {
123
+ const matched = [];
124
+ for (const [pattern, handlers] of this.handlers) {
125
+ if (matchPattern(pattern, event.kind ?? "")) {
126
+ matched.push(...handlers);
127
+ }
128
+ }
129
+ matched.push(...this.anyHandlers);
130
+ for (const handler of matched) {
131
+ await handler(event);
132
+ }
133
+ }
134
+ }
135
+ /** Extract "id" as raw string from JSON to avoid int64 precision loss. */
136
+ function extractIdString(json) {
137
+ let depth = 0;
138
+ let inString = false;
139
+ for (let i = 0; i < json.length; i++) {
140
+ const ch = json[i];
141
+ if (inString) {
142
+ if (ch === "\\") {
143
+ i++;
144
+ continue;
145
+ }
146
+ if (ch === '"') {
147
+ inString = false;
148
+ }
149
+ continue;
150
+ }
151
+ if (ch === '"') {
152
+ if (depth === 1 && json[i + 1] === "i" && json[i + 2] === "d" && json[i + 3] === '"') {
153
+ let j = i + 4;
154
+ while (j < json.length && (json[j] === " " || json[j] === "\t" || json[j] === "\n" || json[j] === "\r" || json[j] === ":"))
155
+ j++;
156
+ const start = j;
157
+ while (j < json.length && json[j] >= "0" && json[j] <= "9")
158
+ j++;
159
+ if (j > start)
160
+ return json.slice(start, j);
161
+ }
162
+ inString = true;
163
+ continue;
164
+ }
165
+ if (ch === "{") {
166
+ depth++;
167
+ continue;
168
+ }
169
+ if (ch === "}") {
170
+ depth--;
171
+ continue;
172
+ }
173
+ }
174
+ return undefined;
175
+ }
176
+ /**
177
+ * Match a webhook event kind against a glob pattern.
178
+ * "*" matches any sequence of characters.
179
+ */
180
+ function matchPattern(pattern, value) {
181
+ if (pattern === value)
182
+ return true;
183
+ const parts = pattern.split("*");
184
+ if (parts.length === 1)
185
+ return false;
186
+ let remaining = value;
187
+ for (let i = 0; i < parts.length; i++) {
188
+ const part = parts[i];
189
+ if (part === "")
190
+ continue;
191
+ const idx = remaining.indexOf(part);
192
+ if (idx === -1)
193
+ return false;
194
+ if (i === 0 && idx !== 0)
195
+ return false;
196
+ remaining = remaining.slice(idx + part.length);
197
+ }
198
+ const lastPart = parts.at(-1);
199
+ if (lastPart !== "") {
200
+ return value.endsWith(lastPart);
201
+ }
202
+ return true;
203
+ }
204
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/webhooks/handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { verifyWebhookSignature, signWebhookPayload, } from "./verify.js";
2
+ export { WebhookReceiver, WebhookVerificationError, type WebhookEvent, type WebhookEventHandler, type WebhookMiddleware, type WebhookReceiverOptions, type HeaderAccessor, } from "./handler.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { verifyWebhookSignature, signWebhookPayload, } from "./verify.js";
2
+ export { WebhookReceiver, WebhookVerificationError, } from "./handler.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,wBAAwB,GAMzB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Verify an HMAC-SHA256 webhook signature.
3
+ * Returns false if secret or signature is empty.
4
+ */
5
+ export declare function verifyWebhookSignature(payload: string | Buffer, signature: string, secret: string): boolean;
6
+ /**
7
+ * Compute the HMAC-SHA256 signature for a webhook payload.
8
+ */
9
+ export declare function signWebhookPayload(payload: string | Buffer, secret: string): string;
10
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/webhooks/verify.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAST;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,MAAM,EAAE,MAAM,GACb,MAAM,CAER"}
@@ -0,0 +1,23 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ /**
3
+ * Verify an HMAC-SHA256 webhook signature.
4
+ * Returns false if secret or signature is empty.
5
+ */
6
+ export function verifyWebhookSignature(payload, signature, secret) {
7
+ if (!secret || !signature)
8
+ return false;
9
+ const expected = signWebhookPayload(payload, secret);
10
+ try {
11
+ return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ /**
18
+ * Compute the HMAC-SHA256 signature for a webhook payload.
19
+ */
20
+ export function signWebhookPayload(payload, secret) {
21
+ return createHmac("sha256", secret).update(payload).digest("hex");
22
+ }
23
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/webhooks/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAwB,EACxB,SAAiB,EACjB,MAAc;IAEd,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAExC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAwB,EACxB,MAAc;IAEd,OAAO,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@37signals/fizzy",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for the Fizzy API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src/generated"
17
+ ],
18
+ "scripts": {
19
+ "generate": "tsx scripts/strip-account-id.ts ../spec/build/smithy/openapi/openapi/Fizzy.openapi.json src/generated/openapi-stripped.json && openapi-typescript src/generated/openapi-stripped.json -o src/generated/schema.d.ts && tsx scripts/extract-metadata.ts src/generated/openapi-stripped.json > src/generated/metadata.json && tsx scripts/generate-path-mapping.ts",
20
+ "build": "tsc",
21
+ "postbuild": "node -e \"fs=require('fs');fs.cpSync('src/generated','dist/generated',{recursive:true});\"",
22
+ "prepublishOnly": "npm run build",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "test:coverage": "vitest run --coverage",
26
+ "typecheck": "tsc --noEmit",
27
+ "lint": "oxlint src --ignore-pattern 'src/generated/**'"
28
+ },
29
+ "keywords": [
30
+ "fizzy",
31
+ "api",
32
+ "sdk",
33
+ "typescript"
34
+ ],
35
+ "author": "Basecamp",
36
+ "license": "MIT",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/basecamp/fizzy-sdk.git",
43
+ "directory": "typescript"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ },
48
+ "dependencies": {
49
+ "openapi-fetch": "^0.17.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^25.3.2",
53
+ "@vitest/coverage-v8": "^4.0.18",
54
+ "msw": "^2.12.10",
55
+ "openapi-typescript": "^7.13.0",
56
+ "oxlint": "^1.50.0",
57
+ "tsx": "^4.19.0",
58
+ "typescript": "^5.7.0",
59
+ "vitest": "^4.0.18"
60
+ },
61
+ "peerDependencies": {
62
+ "typescript": ">=5.0.0"
63
+ },
64
+ "overrides": {
65
+ "minimatch": ">=10.2.1"
66
+ }
67
+ }