@stormwateriq/api-client 0.0.1

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 (63) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +75 -0
  3. package/dist/client.d.ts +34 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +67 -0
  6. package/dist/generated/client/client.gen.d.ts +3 -0
  7. package/dist/generated/client/client.gen.d.ts.map +1 -0
  8. package/dist/generated/client/client.gen.js +216 -0
  9. package/dist/generated/client/index.d.ts +10 -0
  10. package/dist/generated/client/index.d.ts.map +1 -0
  11. package/dist/generated/client/index.js +6 -0
  12. package/dist/generated/client/types.gen.d.ts +121 -0
  13. package/dist/generated/client/types.gen.d.ts.map +1 -0
  14. package/dist/generated/client/types.gen.js +2 -0
  15. package/dist/generated/client/utils.gen.d.ts +38 -0
  16. package/dist/generated/client/utils.gen.d.ts.map +1 -0
  17. package/dist/generated/client/utils.gen.js +228 -0
  18. package/dist/generated/client.gen.d.ts +13 -0
  19. package/dist/generated/client.gen.d.ts.map +1 -0
  20. package/dist/generated/client.gen.js +3 -0
  21. package/dist/generated/core/auth.gen.d.ts +26 -0
  22. package/dist/generated/core/auth.gen.d.ts.map +1 -0
  23. package/dist/generated/core/auth.gen.js +14 -0
  24. package/dist/generated/core/bodySerializer.gen.d.ts +26 -0
  25. package/dist/generated/core/bodySerializer.gen.d.ts.map +1 -0
  26. package/dist/generated/core/bodySerializer.gen.js +57 -0
  27. package/dist/generated/core/params.gen.d.ts +44 -0
  28. package/dist/generated/core/params.gen.d.ts.map +1 -0
  29. package/dist/generated/core/params.gen.js +100 -0
  30. package/dist/generated/core/pathSerializer.gen.d.ts +34 -0
  31. package/dist/generated/core/pathSerializer.gen.d.ts.map +1 -0
  32. package/dist/generated/core/pathSerializer.gen.js +106 -0
  33. package/dist/generated/core/queryKeySerializer.gen.d.ts +19 -0
  34. package/dist/generated/core/queryKeySerializer.gen.d.ts.map +1 -0
  35. package/dist/generated/core/queryKeySerializer.gen.js +92 -0
  36. package/dist/generated/core/serverSentEvents.gen.d.ts +72 -0
  37. package/dist/generated/core/serverSentEvents.gen.d.ts.map +1 -0
  38. package/dist/generated/core/serverSentEvents.gen.js +132 -0
  39. package/dist/generated/core/types.gen.d.ts +79 -0
  40. package/dist/generated/core/types.gen.d.ts.map +1 -0
  41. package/dist/generated/core/types.gen.js +2 -0
  42. package/dist/generated/core/utils.gen.d.ts +20 -0
  43. package/dist/generated/core/utils.gen.d.ts.map +1 -0
  44. package/dist/generated/core/utils.gen.js +87 -0
  45. package/dist/generated/index.d.ts +3 -0
  46. package/dist/generated/index.d.ts.map +1 -0
  47. package/dist/generated/index.js +2 -0
  48. package/dist/generated/sdk.gen.d.ts +90 -0
  49. package/dist/generated/sdk.gen.d.ts.map +1 -0
  50. package/dist/generated/sdk.gen.js +136 -0
  51. package/dist/generated/types.gen.d.ts +535 -0
  52. package/dist/generated/types.gen.d.ts.map +1 -0
  53. package/dist/generated/types.gen.js +2 -0
  54. package/dist/index.d.ts +6 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +9 -0
  57. package/dist/retry.d.ts +16 -0
  58. package/dist/retry.d.ts.map +1 -0
  59. package/dist/retry.js +31 -0
  60. package/dist/webhooks.d.ts +28 -0
  61. package/dist/webhooks.d.ts.map +1 -0
  62. package/dist/webhooks.js +65 -0
  63. package/package.json +45 -0
@@ -0,0 +1,65 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ /**
3
+ * Reference webhook-signature verifier for the StormwaterIQ external API
4
+ * (docs/external-api.md §06). Byte-identical to the server's `verifyWebhook`
5
+ * (packages/api) and the Python SDK — all three are pinned to the shared vectors in
6
+ * fixtures/webhook-signature-vectors.json. Tenants call this rather than re-rolling
7
+ * HMAC code.
8
+ *
9
+ * Header form: `t=<unix_ts>,v1=<hmac_sha256_hex>` over the message `"<t>.<rawBody>"`.
10
+ * The timestamp is inside the signed material, so a tampered timestamp invalidates the
11
+ * signature — that is what lets us reject replays by age without trusting the clock.
12
+ */
13
+ /** Deliveries older than this (seconds) are rejected as replays (§06). */
14
+ export const SIGNATURE_TOLERANCE_SECONDS = 300;
15
+ function parseSignatureHeader(header) {
16
+ const parts = new Map();
17
+ for (const segment of header.split(",")) {
18
+ const idx = segment.indexOf("=");
19
+ if (idx === -1)
20
+ return null;
21
+ parts.set(segment.slice(0, idx).trim(), segment.slice(idx + 1).trim());
22
+ }
23
+ const tRaw = parts.get("t");
24
+ const v1 = parts.get("v1");
25
+ if (!tRaw || !v1)
26
+ return null;
27
+ if (!/^\d+$/.test(tRaw))
28
+ return null;
29
+ if (!/^[0-9a-f]+$/.test(v1))
30
+ return null;
31
+ return { t: Number(tRaw), v1 };
32
+ }
33
+ function timingSafeHexEqual(a, b) {
34
+ if (a.length !== b.length)
35
+ return false;
36
+ try {
37
+ return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ /**
44
+ * Verify a webhook delivery. Returns `true` only when the signature matches the
45
+ * payload under `secret` AND the signed timestamp is within `toleranceSec` of now.
46
+ * Tampered bodies, wrong secrets, malformed headers, and stale/replayed deliveries
47
+ * all return `false`.
48
+ *
49
+ * @param payload the raw request body string exactly as received
50
+ * @param signature the `X-StormwaterIQ-Signature` header value
51
+ * @param secret the endpoint's signing secret
52
+ */
53
+ export function verify(payload, signature, secret, opts) {
54
+ const parsed = parseSignatureHeader(signature);
55
+ if (!parsed)
56
+ return false;
57
+ const tolerance = opts?.toleranceSec ?? SIGNATURE_TOLERANCE_SECONDS;
58
+ const now = opts?.nowSec ?? Math.floor(Date.now() / 1000);
59
+ if (Math.abs(now - parsed.t) > tolerance)
60
+ return false;
61
+ const expected = createHmac("sha256", secret)
62
+ .update(`${parsed.t}.${payload}`)
63
+ .digest("hex");
64
+ return timingSafeHexEqual(expected, parsed.v1);
65
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@stormwateriq/api-client",
3
+ "version": "0.0.1",
4
+ "description": "Official TypeScript client for the StormwaterIQ external API: generated typed SDK over the gateway's OpenAPI contract, plus the reference webhook-signature verifier and automatic retries.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "engines": {
20
+ "node": ">=22"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public",
24
+ "provenance": true
25
+ },
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "typecheck": "tsc --noEmit",
29
+ "openapi-ts": "openapi-ts",
30
+ "test": "vitest run --config vitest.config.ts",
31
+ "release": "release-it"
32
+ },
33
+ "devDependencies": {
34
+ "@hey-api/openapi-ts": "0.98.1",
35
+ "@release-it/conventional-changelog": "^11.0.1",
36
+ "@stormwateriq/typescript-config": "*",
37
+ "@types/node": "^25.2.2",
38
+ "release-it": "^20.2.0",
39
+ "typescript": "~5.9.2",
40
+ "vitest": "^4.0.18"
41
+ },
42
+ "dependencies": {
43
+ "@hey-api/client-fetch": "0.13.1"
44
+ }
45
+ }