@rkt-tools/contracts 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -13,7 +13,16 @@ The pure, shared **ingestion-envelope contract** for the `rkt-comms` monorepo: t
13
13
  | `imessageEnvelopeSchema` / `callEnvelopeSchema` | the two standalone members — what the bridge validates against |
14
14
  | `participantSchema`, `imessageSafeMetadataSchema`, `callSafeMetadataSchema`, `SAFE_METADATA_KEYS` | building blocks |
15
15
  | `parseBridgeEnvelope(value)` | `bridgeEnvelopeSchema.parse` |
16
+ | `mailWebhookPayloadSchema`, `webhookMessageSchema`, `webhookRefSchema`, `webhookEventSchema` | mail triage webhook wire + internal event shapes |
17
+ | `parseMailWebhookPayload(value)` / `parseWebhookEvent(value)` | strict parsers for the mail webhook contract |
16
18
  | types: `BridgeEnvelope` (union), `CoreEnvelope` (**iMessage member only**, not the union), `CallEnvelope`, `SafeMetadata` | inferred |
19
+ | types: `MailWebhookPayload`, `WebhookMessage`, `WebhookRef`, `WebhookEvent`, `WebhookAttachment`, `WebhookThread` | mail webhook inferred types |
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ pnpm add @rkt-tools/contracts
25
+ ```
17
26
 
18
27
  ## Build & test
19
28
 
@@ -23,17 +32,6 @@ pnpm --filter @rkt-tools/contracts test # golden-fixture contract guard
23
32
  pnpm --filter @rkt-tools/contracts typecheck
24
33
  ```
25
34
 
26
- Consumers build it deps-first on every build/deploy path via the trailing-`...` filter, e.g. `pnpm --filter "rkt-crm..." build`.
27
-
28
35
  ## Changing the wire contract
29
36
 
30
37
  Edit `src/envelope.ts` **and extend the golden fixtures in `test/envelope.test.ts` in the same commit.** The fixtures (known-good must-parse, known-bad must-reject) are the regression guard that the contract can't silently loosen or tighten. The build must keep `declaration: true` (in `tsconfig.build.json`) or NodeNext consumers fail type resolution.
31
-
32
- ## Consumption
33
-
34
- | Consumer | How |
35
- | ----------------------------------- | ---------------------------------------------------------------------------------- |
36
- | **rkt-comms** (`crm`, `imap-mcp`) | `"@rkt-tools/contracts": "workspace:*"` — no npm auth needed for local/Railway builds |
37
- | **rkt-ship** (and other cross-repo) | `"@rkt-tools/contracts": "^0.1.0"` from public npm (`publishConfig.access: public`) |
38
-
39
- Release and registry runbook: [`docs/contracts-registry.md`](../../docs/contracts-registry.md). ADR: [`0033`](../../packages/crm/docs/adr/0033-rkt-contracts-npm-registry-consumption.md).
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './envelope.js';
2
+ export * from './mailWebhook.js';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export * from './envelope.js';
2
+ export * from './mailWebhook.js';
@@ -0,0 +1,241 @@
1
+ import { z } from 'zod';
2
+ export declare const attachmentKindSchema: z.ZodEnum<{
3
+ image: "image";
4
+ document: "document";
5
+ pdf: "pdf";
6
+ spreadsheet: "spreadsheet";
7
+ presentation: "presentation";
8
+ archive: "archive";
9
+ audio: "audio";
10
+ video: "video";
11
+ other: "other";
12
+ }>;
13
+ export declare const mailAddressSchema: z.ZodObject<{
14
+ address: z.ZodString;
15
+ name: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strict>;
17
+ export declare const webhookAttachmentSchema: z.ZodObject<{
18
+ filename: z.ZodNullable<z.ZodString>;
19
+ mimeType: z.ZodString;
20
+ size: z.ZodNullable<z.ZodNumber>;
21
+ kind: z.ZodEnum<{
22
+ image: "image";
23
+ document: "document";
24
+ pdf: "pdf";
25
+ spreadsheet: "spreadsheet";
26
+ presentation: "presentation";
27
+ archive: "archive";
28
+ audio: "audio";
29
+ video: "video";
30
+ other: "other";
31
+ }>;
32
+ }, z.core.$strict>;
33
+ export declare const webhookThreadSchema: z.ZodObject<{
34
+ threadId: z.ZodString;
35
+ messageId: z.ZodNullable<z.ZodString>;
36
+ inReplyTo: z.ZodNullable<z.ZodString>;
37
+ references: z.ZodArray<z.ZodString>;
38
+ isReply: z.ZodBoolean;
39
+ }, z.core.$strict>;
40
+ /** Backend-specific locator for the exact buzzed message. */
41
+ export declare const webhookRefSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
42
+ kind: z.ZodLiteral<"imap">;
43
+ account: z.ZodString;
44
+ folder: z.ZodString;
45
+ uid: z.ZodNumber;
46
+ uidValidity: z.ZodOptional<z.ZodString>;
47
+ }, z.core.$strict>, z.ZodObject<{
48
+ kind: z.ZodLiteral<"gmail">;
49
+ account: z.ZodString;
50
+ messageId: z.ZodString;
51
+ }, z.core.$strict>], "kind">;
52
+ export declare const webhookMessageSchema: z.ZodObject<{
53
+ uid: z.ZodOptional<z.ZodNumber>;
54
+ from: z.ZodNullable<z.ZodObject<{
55
+ address: z.ZodString;
56
+ name: z.ZodOptional<z.ZodString>;
57
+ }, z.core.$strict>>;
58
+ to: z.ZodArray<z.ZodObject<{
59
+ address: z.ZodString;
60
+ name: z.ZodOptional<z.ZodString>;
61
+ }, z.core.$strict>>;
62
+ cc: z.ZodArray<z.ZodObject<{
63
+ address: z.ZodString;
64
+ name: z.ZodOptional<z.ZodString>;
65
+ }, z.core.$strict>>;
66
+ subject: z.ZodString;
67
+ date: z.ZodNullable<z.ZodString>;
68
+ preview: z.ZodString;
69
+ thread: z.ZodObject<{
70
+ threadId: z.ZodString;
71
+ messageId: z.ZodNullable<z.ZodString>;
72
+ inReplyTo: z.ZodNullable<z.ZodString>;
73
+ references: z.ZodArray<z.ZodString>;
74
+ isReply: z.ZodBoolean;
75
+ }, z.core.$strict>;
76
+ hasAttachments: z.ZodBoolean;
77
+ attachmentCount: z.ZodNumber;
78
+ attachments: z.ZodArray<z.ZodObject<{
79
+ filename: z.ZodNullable<z.ZodString>;
80
+ mimeType: z.ZodString;
81
+ size: z.ZodNullable<z.ZodNumber>;
82
+ kind: z.ZodEnum<{
83
+ image: "image";
84
+ document: "document";
85
+ pdf: "pdf";
86
+ spreadsheet: "spreadsheet";
87
+ presentation: "presentation";
88
+ archive: "archive";
89
+ audio: "audio";
90
+ video: "video";
91
+ other: "other";
92
+ }>;
93
+ }, z.core.$strict>>;
94
+ ref: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
95
+ kind: z.ZodLiteral<"imap">;
96
+ account: z.ZodString;
97
+ folder: z.ZodString;
98
+ uid: z.ZodNumber;
99
+ uidValidity: z.ZodOptional<z.ZodString>;
100
+ }, z.core.$strict>, z.ZodObject<{
101
+ kind: z.ZodLiteral<"gmail">;
102
+ account: z.ZodString;
103
+ messageId: z.ZodString;
104
+ }, z.core.$strict>], "kind">>;
105
+ messageHandle: z.ZodOptional<z.ZodString>;
106
+ }, z.core.$strict>;
107
+ /** Internal triage event passed to WebhookEmitter.emit (before wire formatting). */
108
+ export declare const webhookEventSchema: z.ZodObject<{
109
+ account: z.ZodOptional<z.ZodString>;
110
+ score: z.ZodOptional<z.ZodNumber>;
111
+ reason: z.ZodOptional<z.ZodString>;
112
+ message: z.ZodObject<{
113
+ uid: z.ZodOptional<z.ZodNumber>;
114
+ from: z.ZodNullable<z.ZodObject<{
115
+ address: z.ZodString;
116
+ name: z.ZodOptional<z.ZodString>;
117
+ }, z.core.$strict>>;
118
+ to: z.ZodArray<z.ZodObject<{
119
+ address: z.ZodString;
120
+ name: z.ZodOptional<z.ZodString>;
121
+ }, z.core.$strict>>;
122
+ cc: z.ZodArray<z.ZodObject<{
123
+ address: z.ZodString;
124
+ name: z.ZodOptional<z.ZodString>;
125
+ }, z.core.$strict>>;
126
+ subject: z.ZodString;
127
+ date: z.ZodNullable<z.ZodString>;
128
+ preview: z.ZodString;
129
+ thread: z.ZodObject<{
130
+ threadId: z.ZodString;
131
+ messageId: z.ZodNullable<z.ZodString>;
132
+ inReplyTo: z.ZodNullable<z.ZodString>;
133
+ references: z.ZodArray<z.ZodString>;
134
+ isReply: z.ZodBoolean;
135
+ }, z.core.$strict>;
136
+ hasAttachments: z.ZodBoolean;
137
+ attachmentCount: z.ZodNumber;
138
+ attachments: z.ZodArray<z.ZodObject<{
139
+ filename: z.ZodNullable<z.ZodString>;
140
+ mimeType: z.ZodString;
141
+ size: z.ZodNullable<z.ZodNumber>;
142
+ kind: z.ZodEnum<{
143
+ image: "image";
144
+ document: "document";
145
+ pdf: "pdf";
146
+ spreadsheet: "spreadsheet";
147
+ presentation: "presentation";
148
+ archive: "archive";
149
+ audio: "audio";
150
+ video: "video";
151
+ other: "other";
152
+ }>;
153
+ }, z.core.$strict>>;
154
+ ref: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
155
+ kind: z.ZodLiteral<"imap">;
156
+ account: z.ZodString;
157
+ folder: z.ZodString;
158
+ uid: z.ZodNumber;
159
+ uidValidity: z.ZodOptional<z.ZodString>;
160
+ }, z.core.$strict>, z.ZodObject<{
161
+ kind: z.ZodLiteral<"gmail">;
162
+ account: z.ZodString;
163
+ messageId: z.ZodString;
164
+ }, z.core.$strict>], "kind">>;
165
+ messageHandle: z.ZodOptional<z.ZodString>;
166
+ }, z.core.$strict>;
167
+ }, z.core.$strict>;
168
+ /** Wire payload POSTed to Ship ingest (`event: new_mail`). */
169
+ export declare const mailWebhookPayloadSchema: z.ZodObject<{
170
+ event: z.ZodLiteral<"new_mail">;
171
+ account: z.ZodOptional<z.ZodString>;
172
+ timestamp: z.ZodISODateTime;
173
+ score: z.ZodOptional<z.ZodNumber>;
174
+ reason: z.ZodOptional<z.ZodString>;
175
+ message: z.ZodString;
176
+ data: z.ZodObject<{
177
+ uid: z.ZodOptional<z.ZodNumber>;
178
+ from: z.ZodNullable<z.ZodObject<{
179
+ address: z.ZodString;
180
+ name: z.ZodOptional<z.ZodString>;
181
+ }, z.core.$strict>>;
182
+ to: z.ZodArray<z.ZodObject<{
183
+ address: z.ZodString;
184
+ name: z.ZodOptional<z.ZodString>;
185
+ }, z.core.$strict>>;
186
+ cc: z.ZodArray<z.ZodObject<{
187
+ address: z.ZodString;
188
+ name: z.ZodOptional<z.ZodString>;
189
+ }, z.core.$strict>>;
190
+ subject: z.ZodString;
191
+ date: z.ZodNullable<z.ZodString>;
192
+ preview: z.ZodString;
193
+ thread: z.ZodObject<{
194
+ threadId: z.ZodString;
195
+ messageId: z.ZodNullable<z.ZodString>;
196
+ inReplyTo: z.ZodNullable<z.ZodString>;
197
+ references: z.ZodArray<z.ZodString>;
198
+ isReply: z.ZodBoolean;
199
+ }, z.core.$strict>;
200
+ hasAttachments: z.ZodBoolean;
201
+ attachmentCount: z.ZodNumber;
202
+ attachments: z.ZodArray<z.ZodObject<{
203
+ filename: z.ZodNullable<z.ZodString>;
204
+ mimeType: z.ZodString;
205
+ size: z.ZodNullable<z.ZodNumber>;
206
+ kind: z.ZodEnum<{
207
+ image: "image";
208
+ document: "document";
209
+ pdf: "pdf";
210
+ spreadsheet: "spreadsheet";
211
+ presentation: "presentation";
212
+ archive: "archive";
213
+ audio: "audio";
214
+ video: "video";
215
+ other: "other";
216
+ }>;
217
+ }, z.core.$strict>>;
218
+ ref: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
219
+ kind: z.ZodLiteral<"imap">;
220
+ account: z.ZodString;
221
+ folder: z.ZodString;
222
+ uid: z.ZodNumber;
223
+ uidValidity: z.ZodOptional<z.ZodString>;
224
+ }, z.core.$strict>, z.ZodObject<{
225
+ kind: z.ZodLiteral<"gmail">;
226
+ account: z.ZodString;
227
+ messageId: z.ZodString;
228
+ }, z.core.$strict>], "kind">>;
229
+ messageHandle: z.ZodOptional<z.ZodString>;
230
+ }, z.core.$strict>;
231
+ }, z.core.$strict>;
232
+ export type AttachmentKind = z.infer<typeof attachmentKindSchema>;
233
+ export type WebhookAttachment = z.infer<typeof webhookAttachmentSchema>;
234
+ export type WebhookThread = z.infer<typeof webhookThreadSchema>;
235
+ export type WebhookRef = z.infer<typeof webhookRefSchema>;
236
+ export type WebhookMessage = z.infer<typeof webhookMessageSchema>;
237
+ export type WebhookEvent = z.infer<typeof webhookEventSchema>;
238
+ export type MailWebhookPayload = z.infer<typeof mailWebhookPayloadSchema>;
239
+ export declare function parseMailWebhookPayload(value: unknown): MailWebhookPayload;
240
+ export declare function parseWebhookEvent(value: unknown): WebhookEvent;
241
+ //# sourceMappingURL=mailWebhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mailWebhook.d.ts","sourceRoot":"","sources":["../src/mailWebhook.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,oBAAoB;;;;;;;;;;EAU/B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;kBAG5B,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;kBAKlC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;kBAM9B,CAAC;AAEH,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB;;;;;;;;;;4BAa3B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiB/B,CAAC;AAEH,oFAAoF;AACpF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAK7B,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBASnC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAE1E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAE9D"}
@@ -0,0 +1,91 @@
1
+ // Mail webhook contract shared by imap-mcp (producer) and rkt-ship (consumer).
2
+ // Pure types/schemas, no I/O. Authored in Zod v4 idiom.
3
+ import { z } from 'zod';
4
+ // ---------------------------------------------------------------------------
5
+ // Attachment kind — mirrors imap-mcp attachmentKind() output without importing it.
6
+ // ---------------------------------------------------------------------------
7
+ export const attachmentKindSchema = z.enum([
8
+ 'image',
9
+ 'document',
10
+ 'pdf',
11
+ 'spreadsheet',
12
+ 'presentation',
13
+ 'archive',
14
+ 'audio',
15
+ 'video',
16
+ 'other',
17
+ ]);
18
+ export const mailAddressSchema = z.strictObject({
19
+ address: z.string().min(1),
20
+ name: z.string().optional(),
21
+ });
22
+ export const webhookAttachmentSchema = z.strictObject({
23
+ filename: z.string().nullable(),
24
+ mimeType: z.string(),
25
+ size: z.number().nullable(),
26
+ kind: attachmentKindSchema,
27
+ });
28
+ export const webhookThreadSchema = z.strictObject({
29
+ threadId: z.string(),
30
+ messageId: z.string().nullable(),
31
+ inReplyTo: z.string().nullable(),
32
+ references: z.array(z.string()),
33
+ isReply: z.boolean(),
34
+ });
35
+ /** Backend-specific locator for the exact buzzed message. */
36
+ export const webhookRefSchema = z.discriminatedUnion('kind', [
37
+ z.strictObject({
38
+ kind: z.literal('imap'),
39
+ account: z.string().min(1),
40
+ folder: z.string().min(1),
41
+ uid: z.number().int().positive(),
42
+ uidValidity: z.string().optional(),
43
+ }),
44
+ z.strictObject({
45
+ kind: z.literal('gmail'),
46
+ account: z.string().min(1),
47
+ messageId: z.string().min(1),
48
+ }),
49
+ ]);
50
+ export const webhookMessageSchema = z.strictObject({
51
+ /** IMAP UID. Present for IMAP messages; absent for Gmail (use `ref` instead). */
52
+ uid: z.number().int().positive().optional(),
53
+ from: mailAddressSchema.nullable(),
54
+ to: z.array(mailAddressSchema),
55
+ cc: z.array(mailAddressSchema),
56
+ subject: z.string(),
57
+ date: z.string().nullable(),
58
+ preview: z.string(),
59
+ thread: webhookThreadSchema,
60
+ hasAttachments: z.boolean(),
61
+ attachmentCount: z.number().int().nonnegative(),
62
+ attachments: z.array(webhookAttachmentSchema),
63
+ /** Backend-agnostic locator for this message. Prefer this over `uid`. */
64
+ ref: webhookRefSchema.optional(),
65
+ /** Opaque msg_ handle minted at emit time; absent when minting failed or no ref. */
66
+ messageHandle: z.string().min(1).optional(),
67
+ });
68
+ /** Internal triage event passed to WebhookEmitter.emit (before wire formatting). */
69
+ export const webhookEventSchema = z.strictObject({
70
+ account: z.string().min(1).optional(),
71
+ score: z.number().optional(),
72
+ reason: z.string().optional(),
73
+ message: webhookMessageSchema,
74
+ });
75
+ /** Wire payload POSTed to Ship ingest (`event: new_mail`). */
76
+ export const mailWebhookPayloadSchema = z.strictObject({
77
+ event: z.literal('new_mail'),
78
+ account: z.string().min(1).optional(),
79
+ timestamp: z.iso.datetime({ offset: true }),
80
+ score: z.number().optional(),
81
+ reason: z.string().optional(),
82
+ /** Human-readable summary string (not the WebhookMessage object). */
83
+ message: z.string(),
84
+ data: webhookMessageSchema,
85
+ });
86
+ export function parseMailWebhookPayload(value) {
87
+ return mailWebhookPayloadSchema.parse(value);
88
+ }
89
+ export function parseWebhookEvent(value) {
90
+ return webhookEventSchema.parse(value);
91
+ }
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@rkt-tools/contracts",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Shared ingestion-envelope Zod schemas for the rkt stack",
5
5
  "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/daviesayo/rkt-comms.git",
9
+ "directory": "packages/contracts"
10
+ },
6
11
  "engines": {
7
12
  "node": ">=22"
8
13
  },