@greatwait/contracts 0.1.0-alpha.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 (241) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/authority.d.ts +217 -0
  4. package/dist/authority.js +261 -0
  5. package/dist/callback-ownership.d.ts +58 -0
  6. package/dist/callback-ownership.js +71 -0
  7. package/dist/callback-safety.d.ts +38 -0
  8. package/dist/callback-safety.js +403 -0
  9. package/dist/compatibility.d.ts +82 -0
  10. package/dist/compatibility.js +115 -0
  11. package/dist/delivery.d.ts +401 -0
  12. package/dist/delivery.js +311 -0
  13. package/dist/endpoints.d.ts +305 -0
  14. package/dist/endpoints.js +179 -0
  15. package/dist/events.d.ts +62 -0
  16. package/dist/events.js +38 -0
  17. package/dist/first-value-journey.d.ts +305 -0
  18. package/dist/first-value-journey.js +466 -0
  19. package/dist/forecast.d.ts +443 -0
  20. package/dist/forecast.js +729 -0
  21. package/dist/identifiers.d.ts +109 -0
  22. package/dist/identifiers.js +131 -0
  23. package/dist/identity.d.ts +196 -0
  24. package/dist/identity.js +182 -0
  25. package/dist/index.d.ts +27 -0
  26. package/dist/index.js +27 -0
  27. package/dist/mcp.d.ts +51 -0
  28. package/dist/mcp.js +56 -0
  29. package/dist/oauth.d.ts +796 -0
  30. package/dist/oauth.js +708 -0
  31. package/dist/operations.d.ts +3985 -0
  32. package/dist/operations.js +1837 -0
  33. package/dist/partition.d.ts +771 -0
  34. package/dist/partition.js +206 -0
  35. package/dist/policy.d.ts +93 -0
  36. package/dist/policy.js +180 -0
  37. package/dist/problems.d.ts +158 -0
  38. package/dist/problems.js +104 -0
  39. package/dist/protocol.d.ts +308 -0
  40. package/dist/protocol.js +515 -0
  41. package/dist/scheduling-records.d.ts +395 -0
  42. package/dist/scheduling-records.js +284 -0
  43. package/dist/scheduling.d.ts +1098 -0
  44. package/dist/scheduling.js +1116 -0
  45. package/dist/secrets.d.ts +383 -0
  46. package/dist/secrets.js +272 -0
  47. package/dist/signatures.d.ts +704 -0
  48. package/dist/signatures.js +867 -0
  49. package/dist/tenancy.d.ts +178 -0
  50. package/dist/tenancy.js +145 -0
  51. package/dist/test-sink.d.ts +986 -0
  52. package/dist/test-sink.js +755 -0
  53. package/dist/time.d.ts +45 -0
  54. package/dist/time.js +128 -0
  55. package/dist/usage.d.ts +121 -0
  56. package/dist/usage.js +200 -0
  57. package/dist/webhooks.d.ts +116 -0
  58. package/dist/webhooks.js +161 -0
  59. package/dist/workspace.d.ts +92 -0
  60. package/dist/workspace.js +59 -0
  61. package/generated/v1/callback-delivery-signature.json +467 -0
  62. package/generated/v1/callback-endpoint-verification.json +59 -0
  63. package/generated/v1/callback-receiver.json +241 -0
  64. package/generated/v1/examples/attempts.list.response.json +24 -0
  65. package/generated/v1/examples/attempts.read.response.json +20 -0
  66. package/generated/v1/examples/credentials.create.request.json +5 -0
  67. package/generated/v1/examples/credentials.create.response.json +10 -0
  68. package/generated/v1/examples/credentials.list.response.json +17 -0
  69. package/generated/v1/examples/credentials.revoke.response.json +11 -0
  70. package/generated/v1/examples/credentials.rotate.request.json +3 -0
  71. package/generated/v1/examples/credentials.rotate.response.json +22 -0
  72. package/generated/v1/examples/endpoints.create.request.json +3 -0
  73. package/generated/v1/examples/endpoints.create.response.json +16 -0
  74. package/generated/v1/examples/endpoints.disable.response.json +15 -0
  75. package/generated/v1/examples/endpoints.list.response.json +21 -0
  76. package/generated/v1/examples/endpoints.read.response.json +14 -0
  77. package/generated/v1/examples/endpoints.rotateSigningKey.request.json +3 -0
  78. package/generated/v1/examples/endpoints.rotateSigningKey.response.json +23 -0
  79. package/generated/v1/examples/endpoints.update.request.json +3 -0
  80. package/generated/v1/examples/endpoints.update.response.json +13 -0
  81. package/generated/v1/examples/endpoints.verify.response.json +15 -0
  82. package/generated/v1/examples/forecast.read.response.json +28 -0
  83. package/generated/v1/examples/forecast.windows.response.json +21 -0
  84. package/generated/v1/examples/grants.list.response.json +17 -0
  85. package/generated/v1/examples/grants.revoke.response.json +16 -0
  86. package/generated/v1/examples/meta.scaffold.response.json +5 -0
  87. package/generated/v1/examples/meta.version.response.json +5 -0
  88. package/generated/v1/examples/occurrences.list.response.json +17 -0
  89. package/generated/v1/examples/occurrences.read.response.json +15 -0
  90. package/generated/v1/examples/occurrences.redeliver.response.json +16 -0
  91. package/generated/v1/examples/projects.create.request.json +3 -0
  92. package/generated/v1/examples/projects.create.response.json +5 -0
  93. package/generated/v1/examples/projects.list.response.json +9 -0
  94. package/generated/v1/examples/schedules.archive.response.json +25 -0
  95. package/generated/v1/examples/schedules.cancel.response.json +24 -0
  96. package/generated/v1/examples/schedules.create.request.json +9 -0
  97. package/generated/v1/examples/schedules.create.response.json +25 -0
  98. package/generated/v1/examples/schedules.list.response.json +23 -0
  99. package/generated/v1/examples/schedules.pause.response.json +23 -0
  100. package/generated/v1/examples/schedules.read.response.json +25 -0
  101. package/generated/v1/examples/schedules.replace.request.json +8 -0
  102. package/generated/v1/examples/schedules.replace.response.json +25 -0
  103. package/generated/v1/examples/schedules.resume.response.json +23 -0
  104. package/generated/v1/examples/sinkdeliveries.list.response.json +19 -0
  105. package/generated/v1/examples/sinkdeliveries.read.response.json +16 -0
  106. package/generated/v1/examples/testsinks.configure.request.json +3 -0
  107. package/generated/v1/examples/testsinks.configure.response.json +13 -0
  108. package/generated/v1/examples/testsinks.create.request.json +8 -0
  109. package/generated/v1/examples/testsinks.create.response.json +13 -0
  110. package/generated/v1/examples/testsinks.delete.response.json +13 -0
  111. package/generated/v1/examples/testsinks.list.response.json +20 -0
  112. package/generated/v1/examples/testsinks.read.response.json +14 -0
  113. package/generated/v1/examples/usage.read.response.json +20 -0
  114. package/generated/v1/first-value-journey.json +436 -0
  115. package/generated/v1/manifest.json +1037 -0
  116. package/generated/v1/openapi.json +23665 -0
  117. package/generated/v1/policy-matrix.json +305 -0
  118. package/generated/v1/schemas/attempts.list.query.json +16 -0
  119. package/generated/v1/schemas/attempts.list.response.json +175 -0
  120. package/generated/v1/schemas/attempts.read.response.json +168 -0
  121. package/generated/v1/schemas/credentials.create.request.json +39 -0
  122. package/generated/v1/schemas/credentials.create.response.json +88 -0
  123. package/generated/v1/schemas/credentials.list.query.json +16 -0
  124. package/generated/v1/schemas/credentials.list.response.json +124 -0
  125. package/generated/v1/schemas/credentials.revoke.response.json +84 -0
  126. package/generated/v1/schemas/credentials.rotate.request.json +11 -0
  127. package/generated/v1/schemas/credentials.rotate.response.json +171 -0
  128. package/generated/v1/schemas/endpoints.create.request.json +12 -0
  129. package/generated/v1/schemas/endpoints.create.response.json +115 -0
  130. package/generated/v1/schemas/endpoints.disable.response-headers.json +11 -0
  131. package/generated/v1/schemas/endpoints.disable.response.json +100 -0
  132. package/generated/v1/schemas/endpoints.list.query.json +16 -0
  133. package/generated/v1/schemas/endpoints.list.response.json +146 -0
  134. package/generated/v1/schemas/endpoints.read.response-headers.json +11 -0
  135. package/generated/v1/schemas/endpoints.read.response.json +100 -0
  136. package/generated/v1/schemas/endpoints.rotateSigningKey.request-headers.json +10 -0
  137. package/generated/v1/schemas/endpoints.rotateSigningKey.request.json +11 -0
  138. package/generated/v1/schemas/endpoints.rotateSigningKey.response-headers.json +11 -0
  139. package/generated/v1/schemas/endpoints.rotateSigningKey.response.json +118 -0
  140. package/generated/v1/schemas/endpoints.update.request-headers.json +10 -0
  141. package/generated/v1/schemas/endpoints.update.request.json +12 -0
  142. package/generated/v1/schemas/endpoints.update.response-headers.json +11 -0
  143. package/generated/v1/schemas/endpoints.update.response.json +100 -0
  144. package/generated/v1/schemas/endpoints.verify.request-headers.json +10 -0
  145. package/generated/v1/schemas/endpoints.verify.response-headers.json +11 -0
  146. package/generated/v1/schemas/endpoints.verify.response.json +100 -0
  147. package/generated/v1/schemas/forecast.read.query.json +26 -0
  148. package/generated/v1/schemas/forecast.read.response.json +100 -0
  149. package/generated/v1/schemas/forecast.windows.query.json +26 -0
  150. package/generated/v1/schemas/forecast.windows.response.json +94 -0
  151. package/generated/v1/schemas/grants.list.response.json +98 -0
  152. package/generated/v1/schemas/grants.revoke.response.json +95 -0
  153. package/generated/v1/schemas/meta.scaffold.response.json +36 -0
  154. package/generated/v1/schemas/meta.version.response.json +19 -0
  155. package/generated/v1/schemas/occurrences.list.query.json +16 -0
  156. package/generated/v1/schemas/occurrences.list.response.json +83 -0
  157. package/generated/v1/schemas/occurrences.read.response.json +76 -0
  158. package/generated/v1/schemas/occurrences.redeliver.request-headers.json +13 -0
  159. package/generated/v1/schemas/occurrences.redeliver.response-headers.json +10 -0
  160. package/generated/v1/schemas/occurrences.redeliver.response.json +168 -0
  161. package/generated/v1/schemas/projects.create.request.json +12 -0
  162. package/generated/v1/schemas/projects.create.response.json +25 -0
  163. package/generated/v1/schemas/projects.list.response.json +35 -0
  164. package/generated/v1/schemas/schedules.archive.request-headers.json +10 -0
  165. package/generated/v1/schemas/schedules.archive.response-headers.json +11 -0
  166. package/generated/v1/schemas/schedules.archive.response.json +189 -0
  167. package/generated/v1/schemas/schedules.cancel.request-headers.json +10 -0
  168. package/generated/v1/schemas/schedules.cancel.response-headers.json +11 -0
  169. package/generated/v1/schemas/schedules.cancel.response.json +189 -0
  170. package/generated/v1/schemas/schedules.create.request-headers.json +12 -0
  171. package/generated/v1/schemas/schedules.create.request.json +99 -0
  172. package/generated/v1/schemas/schedules.create.response-headers.json +15 -0
  173. package/generated/v1/schemas/schedules.create.response.json +189 -0
  174. package/generated/v1/schemas/schedules.list.query.json +16 -0
  175. package/generated/v1/schemas/schedules.list.response.json +170 -0
  176. package/generated/v1/schemas/schedules.pause.request-headers.json +10 -0
  177. package/generated/v1/schemas/schedules.pause.response-headers.json +11 -0
  178. package/generated/v1/schemas/schedules.pause.response.json +189 -0
  179. package/generated/v1/schemas/schedules.read.response-headers.json +11 -0
  180. package/generated/v1/schemas/schedules.read.response.json +189 -0
  181. package/generated/v1/schemas/schedules.replace.request-headers.json +10 -0
  182. package/generated/v1/schemas/schedules.replace.request.json +99 -0
  183. package/generated/v1/schemas/schedules.replace.response-headers.json +11 -0
  184. package/generated/v1/schemas/schedules.replace.response.json +189 -0
  185. package/generated/v1/schemas/schedules.resume.request-headers.json +10 -0
  186. package/generated/v1/schemas/schedules.resume.response-headers.json +11 -0
  187. package/generated/v1/schemas/schedules.resume.response.json +189 -0
  188. package/generated/v1/schemas/sinkdeliveries.list.query.json +16 -0
  189. package/generated/v1/schemas/sinkdeliveries.list.response.json +126 -0
  190. package/generated/v1/schemas/sinkdeliveries.read.response.json +98 -0
  191. package/generated/v1/schemas/testsinks.configure.request.json +66 -0
  192. package/generated/v1/schemas/testsinks.configure.response.json +115 -0
  193. package/generated/v1/schemas/testsinks.create.request.json +76 -0
  194. package/generated/v1/schemas/testsinks.create.response.json +115 -0
  195. package/generated/v1/schemas/testsinks.delete.response.json +115 -0
  196. package/generated/v1/schemas/testsinks.list.query.json +16 -0
  197. package/generated/v1/schemas/testsinks.list.response.json +161 -0
  198. package/generated/v1/schemas/testsinks.read.response.json +115 -0
  199. package/generated/v1/schemas/usage.read.query.json +15 -0
  200. package/generated/v1/schemas/usage.read.response.json +71 -0
  201. package/generated/v1/snippets/attempts.list.json +5 -0
  202. package/generated/v1/snippets/attempts.read.json +5 -0
  203. package/generated/v1/snippets/credentials.create.json +5 -0
  204. package/generated/v1/snippets/credentials.list.json +5 -0
  205. package/generated/v1/snippets/credentials.revoke.json +5 -0
  206. package/generated/v1/snippets/credentials.rotate.json +5 -0
  207. package/generated/v1/snippets/endpoints.create.json +5 -0
  208. package/generated/v1/snippets/endpoints.disable.json +5 -0
  209. package/generated/v1/snippets/endpoints.list.json +5 -0
  210. package/generated/v1/snippets/endpoints.read.json +5 -0
  211. package/generated/v1/snippets/endpoints.rotateSigningKey.json +5 -0
  212. package/generated/v1/snippets/endpoints.update.json +5 -0
  213. package/generated/v1/snippets/endpoints.verify.json +5 -0
  214. package/generated/v1/snippets/forecast.read.json +5 -0
  215. package/generated/v1/snippets/forecast.windows.json +5 -0
  216. package/generated/v1/snippets/grants.list.json +5 -0
  217. package/generated/v1/snippets/grants.revoke.json +5 -0
  218. package/generated/v1/snippets/meta.scaffold.json +5 -0
  219. package/generated/v1/snippets/meta.version.json +5 -0
  220. package/generated/v1/snippets/occurrences.list.json +5 -0
  221. package/generated/v1/snippets/occurrences.read.json +5 -0
  222. package/generated/v1/snippets/occurrences.redeliver.json +5 -0
  223. package/generated/v1/snippets/projects.create.json +5 -0
  224. package/generated/v1/snippets/projects.list.json +5 -0
  225. package/generated/v1/snippets/schedules.archive.json +5 -0
  226. package/generated/v1/snippets/schedules.cancel.json +5 -0
  227. package/generated/v1/snippets/schedules.create.json +5 -0
  228. package/generated/v1/snippets/schedules.list.json +5 -0
  229. package/generated/v1/snippets/schedules.pause.json +5 -0
  230. package/generated/v1/snippets/schedules.read.json +5 -0
  231. package/generated/v1/snippets/schedules.replace.json +5 -0
  232. package/generated/v1/snippets/schedules.resume.json +5 -0
  233. package/generated/v1/snippets/sinkdeliveries.list.json +5 -0
  234. package/generated/v1/snippets/sinkdeliveries.read.json +5 -0
  235. package/generated/v1/snippets/testsinks.configure.json +5 -0
  236. package/generated/v1/snippets/testsinks.create.json +5 -0
  237. package/generated/v1/snippets/testsinks.delete.json +5 -0
  238. package/generated/v1/snippets/testsinks.list.json +5 -0
  239. package/generated/v1/snippets/testsinks.read.json +5 -0
  240. package/generated/v1/snippets/usage.read.json +5 -0
  241. package/package.json +153 -0
@@ -0,0 +1,161 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Inbound webhook authenticity.
4
+ *
5
+ * Clerk delivers organization and membership changes through Svix, which signs
6
+ * `<svix-id>.<svix-timestamp>.<raw body>` with HMAC-SHA256 under a secret minted
7
+ * per endpoint. This module owns the encoding and the header vocabulary; the
8
+ * adapter owns the key material and the constant-time comparison, exactly as
9
+ * `signatures.ts` splits outbound callback signing.
10
+ *
11
+ * The split matters. Keeping the signed-byte construction in the contract layer
12
+ * means every verifier — the Worker, a test, a future replay tool — signs the
13
+ * same bytes, and the reasoning below is stated once instead of being
14
+ * rediscovered by whoever writes the second one.
15
+ */
16
+ export const SVIX_HEADERS = {
17
+ id: "svix-id",
18
+ signature: "svix-signature",
19
+ timestamp: "svix-timestamp",
20
+ };
21
+ /**
22
+ * Where Clerk delivers organization and membership changes.
23
+ *
24
+ * Deliberately outside `/v1`. W1-07 enforces REST/MCP parity over every public
25
+ * `/v1` operation, and a webhook ingress is not a customer-facing operation —
26
+ * putting it there would either break that check or require an exception to it.
27
+ * Follows the internal-route convention set by `/__greatwait/version`.
28
+ *
29
+ * **Here rather than in the Worker that serves it, since W4-08.** The smoke
30
+ * asks a hosted stage whether this route is configured to accept a delivery,
31
+ * and a script cannot import the API application. A second spelling of an
32
+ * address Clerk is pointed at is one that can drift while both read as
33
+ * correct.
34
+ */
35
+ export const CLERK_WEBHOOK_PATH = "/__greatwait/webhooks/clerk";
36
+ /** Only `v1` exists. A new scheme is added alongside, never in place of. */
37
+ export const WEBHOOK_SIGNATURE_SCHEME = "v1";
38
+ /**
39
+ * How far Clerk's clock may differ from ours before a delivery is stale.
40
+ *
41
+ * Svix's own guidance is five minutes, and matching it is deliberate: a tighter
42
+ * window would reject legitimate deliveries during a retry burst, and a wider
43
+ * one lengthens the replay window for a captured request.
44
+ */
45
+ export const WEBHOOK_TOLERANCE_SECONDS = 300;
46
+ /**
47
+ * A Svix message id. Deliberately a restricted charset rather than
48
+ * `z.string().min(1)` — see `webhookSigningInput` for why the absence of `.`
49
+ * here is a security property and not a formatting preference.
50
+ */
51
+ export const svixIdSchema = z
52
+ .string()
53
+ .regex(/^msg_[A-Za-z0-9]{1,64}$/u, 'must be "msg_" followed by up to 64 alphanumeric characters');
54
+ /**
55
+ * Seconds since the Unix epoch, as digits. No sign, no decimal point, no
56
+ * exponent — `Number.parseInt` would happily accept `+1e9` and `12.5`, and both
57
+ * would reach the signed bytes in a form we did not intend.
58
+ */
59
+ export const svixTimestampSchema = z
60
+ .string()
61
+ .regex(/^[0-9]{1,15}$/u, "must be a whole number of seconds since the epoch");
62
+ /**
63
+ * One `v1,<base64>` pair. Svix sends a space-delimited list so an endpoint can
64
+ * be verified under both keys during rotation, which is why the verifier must
65
+ * accept a match against *any* entry rather than parsing a single value.
66
+ */
67
+ export const svixSignatureEntryPattern = /^v1,[A-Za-z0-9+/]+={0,2}$/u;
68
+ export const svixSignatureHeaderSchema = z
69
+ .string()
70
+ .min(1)
71
+ .refine((header) => header
72
+ .split(" ")
73
+ .filter((entry) => entry.length > 0)
74
+ .some((entry) => svixSignatureEntryPattern.test(entry)), "must contain at least one v1,<base64> signature");
75
+ export const svixHeadersSchema = z.object({
76
+ [SVIX_HEADERS.id]: svixIdSchema,
77
+ [SVIX_HEADERS.signature]: svixSignatureHeaderSchema,
78
+ [SVIX_HEADERS.timestamp]: svixTimestampSchema,
79
+ });
80
+ /**
81
+ * Every `v1` signature offered in the header, base64 still encoded.
82
+ *
83
+ * Entries in other schemes are dropped rather than rejected: Svix may add a
84
+ * scheme before we support it, and a delivery that carries both `v1` and a
85
+ * future `v2` must still verify under `v1` instead of failing closed on the
86
+ * presence of something newer.
87
+ */
88
+ export function webhookSignatureCandidates(header) {
89
+ return header
90
+ .split(" ")
91
+ .filter((entry) => svixSignatureEntryPattern.test(entry))
92
+ .map((entry) => entry.slice(`${WEBHOOK_SIGNATURE_SCHEME},`.length));
93
+ }
94
+ /**
95
+ * The exact bytes Svix signs: `<id>.<timestamp>.` followed by the raw body,
96
+ * with no re-serialization anywhere in the path.
97
+ *
98
+ * Both prefix fields are validated rather than trusted, and — as with
99
+ * `signingInput` for outbound callbacks — that is a security property. The
100
+ * delimiter is `.`, so if either field could itself contain a `.` the encoding
101
+ * would not be injective: an attacker holding one legitimate signature could
102
+ * shift bytes across a delimiter, lengthening the id header while shortening
103
+ * the body, and still verify.
104
+ *
105
+ * The argument here is slightly different from the outbound one, which relies
106
+ * on both fields being fixed-width. `svixIdSchema` and `svixTimestampSchema`
107
+ * admit no `.` at all, so splitting the signed content on its first two dots
108
+ * recovers the id and the timestamp uniquely whatever their lengths. Variable
109
+ * width is fine; a dot would not be.
110
+ *
111
+ * **Throws** on malformed input. Use `tryWebhookSigningInput` when verifying
112
+ * headers off the wire, or a malformed-header probe becomes a 500.
113
+ */
114
+ export function webhookSigningInput(svixId, svixTimestamp, rawBody) {
115
+ const checkedId = svixIdSchema.parse(svixId);
116
+ const checkedTimestamp = svixTimestampSchema.parse(svixTimestamp);
117
+ const prefix = `${checkedId}.${checkedTimestamp}.`;
118
+ // Both fields are ASCII by construction, now that both have been validated, so
119
+ // UTF-8 encoding them is byte-identical to their code points.
120
+ const prefixBytes = new TextEncoder().encode(prefix);
121
+ const input = new Uint8Array(prefixBytes.length + rawBody.length);
122
+ input.set(prefixBytes, 0);
123
+ input.set(rawBody, prefixBytes.length);
124
+ return input;
125
+ }
126
+ /**
127
+ * `webhookSigningInput` for untrusted input: `undefined` instead of a throw when
128
+ * the headers are malformed.
129
+ */
130
+ export function tryWebhookSigningInput(svixId, svixTimestamp, rawBody) {
131
+ try {
132
+ return webhookSigningInput(svixId, svixTimestamp, rawBody);
133
+ }
134
+ catch (error) {
135
+ // Only a validation failure means "malformed headers". Anything else — an
136
+ // allocation failure on an oversized body, say — is a real fault and must
137
+ // not be reported to the caller as a bad signature.
138
+ if (error instanceof z.ZodError) {
139
+ return undefined;
140
+ }
141
+ throw error;
142
+ }
143
+ }
144
+ /**
145
+ * Whether a delivery's timestamp is close enough to now.
146
+ *
147
+ * Rejects the future as firmly as the past. A signature dated an hour ahead is
148
+ * not a clock-skew inconvenience — accepting it would hand an attacker who
149
+ * captures one request an hour of replay window, so the comparison is on
150
+ * absolute difference.
151
+ *
152
+ * Replay protection beyond this window belongs to the receiver, keyed on the
153
+ * Svix message id; freshness alone does not make a delivery unique.
154
+ */
155
+ export function isWebhookTimestampFresh(svixTimestamp, nowMs, toleranceSeconds = WEBHOOK_TOLERANCE_SECONDS) {
156
+ if (!svixTimestampSchema.safeParse(svixTimestamp).success) {
157
+ return false;
158
+ }
159
+ const signedMs = Number(svixTimestamp) * 1000;
160
+ return Math.abs(nowMs - signedMs) <= toleranceSeconds * 1000;
161
+ }
@@ -0,0 +1,92 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Repository scaffold contracts.
4
+ *
5
+ * These schemas describe the workspace itself — the layer a package occupies
6
+ * and the scaffold responses the apps expose. The public V1 product contract
7
+ * (IDs, timestamps, pagination, errors, idempotency, events, signatures) is
8
+ * defined by W0-02 and does not belong here.
9
+ */
10
+ export declare const WORKSPACE_LAYERS: readonly ["contract", "platform", "domain", "application", "adapter", "test-support"];
11
+ export declare const workspaceLayerSchema: z.ZodEnum<{
12
+ contract: "contract";
13
+ platform: "platform";
14
+ domain: "domain";
15
+ application: "application";
16
+ adapter: "adapter";
17
+ "test-support": "test-support";
18
+ }>;
19
+ export type WorkspaceLayer = z.infer<typeof workspaceLayerSchema>;
20
+ export declare const workspaceIdentitySchema: z.ZodObject<{
21
+ layer: z.ZodEnum<{
22
+ contract: "contract";
23
+ platform: "platform";
24
+ domain: "domain";
25
+ application: "application";
26
+ adapter: "adapter";
27
+ "test-support": "test-support";
28
+ }>;
29
+ workspace: z.ZodString;
30
+ }, z.core.$strip>;
31
+ export type WorkspaceIdentity = z.infer<typeof workspaceIdentitySchema>;
32
+ /** Shape of `GET /__greatwait/version` on every Greatwait Worker. */
33
+ export declare const scaffoldVersionSchema: z.ZodObject<{
34
+ buildSha: z.ZodString;
35
+ environment: z.ZodString;
36
+ service: z.ZodString;
37
+ }, z.core.$strip>;
38
+ export type ScaffoldVersion = z.infer<typeof scaffoldVersionSchema>;
39
+ /** Shape of the scaffold description an adapter reads from the application. */
40
+ export declare const workspaceScaffoldSchema: z.ZodObject<{
41
+ dependsOn: z.ZodArray<z.ZodEnum<{
42
+ contract: "contract";
43
+ platform: "platform";
44
+ domain: "domain";
45
+ application: "application";
46
+ adapter: "adapter";
47
+ "test-support": "test-support";
48
+ }>>;
49
+ layer: z.ZodEnum<{
50
+ contract: "contract";
51
+ platform: "platform";
52
+ domain: "domain";
53
+ application: "application";
54
+ adapter: "adapter";
55
+ "test-support": "test-support";
56
+ }>;
57
+ service: z.ZodString;
58
+ }, z.core.$strip>;
59
+ export type WorkspaceScaffold = z.infer<typeof workspaceScaffoldSchema>;
60
+ /**
61
+ * The minimal refusal body the scaffold routes return.
62
+ *
63
+ * Superseded by `problems.ts`, which W0-02 defined. This remains only for the
64
+ * scaffold routes in `apps/api` and `apps/contract-mock`; those move to the
65
+ * real problem document when W1-06 replaces the scaffold with the REST
66
+ * control plane. New code uses `problem()`.
67
+ */
68
+ export declare const scaffoldProblemSchema: z.ZodObject<{
69
+ title: z.ZodString;
70
+ type: z.ZodLiteral<"about:blank">;
71
+ }, z.core.$strip>;
72
+ export type ScaffoldProblem = z.infer<typeof scaffoldProblemSchema>;
73
+ /**
74
+ * A transport-neutral tool descriptor. REST and MCP publish the same shape, so
75
+ * the two surfaces cannot drift into describing tools differently.
76
+ */
77
+ export declare const toolDescriptorSchema: z.ZodObject<{
78
+ description: z.ZodString;
79
+ name: z.ZodString;
80
+ readOnly: z.ZodBoolean;
81
+ title: z.ZodString;
82
+ }, z.core.$strip>;
83
+ export type ToolDescriptor = z.infer<typeof toolDescriptorSchema>;
84
+ export declare const toolListSchema: z.ZodObject<{
85
+ tools: z.ZodArray<z.ZodObject<{
86
+ description: z.ZodString;
87
+ name: z.ZodString;
88
+ readOnly: z.ZodBoolean;
89
+ title: z.ZodString;
90
+ }, z.core.$strip>>;
91
+ }, z.core.$strip>;
92
+ export type ToolList = z.infer<typeof toolListSchema>;
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Repository scaffold contracts.
4
+ *
5
+ * These schemas describe the workspace itself — the layer a package occupies
6
+ * and the scaffold responses the apps expose. The public V1 product contract
7
+ * (IDs, timestamps, pagination, errors, idempotency, events, signatures) is
8
+ * defined by W0-02 and does not belong here.
9
+ */
10
+ export const WORKSPACE_LAYERS = [
11
+ "contract",
12
+ "platform",
13
+ "domain",
14
+ "application",
15
+ "adapter",
16
+ "test-support",
17
+ ];
18
+ export const workspaceLayerSchema = z.enum(WORKSPACE_LAYERS);
19
+ export const workspaceIdentitySchema = z.object({
20
+ layer: workspaceLayerSchema,
21
+ workspace: z.string().min(1),
22
+ });
23
+ /** Shape of `GET /__greatwait/version` on every Greatwait Worker. */
24
+ export const scaffoldVersionSchema = z.object({
25
+ buildSha: z.string().min(1),
26
+ environment: z.string().min(1),
27
+ service: z.string().min(1),
28
+ });
29
+ /** Shape of the scaffold description an adapter reads from the application. */
30
+ export const workspaceScaffoldSchema = z.object({
31
+ dependsOn: z.array(workspaceLayerSchema),
32
+ layer: workspaceLayerSchema,
33
+ service: z.string().min(1),
34
+ });
35
+ /**
36
+ * The minimal refusal body the scaffold routes return.
37
+ *
38
+ * Superseded by `problems.ts`, which W0-02 defined. This remains only for the
39
+ * scaffold routes in `apps/api` and `apps/contract-mock`; those move to the
40
+ * real problem document when W1-06 replaces the scaffold with the REST
41
+ * control plane. New code uses `problem()`.
42
+ */
43
+ export const scaffoldProblemSchema = z.object({
44
+ title: z.string().min(1),
45
+ type: z.literal("about:blank"),
46
+ });
47
+ /**
48
+ * A transport-neutral tool descriptor. REST and MCP publish the same shape, so
49
+ * the two surfaces cannot drift into describing tools differently.
50
+ */
51
+ export const toolDescriptorSchema = z.object({
52
+ description: z.string().min(1),
53
+ name: z.string().min(1),
54
+ readOnly: z.boolean(),
55
+ title: z.string().min(1),
56
+ });
57
+ export const toolListSchema = z.object({
58
+ tools: z.array(toolDescriptorSchema),
59
+ });