@webstir-io/module-contract 0.1.15 → 0.1.16

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/dist/index.js CHANGED
@@ -4,34 +4,150 @@ export const CONTRACT_VERSION = '1.0.0';
4
4
  export const contractVersionLiteral = z.literal(CONTRACT_VERSION);
5
5
  export const moduleKindSchema = z.enum(['frontend', 'backend']);
6
6
  export const logLevelSchema = z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']);
7
- export const moduleErrorCodeSchema = z.enum(['validation', 'auth', 'not_found', 'domain', 'conflict', 'internal']);
7
+ export const moduleErrorCodeSchema = z.enum([
8
+ 'validation',
9
+ 'auth',
10
+ 'not_found',
11
+ 'domain',
12
+ 'conflict',
13
+ 'internal',
14
+ ]);
8
15
  export const moduleErrorSchema = z.object({
9
16
  code: moduleErrorCodeSchema,
10
17
  message: z.string(),
11
18
  details: z.unknown().optional(),
12
19
  cause: z.unknown().optional(),
13
- correlationId: z.string().optional()
20
+ correlationId: z.string().optional(),
14
21
  });
15
- export const httpMethodSchema = z.enum(['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']);
22
+ export const httpMethodSchema = z.enum([
23
+ 'GET',
24
+ 'HEAD',
25
+ 'POST',
26
+ 'PUT',
27
+ 'PATCH',
28
+ 'DELETE',
29
+ 'OPTIONS',
30
+ ]);
31
+ export const routeInteractionKindSchema = z.enum(['navigation', 'mutation']);
32
+ export const formEncodingSchema = z.enum([
33
+ 'application/x-www-form-urlencoded',
34
+ 'multipart/form-data',
35
+ 'text/plain',
36
+ ]);
37
+ export const requestHookPhaseSchema = z.enum(['beforeAuth', 'beforeHandler', 'afterHandler']);
38
+ export const fragmentUpdateModeSchema = z.enum(['replace', 'append', 'prepend']);
39
+ export const redirectStatusSchema = z.union([
40
+ z.literal(301),
41
+ z.literal(302),
42
+ z.literal(303),
43
+ z.literal(307),
44
+ z.literal(308),
45
+ ]);
16
46
  export const schemaReferenceSchema = z.object({
17
47
  kind: z.enum(['zod', 'json-schema', 'ts-rest']).default('zod'),
18
48
  name: z.string(),
19
- source: z.string().optional()
49
+ source: z.string().optional(),
20
50
  });
51
+ export const requestHookReferenceSchema = z
52
+ .object({
53
+ id: z.string().min(1),
54
+ })
55
+ .strict();
56
+ export const requestHookDefinitionSchema = z
57
+ .object({
58
+ id: z.string().min(1),
59
+ phase: requestHookPhaseSchema,
60
+ order: z.number().int(),
61
+ summary: z.string().optional(),
62
+ description: z.string().optional(),
63
+ })
64
+ .strict();
21
65
  export const routeInputSchema = z
22
66
  .object({
23
67
  params: schemaReferenceSchema.optional(),
24
68
  query: schemaReferenceSchema.optional(),
25
69
  body: schemaReferenceSchema.optional(),
26
- headers: schemaReferenceSchema.optional()
70
+ headers: schemaReferenceSchema.optional(),
27
71
  })
28
72
  .partial()
29
73
  .strict();
30
- export const routeOutputSchema = z.object({
31
- body: schemaReferenceSchema,
74
+ export const sessionAccessModeSchema = z.enum(['optional', 'required']);
75
+ export const routeSessionSchema = z
76
+ .object({
77
+ mode: sessionAccessModeSchema.optional(),
78
+ write: z.boolean().optional(),
79
+ })
80
+ .strict();
81
+ export const flashLevelSchema = z.enum(['info', 'success', 'warning', 'error']);
82
+ export const flashPublishConditionSchema = z.enum(['always', 'success', 'error']);
83
+ export const routeFlashMessageSchema = z
84
+ .object({
85
+ key: z.string().min(1),
86
+ level: flashLevelSchema.optional(),
87
+ when: flashPublishConditionSchema.optional(),
88
+ })
89
+ .strict();
90
+ export const routeFlashSchema = z
91
+ .object({
92
+ consume: z.array(z.string().min(1)).optional(),
93
+ publish: z.array(routeFlashMessageSchema).optional(),
94
+ })
95
+ .strict();
96
+ export const routeFormSchema = z
97
+ .object({
98
+ contentType: formEncodingSchema.optional(),
99
+ csrf: z.boolean().optional(),
100
+ session: routeSessionSchema.optional(),
101
+ flash: routeFlashSchema.optional(),
102
+ })
103
+ .strict();
104
+ export const routeFragmentSchema = z
105
+ .object({
106
+ target: z.string().min(1),
107
+ selector: z.string().min(1).optional(),
108
+ mode: fragmentUpdateModeSchema.optional(),
109
+ })
110
+ .strict();
111
+ export const routeRedirectSchema = z
112
+ .object({
113
+ status: redirectStatusSchema.optional(),
114
+ location: z.string().min(1).optional(),
115
+ })
116
+ .strict();
117
+ const routeOutputBaseShape = {
32
118
  status: z.number().int().min(100).max(599).optional(),
33
- headers: schemaReferenceSchema.optional()
34
- });
119
+ headers: schemaReferenceSchema.optional(),
120
+ };
121
+ export const routeBodyOutputSchema = z
122
+ .object({
123
+ ...routeOutputBaseShape,
124
+ body: schemaReferenceSchema,
125
+ })
126
+ .strict();
127
+ export const routeRedirectOutputSchema = z
128
+ .object({
129
+ ...routeOutputBaseShape,
130
+ redirect: routeRedirectSchema,
131
+ })
132
+ .strict();
133
+ export const routeFragmentOutputSchema = z
134
+ .object({
135
+ ...routeOutputBaseShape,
136
+ body: schemaReferenceSchema,
137
+ fragment: routeFragmentSchema,
138
+ })
139
+ .strict();
140
+ export const routeOutputVariantSchema = z.union([
141
+ routeBodyOutputSchema,
142
+ routeRedirectOutputSchema,
143
+ routeFragmentOutputSchema,
144
+ ]);
145
+ export const routeOutputResponsesSchema = z
146
+ .object({
147
+ responses: z.array(routeOutputVariantSchema).min(1),
148
+ })
149
+ .strict();
150
+ export const routeOutputSchema = z.union([routeOutputVariantSchema, routeOutputResponsesSchema]);
35
151
  export const routeDefinitionSchema = z.object({
36
152
  name: z.string().min(1),
37
153
  method: httpMethodSchema,
@@ -39,6 +155,12 @@ export const routeDefinitionSchema = z.object({
39
155
  summary: z.string().optional(),
40
156
  description: z.string().optional(),
41
157
  tags: z.array(z.string()).optional(),
158
+ interaction: routeInteractionKindSchema.optional(),
159
+ requestHooks: z.array(requestHookReferenceSchema).optional(),
160
+ session: routeSessionSchema.optional(),
161
+ flash: routeFlashSchema.optional(),
162
+ form: routeFormSchema.optional(),
163
+ fragment: routeFragmentSchema.optional(),
42
164
  input: routeInputSchema.optional(),
43
165
  output: routeOutputSchema.optional(),
44
166
  errors: z.array(moduleErrorSchema).optional(),
@@ -46,9 +168,9 @@ export const routeDefinitionSchema = z.object({
46
168
  staticPaths: z.array(z.string().min(1)).optional(),
47
169
  ssg: z
48
170
  .object({
49
- revalidateSeconds: z.number().int().positive().optional()
171
+ revalidateSeconds: z.number().int().positive().optional(),
50
172
  })
51
- .optional()
173
+ .optional(),
52
174
  });
53
175
  export const viewDefinitionSchema = z.object({
54
176
  name: z.string().min(1),
@@ -62,24 +184,24 @@ export const viewDefinitionSchema = z.object({
62
184
  staticPaths: z.array(z.string().min(1)).optional(),
63
185
  ssg: z
64
186
  .object({
65
- revalidateSeconds: z.number().int().positive().optional()
187
+ revalidateSeconds: z.number().int().positive().optional(),
66
188
  })
67
- .optional()
189
+ .optional(),
68
190
  });
69
191
  export const jobDefinitionSchema = z.object({
70
192
  name: z.string().min(1),
71
193
  schedule: z.string().optional(),
72
194
  description: z.string().optional(),
73
- priority: z.union([z.number().int(), z.string()]).optional()
195
+ priority: z.union([z.number().int(), z.string()]).optional(),
74
196
  });
75
197
  export const eventDefinitionSchema = z.object({
76
198
  name: z.string().min(1),
77
199
  payload: schemaReferenceSchema.optional(),
78
- description: z.string().optional()
200
+ description: z.string().optional(),
79
201
  });
80
202
  export const serviceDefinitionSchema = z.object({
81
203
  name: z.string().min(1),
82
- description: z.string().optional()
204
+ description: z.string().optional(),
83
205
  });
84
206
  export const moduleManifestSchema = z.object({
85
207
  contractVersion: z.string().min(1),
@@ -89,14 +211,14 @@ export const moduleManifestSchema = z.object({
89
211
  capabilities: z.array(z.string()).optional(),
90
212
  // New: optional pass-through lists
91
213
  assets: z.array(z.string()).optional(),
92
- middlewares: z.array(z.string()).optional(),
214
+ requestHooks: z.array(requestHookDefinitionSchema).optional(),
93
215
  routes: z.array(routeDefinitionSchema).optional(),
94
216
  views: z.array(viewDefinitionSchema).optional(),
95
217
  jobs: z.array(jobDefinitionSchema).optional(),
96
218
  events: z.array(eventDefinitionSchema).optional(),
97
219
  services: z.array(serviceDefinitionSchema).optional(),
98
220
  init: z.string().optional(),
99
- dispose: z.string().optional()
221
+ dispose: z.string().optional(),
100
222
  });
101
223
  export function defineRoute(spec) {
102
224
  return spec;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstir-io/module-contract",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Public contract definitions for Webstir frontend and backend module providers.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,12 +24,12 @@
24
24
  ],
25
25
  "scripts": {
26
26
  "clean": "rm -rf dist schema",
27
- "build": "tsc -p tsconfig.json && node scripts/build-schema.mjs",
27
+ "build": "tsc -p tsconfig.json && bun scripts/build-schema.mjs",
28
28
  "build:types": "tsc -p tsconfig.json",
29
- "build:schema": "node scripts/build-schema.mjs",
30
- "test": "tsc -p tsconfig.json && node scripts/build-schema.mjs && tsc -p tsconfig.examples.json",
29
+ "build:schema": "bun scripts/build-schema.mjs",
30
+ "test": "tsc -p tsconfig.json && bun scripts/build-schema.mjs && tsc -p tsconfig.examples.json",
31
31
  "test:examples": "tsc -p tsconfig.examples.json",
32
- "smoke": "node -e \"console.log('[smoke] no smoke tests configured');\"",
32
+ "smoke": "bun -e \"console.log('[smoke] no smoke tests configured');\"",
33
33
  "release": "bash scripts/publish.sh"
34
34
  },
35
35
  "keywords": [
@@ -35,10 +35,39 @@
35
35
  "type": "string"
36
36
  }
37
37
  },
38
- "middlewares": {
38
+ "requestHooks": {
39
39
  "type": "array",
40
40
  "items": {
41
- "type": "string"
41
+ "type": "object",
42
+ "properties": {
43
+ "id": {
44
+ "type": "string",
45
+ "minLength": 1
46
+ },
47
+ "phase": {
48
+ "type": "string",
49
+ "enum": [
50
+ "beforeAuth",
51
+ "beforeHandler",
52
+ "afterHandler"
53
+ ]
54
+ },
55
+ "order": {
56
+ "type": "integer"
57
+ },
58
+ "summary": {
59
+ "type": "string"
60
+ },
61
+ "description": {
62
+ "type": "string"
63
+ }
64
+ },
65
+ "required": [
66
+ "id",
67
+ "phase",
68
+ "order"
69
+ ],
70
+ "additionalProperties": false
42
71
  }
43
72
  },
44
73
  "routes": {
@@ -78,6 +107,139 @@
78
107
  "type": "string"
79
108
  }
80
109
  },
110
+ "interaction": {
111
+ "type": "string",
112
+ "enum": [
113
+ "navigation",
114
+ "mutation"
115
+ ]
116
+ },
117
+ "requestHooks": {
118
+ "type": "array",
119
+ "items": {
120
+ "type": "object",
121
+ "properties": {
122
+ "id": {
123
+ "type": "string",
124
+ "minLength": 1
125
+ }
126
+ },
127
+ "required": [
128
+ "id"
129
+ ],
130
+ "additionalProperties": false
131
+ }
132
+ },
133
+ "session": {
134
+ "type": "object",
135
+ "properties": {
136
+ "mode": {
137
+ "type": "string",
138
+ "enum": [
139
+ "optional",
140
+ "required"
141
+ ]
142
+ },
143
+ "write": {
144
+ "type": "boolean"
145
+ }
146
+ },
147
+ "additionalProperties": false
148
+ },
149
+ "flash": {
150
+ "type": "object",
151
+ "properties": {
152
+ "consume": {
153
+ "type": "array",
154
+ "items": {
155
+ "type": "string",
156
+ "minLength": 1
157
+ }
158
+ },
159
+ "publish": {
160
+ "type": "array",
161
+ "items": {
162
+ "type": "object",
163
+ "properties": {
164
+ "key": {
165
+ "type": "string",
166
+ "minLength": 1
167
+ },
168
+ "level": {
169
+ "type": "string",
170
+ "enum": [
171
+ "info",
172
+ "success",
173
+ "warning",
174
+ "error"
175
+ ]
176
+ },
177
+ "when": {
178
+ "type": "string",
179
+ "enum": [
180
+ "always",
181
+ "success",
182
+ "error"
183
+ ]
184
+ }
185
+ },
186
+ "required": [
187
+ "key"
188
+ ],
189
+ "additionalProperties": false
190
+ }
191
+ }
192
+ },
193
+ "additionalProperties": false
194
+ },
195
+ "form": {
196
+ "type": "object",
197
+ "properties": {
198
+ "contentType": {
199
+ "type": "string",
200
+ "enum": [
201
+ "application/x-www-form-urlencoded",
202
+ "multipart/form-data",
203
+ "text/plain"
204
+ ]
205
+ },
206
+ "csrf": {
207
+ "type": "boolean"
208
+ },
209
+ "session": {
210
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/session"
211
+ },
212
+ "flash": {
213
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/flash"
214
+ }
215
+ },
216
+ "additionalProperties": false
217
+ },
218
+ "fragment": {
219
+ "type": "object",
220
+ "properties": {
221
+ "target": {
222
+ "type": "string",
223
+ "minLength": 1
224
+ },
225
+ "selector": {
226
+ "type": "string",
227
+ "minLength": 1
228
+ },
229
+ "mode": {
230
+ "type": "string",
231
+ "enum": [
232
+ "replace",
233
+ "append",
234
+ "prepend"
235
+ ]
236
+ }
237
+ },
238
+ "required": [
239
+ "target"
240
+ ],
241
+ "additionalProperties": false
242
+ },
81
243
  "input": {
82
244
  "type": "object",
83
245
  "properties": {
@@ -118,24 +280,105 @@
118
280
  "additionalProperties": false
119
281
  },
120
282
  "output": {
121
- "type": "object",
122
- "properties": {
123
- "body": {
124
- "$ref": "#/definitions/module-manifest/properties/routes/items/properties/input/properties/params"
125
- },
126
- "status": {
127
- "type": "integer",
128
- "minimum": 100,
129
- "maximum": 599
283
+ "anyOf": [
284
+ {
285
+ "anyOf": [
286
+ {
287
+ "type": "object",
288
+ "properties": {
289
+ "status": {
290
+ "type": "integer",
291
+ "minimum": 100,
292
+ "maximum": 599
293
+ },
294
+ "headers": {
295
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/input/properties/params"
296
+ },
297
+ "body": {
298
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/input/properties/params"
299
+ }
300
+ },
301
+ "required": [
302
+ "body"
303
+ ],
304
+ "additionalProperties": false
305
+ },
306
+ {
307
+ "type": "object",
308
+ "properties": {
309
+ "status": {
310
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/output/anyOf/0/anyOf/0/properties/status"
311
+ },
312
+ "headers": {
313
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/output/anyOf/0/anyOf/0/properties/headers"
314
+ },
315
+ "redirect": {
316
+ "type": "object",
317
+ "properties": {
318
+ "status": {
319
+ "type": "number",
320
+ "enum": [
321
+ 301,
322
+ 302,
323
+ 303,
324
+ 307,
325
+ 308
326
+ ]
327
+ },
328
+ "location": {
329
+ "type": "string",
330
+ "minLength": 1
331
+ }
332
+ },
333
+ "additionalProperties": false
334
+ }
335
+ },
336
+ "required": [
337
+ "redirect"
338
+ ],
339
+ "additionalProperties": false
340
+ },
341
+ {
342
+ "type": "object",
343
+ "properties": {
344
+ "status": {
345
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/output/anyOf/0/anyOf/0/properties/status"
346
+ },
347
+ "headers": {
348
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/output/anyOf/0/anyOf/0/properties/headers"
349
+ },
350
+ "body": {
351
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/input/properties/params"
352
+ },
353
+ "fragment": {
354
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/fragment"
355
+ }
356
+ },
357
+ "required": [
358
+ "body",
359
+ "fragment"
360
+ ],
361
+ "additionalProperties": false
362
+ }
363
+ ]
130
364
  },
131
- "headers": {
132
- "$ref": "#/definitions/module-manifest/properties/routes/items/properties/input/properties/params"
365
+ {
366
+ "type": "object",
367
+ "properties": {
368
+ "responses": {
369
+ "type": "array",
370
+ "items": {
371
+ "$ref": "#/definitions/module-manifest/properties/routes/items/properties/output/anyOf/0"
372
+ },
373
+ "minItems": 1
374
+ }
375
+ },
376
+ "required": [
377
+ "responses"
378
+ ],
379
+ "additionalProperties": false
133
380
  }
134
- },
135
- "required": [
136
- "body"
137
- ],
138
- "additionalProperties": false
381
+ ]
139
382
  },
140
383
  "errors": {
141
384
  "type": "array",