@kya-os/contracts 1.5.3-canary.16 → 1.5.3-canary.17

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 (71) hide show
  1. package/.turbo/turbo-build.log +17 -0
  2. package/.turbo/turbo-test$colon$coverage.log +85 -0
  3. package/.turbo/turbo-test.log +32 -0
  4. package/coverage/coverage-final.json +38 -0
  5. package/dist/consent/schemas.d.ts +18 -0
  6. package/dist/consent/schemas.js +10 -0
  7. package/dist/dashboard-config/schemas.d.ts +1424 -220
  8. package/dist/tool-protection/index.d.ts +418 -8
  9. package/dist/tool-protection/index.js +61 -2
  10. package/package.json +35 -129
  11. package/schemas/cli/register-output/v1.0.0.json +69 -0
  12. package/schemas/identity/v1.0.0.json +46 -0
  13. package/schemas/proof/v1.0.0.json +80 -0
  14. package/schemas/registry/receipt-v1.0.0.json +60 -0
  15. package/schemas/verifier/verify-page/v1.0.0.json +94 -0
  16. package/schemas/well-known/agent/v1.0.0.json +67 -0
  17. package/schemas/well-known/did/v1.0.0.json +174 -0
  18. package/scripts/emit-schemas.js +11 -0
  19. package/src/agentshield-api/admin-schemas.ts +31 -0
  20. package/src/agentshield-api/admin-types.ts +47 -0
  21. package/src/agentshield-api/endpoints.ts +60 -0
  22. package/src/agentshield-api/index.ts +70 -0
  23. package/src/agentshield-api/schemas.ts +304 -0
  24. package/src/agentshield-api/types.ts +317 -0
  25. package/src/audit/index.ts +128 -0
  26. package/src/cli.ts +156 -0
  27. package/src/config/base.ts +107 -0
  28. package/src/config/builder.ts +97 -0
  29. package/src/config/delegation.ts +232 -0
  30. package/src/config/identity.ts +252 -0
  31. package/src/config/index.ts +78 -0
  32. package/src/config/proofing.ts +138 -0
  33. package/src/config/tool-context.ts +41 -0
  34. package/src/config/tool-protection.ts +174 -0
  35. package/src/consent/index.ts +32 -0
  36. package/src/consent/schemas.ts +334 -0
  37. package/src/consent/types.ts +199 -0
  38. package/src/dashboard-config/default-config.json +86 -0
  39. package/src/dashboard-config/default-config.ts +266 -0
  40. package/src/dashboard-config/index.ts +48 -0
  41. package/src/dashboard-config/schemas.ts +286 -0
  42. package/src/dashboard-config/types.ts +404 -0
  43. package/src/delegation/constraints.ts +267 -0
  44. package/src/delegation/index.ts +8 -0
  45. package/src/delegation/schemas.ts +595 -0
  46. package/src/did/index.ts +9 -0
  47. package/src/did/resolve-contract.ts +255 -0
  48. package/src/did/schemas.ts +190 -0
  49. package/src/did/types.ts +224 -0
  50. package/src/env/constants.ts +70 -0
  51. package/src/env/index.ts +5 -0
  52. package/src/handshake.ts +125 -0
  53. package/src/index.ts +45 -0
  54. package/src/proof/index.ts +31 -0
  55. package/src/proof/proof-record.ts +163 -0
  56. package/src/proof/signing-spec.ts +146 -0
  57. package/src/proof.ts +99 -0
  58. package/src/registry.ts +146 -0
  59. package/src/runtime/errors.ts +153 -0
  60. package/src/runtime/headers.ts +136 -0
  61. package/src/runtime/index.ts +6 -0
  62. package/src/test.ts +143 -0
  63. package/src/tlkrc/index.ts +5 -0
  64. package/src/tlkrc/rotation.ts +153 -0
  65. package/src/tool-protection/index.ts +343 -0
  66. package/src/utils/validation.ts +93 -0
  67. package/src/vc/index.ts +8 -0
  68. package/src/vc/schemas.ts +277 -0
  69. package/src/vc/statuslist.ts +279 -0
  70. package/src/verifier.ts +92 -0
  71. package/src/well-known/index.ts +237 -0
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Proofing Configuration Types
3
+ *
4
+ * Configuration for proof generation and submission including batch
5
+ * processing, destinations, and retry logic.
6
+ *
7
+ * @module @kya-os/contracts/config
8
+ */
9
+
10
+ /**
11
+ * Proof destination types
12
+ */
13
+ export type ProofDestinationType = 'agentshield' | 'kta' | 'custom';
14
+
15
+ /**
16
+ * Proof destination configuration
17
+ * Defines where proofs should be submitted
18
+ */
19
+ export interface ProofDestination {
20
+ /**
21
+ * Type of destination
22
+ */
23
+ type: ProofDestinationType;
24
+
25
+ /**
26
+ * API base URL for the destination
27
+ * Required for 'agentshield' and 'kta' types
28
+ * @example 'https://kya.vouched.id'
29
+ */
30
+ apiUrl?: string;
31
+
32
+ /**
33
+ * API key for authentication
34
+ * Required for most destinations
35
+ */
36
+ apiKey?: string;
37
+
38
+ /**
39
+ * Custom submission function
40
+ * Required for 'custom' type destinations
41
+ */
42
+ submit?: (proofs: any[]) => Promise<void>;
43
+
44
+ /**
45
+ * Additional destination-specific configuration
46
+ */
47
+ options?: Record<string, unknown>;
48
+ }
49
+
50
+ /**
51
+ * Proof batch queue configuration
52
+ * Controls how proofs are batched and submitted
53
+ */
54
+ export interface ProofBatchQueueConfig {
55
+ /**
56
+ * Destinations where proofs should be sent
57
+ * Multiple destinations are processed in parallel
58
+ */
59
+ destinations: ProofDestination[];
60
+
61
+ /**
62
+ * Maximum number of proofs to batch before auto-submission
63
+ * @default 10
64
+ */
65
+ maxBatchSize?: number;
66
+
67
+ /**
68
+ * Time interval (ms) between automatic flush attempts
69
+ * @default 5000
70
+ */
71
+ flushIntervalMs?: number;
72
+
73
+ /**
74
+ * Maximum number of retry attempts for failed submissions
75
+ * @default 3
76
+ */
77
+ maxRetries?: number;
78
+
79
+ /**
80
+ * Backoff multiplier for retry delays
81
+ * @default 2
82
+ */
83
+ retryBackoff?: number;
84
+
85
+ /**
86
+ * Enable debug logging for proof submission
87
+ * @default false
88
+ */
89
+ debug?: boolean;
90
+ }
91
+
92
+ /**
93
+ * Proofing configuration (platform-agnostic)
94
+ *
95
+ * Controls proof generation, batching, and submission to external services
96
+ * like AgentShield or Know That AI (KTA).
97
+ */
98
+ export interface ProofingConfig {
99
+ /**
100
+ * Enable proof generation and submission
101
+ * @default true
102
+ */
103
+ enabled: boolean;
104
+
105
+ /**
106
+ * Proof batch queue configuration
107
+ * Controls batching and submission behavior
108
+ */
109
+ batchQueue?: ProofBatchQueueConfig;
110
+
111
+ /**
112
+ * Include additional metadata in proofs
113
+ * @default true
114
+ */
115
+ includeMetadata?: boolean;
116
+
117
+ /**
118
+ * Custom proof generation options
119
+ */
120
+ options?: {
121
+ /**
122
+ * Include timestamp in all proofs
123
+ * @default true
124
+ */
125
+ includeTimestamp?: boolean;
126
+
127
+ /**
128
+ * Include session context in proofs
129
+ * @default true
130
+ */
131
+ includeSession?: boolean;
132
+
133
+ /**
134
+ * Custom fields to include in every proof
135
+ */
136
+ customFields?: Record<string, unknown>;
137
+ };
138
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Tool Execution Context
3
+ *
4
+ * Execution context passed to tool handlers, enabling tools to access
5
+ * IDP tokens for external API calls (GitHub, Google, etc.).
6
+ *
7
+ * All fields are optional for backward compatibility - tools that don't
8
+ * require OAuth will receive undefined context.
9
+ *
10
+ * @package @kya-os/contracts
11
+ */
12
+
13
+ /**
14
+ * Execution context passed to tool handlers
15
+ *
16
+ * Enables tools to access IDP tokens for external API calls.
17
+ * Context is only provided when:
18
+ * - Tool requires OAuth (has requiredScopes)
19
+ * - User DID is available
20
+ * - IDP token is successfully resolved
21
+ */
22
+ export interface ToolExecutionContext {
23
+ /** IDP access token for external API calls (e.g., GitHub, Google) */
24
+ idpToken?: string;
25
+
26
+ /** OAuth provider name (e.g., "github", "google") */
27
+ provider?: string;
28
+
29
+ /** Scopes granted for this token */
30
+ scopes?: string[];
31
+
32
+ /** User DID associated with this token */
33
+ userDid?: string;
34
+
35
+ /** Session ID */
36
+ sessionId?: string;
37
+
38
+ /** Delegation token (MCP-I internal authorization) */
39
+ delegationToken?: string;
40
+ }
41
+
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Tool Protection Configuration Types
3
+ *
4
+ * Configuration for tool protection including delegation requirements,
5
+ * scopes, and multi-source resolution strategies.
6
+ *
7
+ * @module @kya-os/contracts/config
8
+ */
9
+
10
+ // Import core tool protection types from the spec
11
+ import type {
12
+ ToolProtection as BaseToolProtection,
13
+ ToolProtectionMap as BaseToolProtectionMap,
14
+ DelegationRequiredErrorData as BaseDelegationRequiredErrorData,
15
+ ToolProtectionResponse as BaseToolProtectionResponse
16
+ } from '../tool-protection/index.js';
17
+
18
+ // Re-export for convenience
19
+ export type ToolProtection = BaseToolProtection;
20
+ export type ToolProtectionMap = BaseToolProtectionMap;
21
+ export type DelegationRequiredErrorData = BaseDelegationRequiredErrorData;
22
+ export type ToolProtectionResponse = BaseToolProtectionResponse;
23
+
24
+ /**
25
+ * Tool protection source types
26
+ */
27
+ export type ToolProtectionSourceType =
28
+ | 'inline' // Inline configuration in code
29
+ | 'local' // Local file (tool-protections.json)
30
+ | 'agentshield' // AgentShield API
31
+ | 'kta' // Know That AI
32
+ | 'multi'; // Multiple sources with priority resolution
33
+
34
+ /**
35
+ * Tool protection source configuration
36
+ * Defines where tool protection settings come from
37
+ */
38
+ export interface ToolProtectionSourceConfig {
39
+ /**
40
+ * Type of source to use
41
+ */
42
+ source: ToolProtectionSourceType;
43
+
44
+ /**
45
+ * Inline tool protection map
46
+ * Used when source is 'inline'
47
+ */
48
+ inline?: BaseToolProtectionMap;
49
+
50
+ /**
51
+ * Path to local tool protections file
52
+ * Used when source is 'local'
53
+ * @example './tool-protections.json'
54
+ */
55
+ localFile?: string;
56
+
57
+ /**
58
+ * AgentShield configuration
59
+ * Used when source is 'agentshield'
60
+ */
61
+ agentShield?: {
62
+ /**
63
+ * AgentShield API base URL
64
+ * @example 'https://kya.vouched.id'
65
+ */
66
+ apiUrl: string;
67
+
68
+ /**
69
+ * API key for authentication
70
+ */
71
+ apiKey?: string;
72
+
73
+ /**
74
+ * Project ID (optional, for backward compatibility)
75
+ * Modern approach uses agent DID
76
+ */
77
+ projectId?: string;
78
+
79
+ /**
80
+ * Cache TTL in milliseconds
81
+ * @default 300000 (5 minutes)
82
+ */
83
+ cacheTtl?: number;
84
+ };
85
+
86
+ /**
87
+ * KTA configuration
88
+ * Used when source is 'kta'
89
+ */
90
+ kta?: {
91
+ /**
92
+ * KTA API base URL
93
+ */
94
+ apiUrl: string;
95
+
96
+ /**
97
+ * API key for authentication
98
+ */
99
+ apiKey?: string;
100
+ };
101
+
102
+ /**
103
+ * Multi-source configuration
104
+ * Used when source is 'multi'
105
+ * Sources are checked in priority order
106
+ */
107
+ sources?: Array<{
108
+ /**
109
+ * Source configuration
110
+ */
111
+ config: Omit<ToolProtectionSourceConfig, 'source' | 'sources'>;
112
+
113
+ /**
114
+ * Priority (higher number = higher priority)
115
+ * @default 0
116
+ */
117
+ priority?: number;
118
+
119
+ /**
120
+ * Whether to stop after this source if found
121
+ * @default false
122
+ */
123
+ exclusive?: boolean;
124
+ }>;
125
+
126
+ /**
127
+ * Fallback configuration if all sources fail
128
+ */
129
+ fallback?: BaseToolProtectionMap;
130
+
131
+ /**
132
+ * Enable debug logging
133
+ * @default false
134
+ */
135
+ debug?: boolean;
136
+ }
137
+
138
+ /**
139
+ * Tool protection service configuration
140
+ * Used by provider-based implementations
141
+ */
142
+ export interface ToolProtectionServiceConfig {
143
+ /**
144
+ * API base URL for fetching tool protections
145
+ */
146
+ apiUrl: string;
147
+
148
+ /**
149
+ * API key for authentication
150
+ */
151
+ apiKey: string;
152
+
153
+ /**
154
+ * Project ID (optional)
155
+ */
156
+ projectId?: string;
157
+
158
+ /**
159
+ * Cache TTL in milliseconds
160
+ * @default 300000 (5 minutes)
161
+ */
162
+ cacheTtl?: number;
163
+
164
+ /**
165
+ * Fallback configuration if API is unavailable
166
+ */
167
+ fallbackConfig?: BaseToolProtectionMap;
168
+
169
+ /**
170
+ * Enable debug logging
171
+ * @default false
172
+ */
173
+ debug?: boolean;
174
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Consent Module Exports
3
+ *
4
+ * Types and schemas for consent page configuration and approval handling
5
+ */
6
+
7
+ // Export schemas and inferred types (types are derived from schemas)
8
+ export {
9
+ consentBrandingSchema,
10
+ consentTermsSchema,
11
+ consentCustomFieldSchema,
12
+ consentCustomFieldOptionSchema,
13
+ consentPageConfigSchema,
14
+ consentApprovalRequestSchema,
15
+ consentApprovalResponseSchema,
16
+ consentConfigSchema,
17
+ oauthIdentitySchema,
18
+ validateConsentPageConfig,
19
+ validateConsentApprovalRequest,
20
+ validateConsentApprovalResponse,
21
+ validateConsentConfig,
22
+ type ConsentBranding,
23
+ type ConsentTerms,
24
+ type ConsentCustomField,
25
+ type ConsentPageConfig,
26
+ type ConsentApprovalRequest,
27
+ type ConsentApprovalResponse,
28
+ type ConsentConfig,
29
+ type OAuthIdentity,
30
+ } from './schemas.js';
31
+
32
+
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Consent Schemas
3
+ *
4
+ * Zod schemas for runtime validation of consent-related data structures.
5
+ * All types are derived from these schemas using z.infer.
6
+ *
7
+ * Related Spec: MCP-I Phase 0 Implementation Plan
8
+ */
9
+
10
+ import { z } from "zod";
11
+
12
+ /**
13
+ * Consent Branding Schema
14
+ */
15
+ export const consentBrandingSchema = z.object({
16
+ primaryColor: z
17
+ .string()
18
+ .regex(/^#[0-9A-Fa-f]{6}$/, "Must be a valid hex color (e.g., #0066CC)")
19
+ .optional(),
20
+ logoUrl: z.string().url("Must be a valid URL").optional(),
21
+ companyName: z
22
+ .string()
23
+ .max(100, "Company name must be 100 characters or less")
24
+ .optional(),
25
+ theme: z.enum(["light", "dark", "auto"]).optional(),
26
+ });
27
+
28
+ export type ConsentBranding = z.infer<typeof consentBrandingSchema>;
29
+
30
+ /**
31
+ * Consent Terms Schema
32
+ */
33
+ export const consentTermsSchema = z.object({
34
+ text: z
35
+ .string()
36
+ .max(10000, "Terms text must be 10000 characters or less")
37
+ .optional(),
38
+ url: z.string().url("Must be a valid URL").optional(),
39
+ version: z
40
+ .string()
41
+ .max(50, "Version must be 50 characters or less")
42
+ .optional(),
43
+ required: z.boolean().default(true),
44
+ });
45
+
46
+ export type ConsentTerms = z.infer<typeof consentTermsSchema>;
47
+
48
+ /**
49
+ * Consent Custom Field Option Schema
50
+ */
51
+ export const consentCustomFieldOptionSchema = z.object({
52
+ value: z.string().max(100, "Option value must be 100 characters or less"),
53
+ label: z.string().max(100, "Option label must be 100 characters or less"),
54
+ });
55
+
56
+ /**
57
+ * Consent Custom Field Schema
58
+ */
59
+ export const consentCustomFieldSchema = z
60
+ .object({
61
+ name: z
62
+ .string()
63
+ .min(1, "Field name is required")
64
+ .max(50, "Field name must be 50 characters or less")
65
+ .regex(
66
+ /^[a-zA-Z0-9_]+$/,
67
+ "Field name must contain only letters, numbers, and underscores"
68
+ ),
69
+ label: z
70
+ .string()
71
+ .min(1, "Field label is required")
72
+ .max(100, "Field label must be 100 characters or less"),
73
+ type: z.enum(["text", "textarea", "checkbox", "select"]),
74
+ required: z.boolean(),
75
+ placeholder: z
76
+ .string()
77
+ .max(200, "Placeholder must be 200 characters or less")
78
+ .optional(),
79
+ options: z
80
+ .array(consentCustomFieldOptionSchema)
81
+ .min(1, "Select fields must have at least one option")
82
+ .optional(),
83
+ pattern: z
84
+ .string()
85
+ .max(500, "Pattern must be 500 characters or less")
86
+ .optional(),
87
+ })
88
+ .refine(
89
+ (data) => {
90
+ // Select fields must have options
91
+ if (
92
+ data.type === "select" &&
93
+ (!data.options || data.options.length === 0)
94
+ ) {
95
+ return false;
96
+ }
97
+ // Non-select fields should not have options
98
+ if (data.type !== "select" && data.options) {
99
+ return false;
100
+ }
101
+ return true;
102
+ },
103
+ {
104
+ message:
105
+ "Select fields must have options, and non-select fields must not have options",
106
+ }
107
+ );
108
+
109
+ export type ConsentCustomField = z.infer<typeof consentCustomFieldSchema>;
110
+
111
+ /**
112
+ * OAuth Identity Schema
113
+ *
114
+ * Represents a user's OAuth provider account information.
115
+ * Used in Phase 4 to link OAuth accounts to persistent User DIDs.
116
+ */
117
+ export const oauthIdentitySchema = z.object({
118
+ /**
119
+ * OAuth provider name (e.g., "google", "github", "microsoft")
120
+ */
121
+ provider: z
122
+ .string()
123
+ .min(1, "Provider is required")
124
+ .max(50, "Provider name must be 50 characters or less"),
125
+
126
+ /**
127
+ * OAuth subject identifier (unique user ID from provider)
128
+ * @example "123456789" (Google), "github-user-id" (GitHub)
129
+ */
130
+ subject: z
131
+ .string()
132
+ .min(1, "Subject is required")
133
+ .max(255, "Subject must be 255 characters or less"),
134
+
135
+ /**
136
+ * User's email address from OAuth provider (optional)
137
+ */
138
+ email: z
139
+ .string()
140
+ .email("Must be a valid email address")
141
+ .max(255, "Email must be 255 characters or less")
142
+ .optional(),
143
+
144
+ /**
145
+ * User's display name from OAuth provider (optional)
146
+ */
147
+ name: z.string().max(255, "Name must be 255 characters or less").optional(),
148
+ });
149
+
150
+ export type OAuthIdentity = z.infer<typeof oauthIdentitySchema>;
151
+
152
+ /**
153
+ * Consent Page Config Schema
154
+ */
155
+ export const consentPageConfigSchema = z.object({
156
+ tool: z.string().min(1, "Tool name is required"),
157
+ toolDescription: z
158
+ .string()
159
+ .max(500, "Tool description must be 500 characters or less"),
160
+ scopes: z.array(z.string()).min(0, "Scopes array cannot be negative"),
161
+ agentDid: z.string().min(1, "Agent DID is required"),
162
+ sessionId: z.string().min(1, "Session ID is required"),
163
+ projectId: z.string().min(1, "Project ID is required"),
164
+ provider: z.string().optional(), // Phase 2: OAuth provider name (e.g., "github", "google")
165
+ branding: consentBrandingSchema.optional(),
166
+ terms: consentTermsSchema.optional(),
167
+ customFields: z
168
+ .array(consentCustomFieldSchema)
169
+ .max(10, "Maximum 10 custom fields allowed")
170
+ .optional(),
171
+ serverUrl: z.string().url("Server URL must be a valid URL"),
172
+ autoClose: z.boolean().optional(),
173
+ /**
174
+ * Whether OAuth authorization is required immediately
175
+ * If true, the consent page will act as a landing page before redirecting
176
+ */
177
+ oauthRequired: z.boolean().optional(),
178
+ /**
179
+ * The OAuth authorization URL to redirect to
180
+ * Required if oauthRequired is true
181
+ */
182
+ oauthUrl: z.string().url().optional(),
183
+ });
184
+
185
+ export type ConsentPageConfig = z.infer<typeof consentPageConfigSchema>;
186
+
187
+ /**
188
+ * Consent Approval Request Schema
189
+ *
190
+ * Note: Uses snake_case for API compatibility (agent_did, session_id, project_id)
191
+ *
192
+ * Phase 4 additions:
193
+ * - oauth_identity: Optional OAuth provider information for identity linking
194
+ * - user_did: Optional User DID for persistent identity (if already known)
195
+ */
196
+ export const consentApprovalRequestSchema = z.object({
197
+ tool: z.string().min(1, "Tool name is required"),
198
+ scopes: z.array(z.string()).min(0, "Scopes array cannot be negative"),
199
+ agent_did: z.string().min(1, "Agent DID is required"),
200
+ session_id: z.string().min(1, "Session ID is required"),
201
+ project_id: z.string().min(1, "Project ID is required"),
202
+ termsAccepted: z.boolean(),
203
+ termsVersion: z
204
+ .string()
205
+ .max(50, "Terms version must be 50 characters or less")
206
+ .optional(),
207
+ customFields: z.record(z.union([z.string(), z.boolean()])).optional(),
208
+
209
+ // Phase 4: OAuth identity linking
210
+ /**
211
+ * OAuth provider identity information (optional)
212
+ * Used to link OAuth accounts to persistent User DIDs
213
+ *
214
+ * CRITICAL: Uses .nullish() to accept null, undefined, or OAuthIdentity
215
+ * This matches JSON parsing behavior where missing fields become null
216
+ */
217
+ oauth_identity: oauthIdentitySchema.nullish(),
218
+
219
+ /**
220
+ * User DID (optional)
221
+ * If provided, represents the persistent User DID for this user
222
+ * Format: did:key:... or did:web:...
223
+ */
224
+ user_did: z
225
+ .string()
226
+ .regex(/^did:/, "Must be a valid DID format (starting with did:)")
227
+ .max(500, "DID must be 500 characters or less")
228
+ .optional(),
229
+ });
230
+
231
+ export type ConsentApprovalRequest = z.infer<
232
+ typeof consentApprovalRequestSchema
233
+ >;
234
+
235
+ /**
236
+ * Consent Approval Response Schema
237
+ */
238
+ export const consentApprovalResponseSchema = z
239
+ .object({
240
+ success: z.boolean(),
241
+ delegation_id: z.string().min(1).optional(),
242
+ delegation_token: z.string().min(1).optional(),
243
+ error: z.string().optional(),
244
+ error_code: z.string().optional(),
245
+ })
246
+ .refine(
247
+ (data) => {
248
+ // If success is true, must have delegation_id and delegation_token
249
+ if (data.success) {
250
+ return !!data.delegation_id && !!data.delegation_token;
251
+ }
252
+ // If success is false, must have error or error_code
253
+ return !!data.error || !!data.error_code;
254
+ },
255
+ {
256
+ message:
257
+ "Successful responses must include delegation_id and delegation_token. Failed responses must include error or error_code",
258
+ }
259
+ );
260
+
261
+ export type ConsentApprovalResponse = z.infer<
262
+ typeof consentApprovalResponseSchema
263
+ >;
264
+
265
+ /**
266
+ * Consent Config Schema
267
+ */
268
+ export const consentConfigSchema = z.object({
269
+ branding: consentBrandingSchema.optional(),
270
+ terms: consentTermsSchema.optional(),
271
+ customFields: z
272
+ .array(consentCustomFieldSchema)
273
+ .max(10, "Maximum 10 custom fields allowed")
274
+ .optional(),
275
+ ui: z
276
+ .object({
277
+ theme: z.enum(["light", "dark", "auto"]).optional(),
278
+ popupEnabled: z.boolean().optional(),
279
+ autoClose: z.boolean().optional(),
280
+ autoCloseDelay: z
281
+ .number()
282
+ .int()
283
+ .positive()
284
+ .max(60000, "Auto-close delay must be 60000ms or less")
285
+ .optional(),
286
+ })
287
+ .optional(),
288
+ });
289
+
290
+ export type ConsentConfig = z.infer<typeof consentConfigSchema>;
291
+
292
+ /**
293
+ * Validation Helpers
294
+ */
295
+
296
+ /**
297
+ * Validate a consent page config
298
+ *
299
+ * @param config - The config to validate
300
+ * @returns Validation result
301
+ */
302
+ export function validateConsentPageConfig(config: unknown) {
303
+ return consentPageConfigSchema.safeParse(config);
304
+ }
305
+
306
+ /**
307
+ * Validate a consent approval request
308
+ *
309
+ * @param request - The request to validate
310
+ * @returns Validation result
311
+ */
312
+ export function validateConsentApprovalRequest(request: unknown) {
313
+ return consentApprovalRequestSchema.safeParse(request);
314
+ }
315
+
316
+ /**
317
+ * Validate a consent approval response
318
+ *
319
+ * @param response - The response to validate
320
+ * @returns Validation result
321
+ */
322
+ export function validateConsentApprovalResponse(response: unknown) {
323
+ return consentApprovalResponseSchema.safeParse(response);
324
+ }
325
+
326
+ /**
327
+ * Validate a consent config
328
+ *
329
+ * @param config - The config to validate
330
+ * @returns Validation result
331
+ */
332
+ export function validateConsentConfig(config: unknown) {
333
+ return consentConfigSchema.safeParse(config);
334
+ }