@newhomestar/sdk 0.5.2 → 0.6.5

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.
@@ -0,0 +1,416 @@
1
+ // nova-sdk – Integration Definition API
2
+ // =====================================================
3
+ // Code-first integration definitions with Zod schemas.
4
+ // Integrations are containerized services (like workers) that ALSO
5
+ // carry schema/event/function configuration synced to the platform DB.
6
+ //
7
+ // TWO API styles supported:
8
+ // Verbose: integrationSchema({ name, slug, schemaType, schema, version })
9
+ // Lean: schema("entity", z.object({...})) ← slug/name inferred from key
10
+ // -----------------------------------------------------------
11
+ import { z } from "zod";
12
+ /** Symbol used to tag lean schema/event wrappers (non-enumerable) */
13
+ const NOVA_SCHEMA = Symbol.for('nova.schema');
14
+ const NOVA_EVENT = Symbol.for('nova.event');
15
+ /**
16
+ * **Verbose** helper — define a schema with all metadata explicitly.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const WorkerProfile = integrationSchema({
21
+ * name: "Worker Profile",
22
+ * slug: "worker_profile",
23
+ * schemaType: "entity",
24
+ * schema: z.object({ workerId: z.string() }),
25
+ * });
26
+ * ```
27
+ */
28
+ export function integrationSchema(cfg) {
29
+ return cfg;
30
+ }
31
+ /**
32
+ * **Lean** helper — slug and name are inferred from the key in `schemas: {}`.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const User = schema("entity", z.object({
37
+ * id: z.string(),
38
+ * email: z.string().email(),
39
+ * }));
40
+ *
41
+ * // In defineIntegration:
42
+ * schemas: { user: User }
43
+ * // → slug: "user", name: "User", schemaType: "entity"
44
+ * ```
45
+ */
46
+ export function schema(schemaType, zodSchema, opts) {
47
+ const def = {
48
+ name: '', // filled from key by defineIntegration()
49
+ slug: '', // filled from key by defineIntegration()
50
+ schemaType,
51
+ schema: zodSchema,
52
+ version: opts?.version ?? '1.0.0',
53
+ description: opts?.description,
54
+ shape: zodSchema, // convenience alias for direct Zod reference
55
+ };
56
+ Object.defineProperty(def, NOVA_SCHEMA, { value: true, enumerable: false });
57
+ return def;
58
+ }
59
+ /**
60
+ * **Verbose** helper — define an event with all metadata explicitly.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const workerHire = integrationEvent({
65
+ * slug: "worker.hire",
66
+ * name: "Worker Hired",
67
+ * direction: "inbound",
68
+ * category: "lifecycle",
69
+ * severity: "info",
70
+ * payloadSchema: "new_hire_payload",
71
+ * });
72
+ * ```
73
+ */
74
+ export function integrationEvent(cfg) {
75
+ return cfg;
76
+ }
77
+ /**
78
+ * **Lean** helper — slug and name inferred from key in `events: {}`.
79
+ * Payload can reference a `schema()` result directly (type-safe, no strings).
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * const User = schema("entity", z.object({ id: z.string() }));
84
+ *
85
+ * // In defineIntegration:
86
+ * events: {
87
+ * user_synced: event("outbound", { payload: User }),
88
+ * sync_failed: event("outbound", { severity: "error" }),
89
+ * }
90
+ * ```
91
+ */
92
+ export function event(direction, opts) {
93
+ const def = {
94
+ slug: '', // filled from key by defineIntegration()
95
+ name: '', // filled from key by defineIntegration()
96
+ direction,
97
+ severity: opts?.severity,
98
+ category: opts?.category,
99
+ description: opts?.description,
100
+ };
101
+ // Store payload reference for resolution during normalization
102
+ if (opts?.payload) {
103
+ Object.defineProperty(def, '__payloadRef', { value: opts.payload, enumerable: false });
104
+ }
105
+ Object.defineProperty(def, NOVA_EVENT, { value: true, enumerable: false });
106
+ return def;
107
+ }
108
+ /**
109
+ * Helper to define an integration function (API endpoint).
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * const listWorkers = integrationFunction({
114
+ * slug: "list_workers",
115
+ * name: "List Workers",
116
+ * httpMethod: "GET",
117
+ * endpointPath: "/hr/v2/workers",
118
+ * responseSchema: "worker_profile",
119
+ * requiredScopes: ["api"],
120
+ * category: "workers",
121
+ * });
122
+ * ```
123
+ */
124
+ export function integrationFunction(cfg) {
125
+ return cfg;
126
+ }
127
+ /*─────────────────────────* Zod Validation Schema *──────────────────────────*/
128
+ const IntegrationSchemaDefSchema = z.object({
129
+ name: z.string(),
130
+ slug: z.string().regex(/^[a-z][a-z0-9_]*$/, 'Schema slug must be snake_case'),
131
+ description: z.string().optional(),
132
+ schemaType: z.enum(['request', 'response', 'entity', 'webhook_payload', 'configuration']),
133
+ schema: z.any(), // Zod schema instance
134
+ version: z.string().optional(),
135
+ });
136
+ const IntegrationEventDefSchema = z.object({
137
+ slug: z.string(),
138
+ name: z.string(),
139
+ direction: z.enum(['inbound', 'outbound', 'bidirectional']),
140
+ description: z.string().optional(),
141
+ category: z.string().optional(),
142
+ severity: z.enum(['info', 'warning', 'error', 'critical']).optional(),
143
+ payloadSchema: z.string().optional(),
144
+ });
145
+ const IntegrationFunctionDefSchema = z.object({
146
+ slug: z.string().regex(/^[a-z][a-z0-9_]*$/, 'Function slug must be snake_case'),
147
+ name: z.string(),
148
+ httpMethod: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']),
149
+ endpointPath: z.string(),
150
+ description: z.string().optional(),
151
+ requestSchema: z.string().optional(),
152
+ responseSchema: z.string().optional(),
153
+ requiredScopes: z.array(z.string()).optional(),
154
+ category: z.string().optional(),
155
+ capabilities: z.array(z.union([z.string(), z.record(z.string(), z.unknown())])).optional(),
156
+ });
157
+ export const IntegrationDefSchema = z.object({
158
+ slug: z.string().regex(/^[a-z][a-z0-9_]*$/, 'Integration slug must be snake_case'),
159
+ name: z.string(),
160
+ description: z.string().optional(),
161
+ integrationType: z.enum(['oidc', 'oauth2', 'api_key']),
162
+ category: z.string().optional(),
163
+ logoUrl: z.string().optional(),
164
+ color: z.string().optional(),
165
+ authorizationEndpoint: z.string().optional(),
166
+ tokenEndpoint: z.string().optional(),
167
+ userinfoEndpoint: z.string().optional(),
168
+ revocationEndpoint: z.string().optional(),
169
+ jwksUri: z.string().optional(),
170
+ baseUrl: z.string().optional(),
171
+ scopes: z.array(z.string()).optional(),
172
+ queue: z.string(),
173
+ displayName: z.string().optional(),
174
+ icon: z.string().optional(),
175
+ tags: z.array(z.string()).optional(),
176
+ ui: z.object({
177
+ category: z.string().optional(),
178
+ color: z.string().optional(),
179
+ }).optional(),
180
+ resources: z.object({
181
+ cpu: z.string(),
182
+ memory: z.string(),
183
+ }).optional(),
184
+ envSpec: z.array(z.object({
185
+ name: z.string(),
186
+ secret: z.boolean(),
187
+ default: z.string().optional(),
188
+ })).optional(),
189
+ actions: z.record(z.string(), z.any()),
190
+ schemas: z.record(z.string(), IntegrationSchemaDefSchema),
191
+ events: z.record(z.string(), IntegrationEventDefSchema),
192
+ functions: z.record(z.string(), IntegrationFunctionDefSchema),
193
+ });
194
+ /**
195
+ * Validate an integration definition before build or push.
196
+ *
197
+ * Performs conditional validation based on `integrationType`:
198
+ * - **Always required**: slug, name, queue, baseUrl, ≥1 action
199
+ * - **OAuth2/OIDC required**: authorizationEndpoint, tokenEndpoint
200
+ * - **OIDC warned**: jwksUri, userinfoEndpoint
201
+ * - **Warnings**: no schemas, no scopes, non-HTTPS URLs, no health action
202
+ *
203
+ * Called automatically during `nova integrations build` and `nova integrations push`.
204
+ *
205
+ * @example
206
+ * ```ts
207
+ * const result = validateIntegration(myIntegration);
208
+ * if (!result.valid) {
209
+ * result.errors.forEach(e => console.error(`❌ ${e}`));
210
+ * process.exit(1);
211
+ * }
212
+ * result.warnings.forEach(w => console.warn(`⚠️ ${w}`));
213
+ * ```
214
+ */
215
+ export function validateIntegration(def) {
216
+ const errors = [];
217
+ const warnings = [];
218
+ // ── Always required ──
219
+ if (!def.slug)
220
+ errors.push("'slug' is required");
221
+ if (!def.name)
222
+ errors.push("'name' is required");
223
+ if (!def.queue)
224
+ errors.push("'queue' is required");
225
+ if (!def.baseUrl || def.baseUrl.trim() === '') {
226
+ errors.push("'baseUrl' is required — the base URL for API calls (e.g., https://api.example.com)");
227
+ }
228
+ if (!def.actions || Object.keys(def.actions).length === 0) {
229
+ errors.push("at least one action is required");
230
+ }
231
+ // ── OAuth2 / OIDC specific ──
232
+ if (def.integrationType === 'oauth2' || def.integrationType === 'oidc') {
233
+ if (!def.authorizationEndpoint || def.authorizationEndpoint.trim() === '') {
234
+ errors.push(`'authorizationEndpoint' is required for ${def.integrationType} integrations`);
235
+ }
236
+ if (!def.tokenEndpoint || def.tokenEndpoint.trim() === '') {
237
+ errors.push(`'tokenEndpoint' is required for ${def.integrationType} integrations`);
238
+ }
239
+ if (!def.scopes || def.scopes.length === 0) {
240
+ warnings.push(`no 'scopes' defined for ${def.integrationType} integration — most providers require at least one`);
241
+ }
242
+ }
243
+ // ── OIDC specific ──
244
+ if (def.integrationType === 'oidc') {
245
+ if (!def.jwksUri) {
246
+ warnings.push("'jwksUri' not set for OIDC integration — required for token verification");
247
+ }
248
+ if (!def.userinfoEndpoint) {
249
+ warnings.push("'userinfoEndpoint' not set for OIDC integration");
250
+ }
251
+ }
252
+ // ── URL format validation ──
253
+ const urlFields = [
254
+ ['authorizationEndpoint', def.authorizationEndpoint],
255
+ ['tokenEndpoint', def.tokenEndpoint],
256
+ ['baseUrl', def.baseUrl],
257
+ ['userinfoEndpoint', def.userinfoEndpoint],
258
+ ['revocationEndpoint', def.revocationEndpoint],
259
+ ['jwksUri', def.jwksUri],
260
+ ];
261
+ for (const [fieldName, value] of urlFields) {
262
+ if (value && value.trim() !== '' && !value.startsWith('https://') && !value.startsWith('http://localhost')) {
263
+ warnings.push(`'${fieldName}' should use HTTPS: "${value}"`);
264
+ }
265
+ }
266
+ // ── Structural checks ──
267
+ if (!def.schemas || Object.keys(def.schemas).length === 0) {
268
+ warnings.push("no schemas defined — consider adding at least one entity schema");
269
+ }
270
+ if (def.actions && !def.actions['health'] && !def.actions['healthCheck']) {
271
+ warnings.push("no 'health' action defined — recommended for all integrations");
272
+ }
273
+ if (!def.envSpec || def.envSpec.length === 0) {
274
+ warnings.push("no 'envSpec' defined — environment variables won't be validated at deploy time");
275
+ }
276
+ return {
277
+ valid: errors.length === 0,
278
+ errors,
279
+ warnings,
280
+ };
281
+ }
282
+ /*─────────────────────────* defineIntegration() *──────────────────────────*/
283
+ /**
284
+ * Register an integration definition — the single source of truth for both
285
+ * the containerized runtime AND the platform configuration.
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * export default defineIntegration({
290
+ * slug: "adp_workforce_now",
291
+ * name: "ADP Workforce Now",
292
+ * integrationType: "oidc",
293
+ * queue: "adp_integration_queue",
294
+ * schemas: { ... },
295
+ * events: { ... },
296
+ * functions: { ... },
297
+ * actions: {
298
+ * health: action({ ... }),
299
+ * handleWebhook: action({ ... }),
300
+ * },
301
+ * });
302
+ * ```
303
+ */
304
+ /** Convert a key like "user_profile" → "User Profile" */
305
+ function slugToName(slug) {
306
+ return slug
307
+ .replace(/_/g, ' ')
308
+ .replace(/\b\w/g, c => c.toUpperCase());
309
+ }
310
+ /** Convert camelCase key like "listUsers" → "list_users" */
311
+ function camelToSnake(str) {
312
+ return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
313
+ }
314
+ export function defineIntegration(def) {
315
+ // ── Phase 1: Normalize lean schemas ──
316
+ // Fill slug/name from the key when using schema() helper
317
+ for (const [key, schemaDef] of Object.entries(def.schemas)) {
318
+ if (!schemaDef.slug || schemaDef.slug === '') {
319
+ schemaDef.slug = key;
320
+ }
321
+ if (!schemaDef.name || schemaDef.name === '') {
322
+ schemaDef.name = slugToName(key);
323
+ }
324
+ }
325
+ // ── Phase 2: Normalize lean events ──
326
+ // Fill slug/name from the key and resolve payload references
327
+ for (const [key, eventDef] of Object.entries(def.events)) {
328
+ if (!eventDef.slug || eventDef.slug === '') {
329
+ eventDef.slug = key;
330
+ }
331
+ if (!eventDef.name || eventDef.name === '') {
332
+ eventDef.name = slugToName(key);
333
+ }
334
+ // Resolve direct payload reference → schema slug string
335
+ const payloadRef = eventDef.__payloadRef;
336
+ if (payloadRef && !eventDef.payloadSchema) {
337
+ for (const [schemaKey, schemaDef] of Object.entries(def.schemas)) {
338
+ if (schemaDef === payloadRef ||
339
+ schemaDef.shape === payloadRef ||
340
+ schemaDef.schema === payloadRef) {
341
+ eventDef.payloadSchema = schemaKey;
342
+ break;
343
+ }
344
+ }
345
+ }
346
+ }
347
+ // ── Phase 3: Auto-extract functions from ALL actions ──
348
+ // Every action is promoted to a function entry so it's synced to the DB
349
+ // and visible in the Service Mode tester. Actions with scopes get those
350
+ // recorded; actions without scopes (e.g., health, handleWebhook) are
351
+ // still registered so the admin UI can discover and invoke them.
352
+ if (!def.functions) {
353
+ def.functions = {};
354
+ }
355
+ for (const [key, actionDef] of Object.entries(def.actions)) {
356
+ const snakeKey = camelToSnake(key);
357
+ // Skip if already explicitly declared in functions map
358
+ if (def.functions[snakeKey])
359
+ continue;
360
+ const scopes = actionDef.scopes || actionDef.requiredScopes;
361
+ const fnEntry = {
362
+ slug: snakeKey,
363
+ name: slugToName(snakeKey),
364
+ httpMethod: (actionDef.method || 'POST').toUpperCase(),
365
+ endpointPath: actionDef.path || `/${snakeKey}`,
366
+ description: actionDef.description || '',
367
+ requiredScopes: scopes && Array.isArray(scopes) ? scopes : [],
368
+ category: actionDef.category || '',
369
+ capabilities: actionDef.capabilities || [],
370
+ };
371
+ def.functions[snakeKey] = fnEntry;
372
+ // Store Zod input/output as non-enumerable props for build step to
373
+ // convert to JSON Schema → inputSchema / outputSchema DB columns.
374
+ if (actionDef.input) {
375
+ Object.defineProperty(fnEntry, '__inputZod', {
376
+ value: actionDef.input,
377
+ enumerable: false,
378
+ });
379
+ }
380
+ if (actionDef.output) {
381
+ Object.defineProperty(fnEntry, '__outputZod', {
382
+ value: actionDef.output,
383
+ enumerable: false,
384
+ });
385
+ }
386
+ // Store params metadata for the CLI build step to embed
387
+ // x-nova-* extensions into JSON Schema output.
388
+ if (actionDef.params) {
389
+ Object.defineProperty(fnEntry, '__paramsMeta', {
390
+ value: actionDef.params,
391
+ enumerable: false,
392
+ });
393
+ }
394
+ }
395
+ // ── Phase 4: Validate with Zod ──
396
+ IntegrationDefSchema.parse(def);
397
+ // ── Phase 5: Cross-validate schema references in events ──
398
+ for (const [eventKey, eventDef] of Object.entries(def.events)) {
399
+ if (eventDef.payloadSchema && !def.schemas[eventDef.payloadSchema]) {
400
+ throw new Error(`Event '${eventKey}' references payloadSchema '${eventDef.payloadSchema}' ` +
401
+ `which is not defined in schemas. Available schemas: ${Object.keys(def.schemas).join(', ')}`);
402
+ }
403
+ }
404
+ // ── Phase 6: Cross-validate schema references in functions ──
405
+ for (const [fnKey, fn] of Object.entries(def.functions)) {
406
+ if (fn.requestSchema && !def.schemas[fn.requestSchema]) {
407
+ throw new Error(`Function '${fnKey}' references requestSchema '${fn.requestSchema}' ` +
408
+ `which is not defined in schemas. Available schemas: ${Object.keys(def.schemas).join(', ')}`);
409
+ }
410
+ if (fn.responseSchema && !def.schemas[fn.responseSchema]) {
411
+ throw new Error(`Function '${fnKey}' references responseSchema '${fn.responseSchema}' ` +
412
+ `which is not defined in schemas. Available schemas: ${Object.keys(def.schemas).join(', ')}`);
413
+ }
414
+ }
415
+ return def;
416
+ }
@@ -0,0 +1,204 @@
1
+ import { z } from "zod";
2
+ export declare const IntegrationSpecSchema: z.ZodObject<{
3
+ apiVersion: z.ZodString;
4
+ kind: z.ZodLiteral<"Integration">;
5
+ metadata: z.ZodObject<{
6
+ slug: z.ZodString;
7
+ name: z.ZodString;
8
+ displayName: z.ZodOptional<z.ZodString>;
9
+ description: z.ZodOptional<z.ZodString>;
10
+ category: z.ZodOptional<z.ZodString>;
11
+ icon: z.ZodOptional<z.ZodString>;
12
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
13
+ logoUrl: z.ZodOptional<z.ZodString>;
14
+ color: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strip>;
16
+ spec: z.ZodObject<{
17
+ type: z.ZodEnum<{
18
+ api_key: "api_key";
19
+ oidc: "oidc";
20
+ oauth2: "oauth2";
21
+ }>;
22
+ endpoints: z.ZodOptional<z.ZodObject<{
23
+ authorization: z.ZodOptional<z.ZodString>;
24
+ token: z.ZodOptional<z.ZodString>;
25
+ userinfo: z.ZodOptional<z.ZodString>;
26
+ revocation: z.ZodOptional<z.ZodString>;
27
+ jwks: z.ZodOptional<z.ZodString>;
28
+ baseUrl: z.ZodOptional<z.ZodString>;
29
+ }, z.core.$strip>>;
30
+ scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
31
+ runtime: z.ZodObject<{
32
+ type: z.ZodString;
33
+ image: z.ZodString;
34
+ queue: z.ZodString;
35
+ port: z.ZodOptional<z.ZodNumber>;
36
+ command: z.ZodArray<z.ZodString>;
37
+ resources: z.ZodObject<{
38
+ cpu: z.ZodString;
39
+ memory: z.ZodString;
40
+ }, z.core.$strip>;
41
+ envSpec: z.ZodOptional<z.ZodArray<z.ZodObject<{
42
+ name: z.ZodString;
43
+ value: z.ZodOptional<z.ZodString>;
44
+ secret: z.ZodOptional<z.ZodBoolean>;
45
+ default: z.ZodOptional<z.ZodString>;
46
+ }, z.core.$strip>>>;
47
+ }, z.core.$strip>;
48
+ actions: z.ZodArray<z.ZodObject<{
49
+ name: z.ZodString;
50
+ displayName: z.ZodOptional<z.ZodString>;
51
+ description: z.ZodOptional<z.ZodString>;
52
+ async: z.ZodOptional<z.ZodBoolean>;
53
+ input: z.ZodOptional<z.ZodUnknown>;
54
+ output: z.ZodOptional<z.ZodUnknown>;
55
+ schema: z.ZodOptional<z.ZodObject<{
56
+ input: z.ZodString;
57
+ output: z.ZodString;
58
+ }, z.core.$strip>>;
59
+ fga: z.ZodOptional<z.ZodObject<{
60
+ resourceType: z.ZodString;
61
+ relation: z.ZodString;
62
+ }, z.core.$strip>>;
63
+ capabilities: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
64
+ type: z.ZodLiteral<"webhook">;
65
+ eventTypes: z.ZodArray<z.ZodString>;
66
+ source: z.ZodString;
67
+ endpoint: z.ZodOptional<z.ZodString>;
68
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
69
+ authentication: z.ZodOptional<z.ZodObject<{
70
+ type: z.ZodEnum<{
71
+ bearer: "bearer";
72
+ basic: "basic";
73
+ api_key: "api_key";
74
+ signature: "signature";
75
+ }>;
76
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
77
+ }, z.core.$strip>>;
78
+ }, z.core.$strip>, z.ZodObject<{
79
+ type: z.ZodLiteral<"scheduled">;
80
+ cron: z.ZodString;
81
+ timezone: z.ZodOptional<z.ZodString>;
82
+ description: z.ZodOptional<z.ZodString>;
83
+ }, z.core.$strip>, z.ZodObject<{
84
+ type: z.ZodLiteral<"queue">;
85
+ topics: z.ZodArray<z.ZodString>;
86
+ queueName: z.ZodOptional<z.ZodString>;
87
+ consumerGroup: z.ZodOptional<z.ZodString>;
88
+ }, z.core.$strip>, z.ZodObject<{
89
+ type: z.ZodLiteral<"stream">;
90
+ streamName: z.ZodString;
91
+ eventTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
92
+ consumerGroup: z.ZodOptional<z.ZodString>;
93
+ }, z.core.$strip>]>>>;
94
+ }, z.core.$strip>>;
95
+ capabilities: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
96
+ type: z.ZodLiteral<"webhook">;
97
+ eventTypes: z.ZodArray<z.ZodString>;
98
+ source: z.ZodString;
99
+ endpoint: z.ZodOptional<z.ZodString>;
100
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
101
+ authentication: z.ZodOptional<z.ZodObject<{
102
+ type: z.ZodEnum<{
103
+ bearer: "bearer";
104
+ basic: "basic";
105
+ api_key: "api_key";
106
+ signature: "signature";
107
+ }>;
108
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
109
+ }, z.core.$strip>>;
110
+ }, z.core.$strip>, z.ZodObject<{
111
+ type: z.ZodLiteral<"scheduled">;
112
+ cron: z.ZodString;
113
+ timezone: z.ZodOptional<z.ZodString>;
114
+ description: z.ZodOptional<z.ZodString>;
115
+ }, z.core.$strip>, z.ZodObject<{
116
+ type: z.ZodLiteral<"queue">;
117
+ topics: z.ZodArray<z.ZodString>;
118
+ queueName: z.ZodOptional<z.ZodString>;
119
+ consumerGroup: z.ZodOptional<z.ZodString>;
120
+ }, z.core.$strip>, z.ZodObject<{
121
+ type: z.ZodLiteral<"stream">;
122
+ streamName: z.ZodString;
123
+ eventTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
124
+ consumerGroup: z.ZodOptional<z.ZodString>;
125
+ }, z.core.$strip>]>>>;
126
+ schemas: z.ZodOptional<z.ZodArray<z.ZodObject<{
127
+ slug: z.ZodString;
128
+ name: z.ZodString;
129
+ type: z.ZodEnum<{
130
+ response: "response";
131
+ request: "request";
132
+ entity: "entity";
133
+ webhook_payload: "webhook_payload";
134
+ configuration: "configuration";
135
+ }>;
136
+ description: z.ZodOptional<z.ZodString>;
137
+ schema: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
138
+ version: z.ZodOptional<z.ZodString>;
139
+ fieldCount: z.ZodOptional<z.ZodNumber>;
140
+ }, z.core.$strip>>>;
141
+ events: z.ZodOptional<z.ZodArray<z.ZodObject<{
142
+ slug: z.ZodString;
143
+ name: z.ZodString;
144
+ direction: z.ZodEnum<{
145
+ inbound: "inbound";
146
+ outbound: "outbound";
147
+ bidirectional: "bidirectional";
148
+ }>;
149
+ description: z.ZodOptional<z.ZodString>;
150
+ category: z.ZodOptional<z.ZodString>;
151
+ severity: z.ZodOptional<z.ZodEnum<{
152
+ error: "error";
153
+ info: "info";
154
+ warning: "warning";
155
+ critical: "critical";
156
+ }>>;
157
+ payloadSchema: z.ZodOptional<z.ZodString>;
158
+ }, z.core.$strip>>>;
159
+ functions: z.ZodOptional<z.ZodArray<z.ZodObject<{
160
+ slug: z.ZodString;
161
+ name: z.ZodString;
162
+ httpMethod: z.ZodEnum<{
163
+ GET: "GET";
164
+ POST: "POST";
165
+ PATCH: "PATCH";
166
+ DELETE: "DELETE";
167
+ PUT: "PUT";
168
+ }>;
169
+ endpointPath: z.ZodString;
170
+ description: z.ZodOptional<z.ZodString>;
171
+ requestSchema: z.ZodOptional<z.ZodString>;
172
+ responseSchema: z.ZodOptional<z.ZodString>;
173
+ requiredScopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
174
+ category: z.ZodOptional<z.ZodString>;
175
+ }, z.core.$strip>>>;
176
+ }, z.core.$strip>;
177
+ build: z.ZodOptional<z.ZodObject<{
178
+ dockerfile: z.ZodString;
179
+ context: z.ZodString;
180
+ }, z.core.$strip>>;
181
+ ui: z.ZodOptional<z.ZodObject<{
182
+ category: z.ZodOptional<z.ZodString>;
183
+ color: z.ZodOptional<z.ZodString>;
184
+ }, z.core.$strip>>;
185
+ fga: z.ZodOptional<z.ZodObject<{
186
+ types: z.ZodArray<z.ZodObject<{
187
+ name: z.ZodString;
188
+ relations: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodObject<{
189
+ computedUserset: z.ZodObject<{
190
+ object: z.ZodString;
191
+ relation: z.ZodString;
192
+ }, z.core.$strip>;
193
+ }, z.core.$strip>]>>;
194
+ }, z.core.$strip>>;
195
+ }, z.core.$strip>>;
196
+ }, z.core.$strip>;
197
+ export type IntegrationSpec = z.infer<typeof IntegrationSpecSchema>;
198
+ /**
199
+ * Parse nova-integration.yaml content and validate against the IntegrationSpec schema.
200
+ * @param yamlContent String contents of a nova-integration.yaml specification
201
+ * @returns Parsed IntegrationSpec object
202
+ * @throws Error with validation details if parsing or validation fail
203
+ */
204
+ export declare function parseIntegrationSpec(yamlContent: string): IntegrationSpec;