digital-products 2.1.1 → 2.3.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/CHANGELOG.md +17 -0
- package/README.md +2 -0
- package/dist/api.js +7 -7
- package/dist/api.js.map +1 -1
- package/dist/app.js +6 -6
- package/dist/app.js.map +1 -1
- package/dist/client.d.ts +157 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +69 -0
- package/dist/client.js.map +1 -0
- package/dist/content.js +7 -7
- package/dist/content.js.map +1 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +6 -6
- package/dist/data.js.map +1 -1
- package/dist/dataset.js +5 -5
- package/dist/dataset.js.map +1 -1
- package/dist/index.d.ts +92 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +139 -15
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +17 -10
- package/dist/mcp.js.map +1 -1
- package/dist/product.js +2 -2
- package/dist/product.js.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +52 -16
- package/dist/sdk.js.map +1 -1
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +12 -8
- package/dist/site.js.map +1 -1
- package/dist/types.d.ts +830 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +495 -2
- package/dist/types.js.map +1 -1
- package/dist/worker.d.ts +205 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +356 -0
- package/dist/worker.js.map +1 -0
- package/package.json +20 -4
- package/src/api.ts +7 -7
- package/src/app.ts +6 -6
- package/src/client.ts +192 -0
- package/src/content.ts +7 -7
- package/src/data.ts +12 -7
- package/src/dataset.ts +5 -5
- package/src/index.ts +151 -15
- package/src/mcp.ts +18 -11
- package/src/product.ts +2 -2
- package/src/sdk.ts +54 -15
- package/src/site.ts +12 -8
- package/src/types.ts +821 -12
- package/src/worker.ts +525 -0
- package/test/product.test.ts +53 -198
- package/test/unified-types.test.ts +589 -0
- package/test/worker.test.ts +912 -0
- package/vitest.config.ts +42 -0
- package/wrangler.jsonc +36 -0
- package/.turbo/turbo-build.log +0 -5
- package/src/api.js +0 -128
- package/src/app.js +0 -106
- package/src/content.js +0 -77
- package/src/data.js +0 -106
- package/src/dataset.js +0 -49
- package/src/entities/ai.js +0 -858
- package/src/entities/content.js +0 -783
- package/src/entities/index.js +0 -88
- package/src/entities/interfaces.js +0 -929
- package/src/entities/lifecycle.js +0 -803
- package/src/entities/products.js +0 -797
- package/src/entities/web.js +0 -657
- package/src/index.js +0 -35
- package/src/mcp.js +0 -139
- package/src/product.js +0 -53
- package/src/registry.js +0 -31
- package/src/sdk.js +0 -127
- package/src/site.js +0 -112
- package/src/types.js +0 -4
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for unified type system consolidation
|
|
3
|
+
*
|
|
4
|
+
* TDD RED PHASE - These tests WILL FAIL because the implementation doesn't exist yet.
|
|
5
|
+
*
|
|
6
|
+
* Goal: Consolidate to ONLY use JSON-LD style with $id, $type and add Zod schemas.
|
|
7
|
+
* The old builder pattern types (id, type) should be rejected.
|
|
8
|
+
*
|
|
9
|
+
* @see https://schema.org.ai/Product
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, it, expect } from 'vitest'
|
|
13
|
+
import {
|
|
14
|
+
// Core types (these exist as interfaces but need Zod schemas)
|
|
15
|
+
Product, ProductSchema, isProduct, createProduct,
|
|
16
|
+
App, AppSchema, isApp, createApp,
|
|
17
|
+
API, APISchema, isAPI, createAPI,
|
|
18
|
+
Site, SiteSchema, isSite, createSite,
|
|
19
|
+
// New types to add
|
|
20
|
+
Service, ServiceSchema, isService, createService,
|
|
21
|
+
Feature, FeatureSchema, isFeature, createFeature
|
|
22
|
+
} from '../src/index.js'
|
|
23
|
+
|
|
24
|
+
describe('Unified Product Type', () => {
|
|
25
|
+
const validProduct = {
|
|
26
|
+
$id: 'https://schema.org.ai/products/acme',
|
|
27
|
+
$type: 'https://schema.org.ai/Product' as const,
|
|
28
|
+
name: 'Acme Product',
|
|
29
|
+
description: 'A product',
|
|
30
|
+
status: 'active' as const
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
it('should use $id and $type (JSON-LD style)', () => {
|
|
34
|
+
expect(validProduct.$id).toBeDefined()
|
|
35
|
+
expect(validProduct.$type).toBe('https://schema.org.ai/Product')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should NOT use plain id and type fields', () => {
|
|
39
|
+
// This should fail - we want to enforce $id/$type
|
|
40
|
+
const oldStyle = { id: 'test', type: 'product', name: 'Test' }
|
|
41
|
+
const result = ProductSchema.safeParse(oldStyle)
|
|
42
|
+
expect(result.success).toBe(false)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should validate with Zod schema', () => {
|
|
46
|
+
const result = ProductSchema.safeParse(validProduct)
|
|
47
|
+
expect(result.success).toBe(true)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should reject invalid status', () => {
|
|
51
|
+
const invalid = { ...validProduct, status: 'invalid' }
|
|
52
|
+
const result = ProductSchema.safeParse(invalid)
|
|
53
|
+
expect(result.success).toBe(false)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('isProduct type guard should work', () => {
|
|
57
|
+
expect(isProduct(validProduct)).toBe(true)
|
|
58
|
+
expect(isProduct({ id: 'old-style' })).toBe(false)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('createProduct factory should create valid Product', () => {
|
|
62
|
+
const product = createProduct({
|
|
63
|
+
$id: 'https://schema.org.ai/products/new',
|
|
64
|
+
name: 'New Product',
|
|
65
|
+
description: 'A new product'
|
|
66
|
+
})
|
|
67
|
+
expect(product.$type).toBe('https://schema.org.ai/Product')
|
|
68
|
+
expect(product.status).toBe('active') // default
|
|
69
|
+
expect(isProduct(product)).toBe(true)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('Unified App Type', () => {
|
|
74
|
+
const validApp = {
|
|
75
|
+
$id: 'https://schema.org.ai/apps/dashboard',
|
|
76
|
+
$type: 'https://schema.org.ai/App' as const,
|
|
77
|
+
name: 'Dashboard',
|
|
78
|
+
description: 'Admin dashboard',
|
|
79
|
+
status: 'active' as const,
|
|
80
|
+
platform: 'web' as const,
|
|
81
|
+
url: 'https://dashboard.example.com'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
it('should extend Product with $type override', () => {
|
|
85
|
+
expect(validApp.$type).toBe('https://schema.org.ai/App')
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('should have platform and url fields', () => {
|
|
89
|
+
expect(validApp.platform).toBeDefined()
|
|
90
|
+
expect(validApp.url).toBeDefined()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('should validate platform enum', () => {
|
|
94
|
+
const platforms = ['web', 'mobile', 'desktop', 'api']
|
|
95
|
+
platforms.forEach(platform => {
|
|
96
|
+
const result = AppSchema.safeParse({ ...validApp, platform })
|
|
97
|
+
expect(result.success).toBe(true)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('should reject invalid platform', () => {
|
|
102
|
+
const result = AppSchema.safeParse({ ...validApp, platform: 'invalid' })
|
|
103
|
+
expect(result.success).toBe(false)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('isApp type guard should work', () => {
|
|
107
|
+
expect(isApp(validApp)).toBe(true)
|
|
108
|
+
expect(isApp({ type: 'app' })).toBe(false) // old style
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('createApp factory should work', () => {
|
|
112
|
+
const app = createApp({
|
|
113
|
+
$id: 'https://schema.org.ai/apps/new',
|
|
114
|
+
name: 'New App',
|
|
115
|
+
description: 'A new app',
|
|
116
|
+
platform: 'web',
|
|
117
|
+
url: 'https://new.app'
|
|
118
|
+
})
|
|
119
|
+
expect(app.$type).toBe('https://schema.org.ai/App')
|
|
120
|
+
expect(isApp(app)).toBe(true)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('Unified API Type', () => {
|
|
125
|
+
const validAPI = {
|
|
126
|
+
$id: 'https://schema.org.ai/apis/v1',
|
|
127
|
+
$type: 'https://schema.org.ai/API' as const,
|
|
128
|
+
name: 'API v1',
|
|
129
|
+
description: 'REST API',
|
|
130
|
+
status: 'active' as const,
|
|
131
|
+
baseUrl: 'https://api.example.com/v1',
|
|
132
|
+
version: '1.0.0',
|
|
133
|
+
authentication: 'bearer' as const
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
it('should extend Product with $type override', () => {
|
|
137
|
+
expect(validAPI.$type).toBe('https://schema.org.ai/API')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('should have baseUrl, version, authentication', () => {
|
|
141
|
+
expect(validAPI.baseUrl).toBeDefined()
|
|
142
|
+
expect(validAPI.version).toBeDefined()
|
|
143
|
+
expect(validAPI.authentication).toBeDefined()
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('should validate authentication enum', () => {
|
|
147
|
+
const auths = ['bearer', 'api_key', 'oauth', 'none']
|
|
148
|
+
auths.forEach(auth => {
|
|
149
|
+
const result = APISchema.safeParse({ ...validAPI, authentication: auth })
|
|
150
|
+
expect(result.success).toBe(true)
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('isAPI type guard should work', () => {
|
|
155
|
+
expect(isAPI(validAPI)).toBe(true)
|
|
156
|
+
expect(isAPI({ type: 'api' })).toBe(false) // old style
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('createAPI factory should work', () => {
|
|
160
|
+
const api = createAPI({
|
|
161
|
+
$id: 'https://schema.org.ai/apis/new',
|
|
162
|
+
name: 'New API',
|
|
163
|
+
description: 'A new API',
|
|
164
|
+
baseUrl: 'https://api.new.com',
|
|
165
|
+
version: '1.0.0',
|
|
166
|
+
authentication: 'bearer'
|
|
167
|
+
})
|
|
168
|
+
expect(api.$type).toBe('https://schema.org.ai/API')
|
|
169
|
+
expect(isAPI(api)).toBe(true)
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
describe('Unified Site Type', () => {
|
|
174
|
+
const validSite = {
|
|
175
|
+
$id: 'https://schema.org.ai/sites/docs',
|
|
176
|
+
$type: 'https://schema.org.ai/Site' as const,
|
|
177
|
+
name: 'Docs',
|
|
178
|
+
description: 'Documentation site',
|
|
179
|
+
status: 'active' as const,
|
|
180
|
+
url: 'https://docs.example.com',
|
|
181
|
+
siteType: 'docs' as const
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
it('should extend Product with $type override', () => {
|
|
185
|
+
expect(validSite.$type).toBe('https://schema.org.ai/Site')
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('should have url and siteType', () => {
|
|
189
|
+
expect(validSite.url).toBeDefined()
|
|
190
|
+
expect(validSite.siteType).toBeDefined()
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('should validate siteType enum', () => {
|
|
194
|
+
const types = ['marketing', 'docs', 'blog', 'app']
|
|
195
|
+
types.forEach(siteType => {
|
|
196
|
+
const result = SiteSchema.safeParse({ ...validSite, siteType })
|
|
197
|
+
expect(result.success).toBe(true)
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('isSite type guard should work', () => {
|
|
202
|
+
expect(isSite(validSite)).toBe(true)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('createSite factory should work', () => {
|
|
206
|
+
const site = createSite({
|
|
207
|
+
$id: 'https://schema.org.ai/sites/new',
|
|
208
|
+
name: 'New Site',
|
|
209
|
+
description: 'A new site',
|
|
210
|
+
url: 'https://new.site',
|
|
211
|
+
siteType: 'marketing'
|
|
212
|
+
})
|
|
213
|
+
expect(site.$type).toBe('https://schema.org.ai/Site')
|
|
214
|
+
expect(isSite(site)).toBe(true)
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
describe('Service Type', () => {
|
|
219
|
+
const validService = {
|
|
220
|
+
$id: 'https://schema.org.ai/services/auth',
|
|
221
|
+
$type: 'https://schema.org.ai/Service' as const,
|
|
222
|
+
name: 'Auth Service',
|
|
223
|
+
description: 'Authentication service',
|
|
224
|
+
status: 'active' as const,
|
|
225
|
+
endpoints: ['/login', '/logout', '/refresh']
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
it('should have $id, $type, name, description', () => {
|
|
229
|
+
expect(validService.$id).toBeDefined()
|
|
230
|
+
expect(validService.$type).toBe('https://schema.org.ai/Service')
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('should validate with Zod schema', () => {
|
|
234
|
+
const result = ServiceSchema.safeParse(validService)
|
|
235
|
+
expect(result.success).toBe(true)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('endpoints should be optional', () => {
|
|
239
|
+
const noEndpoints = { ...validService, endpoints: undefined }
|
|
240
|
+
const result = ServiceSchema.safeParse(noEndpoints)
|
|
241
|
+
expect(result.success).toBe(true)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('isService type guard should work', () => {
|
|
245
|
+
expect(isService(validService)).toBe(true)
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it('createService factory should work', () => {
|
|
249
|
+
const service = createService({
|
|
250
|
+
$id: 'https://schema.org.ai/services/new',
|
|
251
|
+
name: 'New Service',
|
|
252
|
+
description: 'A new service'
|
|
253
|
+
})
|
|
254
|
+
expect(service.$type).toBe('https://schema.org.ai/Service')
|
|
255
|
+
expect(isService(service)).toBe(true)
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
describe('Feature Type', () => {
|
|
260
|
+
const validFeature = {
|
|
261
|
+
$id: 'https://schema.org.ai/features/dark-mode',
|
|
262
|
+
$type: 'https://schema.org.ai/Feature' as const,
|
|
263
|
+
name: 'Dark Mode',
|
|
264
|
+
description: 'Toggle dark theme',
|
|
265
|
+
productId: 'https://schema.org.ai/products/dashboard',
|
|
266
|
+
status: 'ga' as const
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
it('should have $id, $type, name, description', () => {
|
|
270
|
+
expect(validFeature.$id).toBeDefined()
|
|
271
|
+
expect(validFeature.$type).toBe('https://schema.org.ai/Feature')
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('should reference productId', () => {
|
|
275
|
+
expect(validFeature.productId).toBeDefined()
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it('status should be: draft, beta, ga, deprecated', () => {
|
|
279
|
+
const statuses = ['draft', 'beta', 'ga', 'deprecated']
|
|
280
|
+
statuses.forEach(status => {
|
|
281
|
+
const result = FeatureSchema.safeParse({ ...validFeature, status })
|
|
282
|
+
expect(result.success).toBe(true)
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it('isFeature type guard should work', () => {
|
|
287
|
+
expect(isFeature(validFeature)).toBe(true)
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
it('createFeature factory should work', () => {
|
|
291
|
+
const feature = createFeature({
|
|
292
|
+
$id: 'https://schema.org.ai/features/new',
|
|
293
|
+
name: 'New Feature',
|
|
294
|
+
description: 'A new feature',
|
|
295
|
+
productId: 'https://schema.org.ai/products/main'
|
|
296
|
+
})
|
|
297
|
+
expect(feature.$type).toBe('https://schema.org.ai/Feature')
|
|
298
|
+
expect(feature.status).toBe('draft') // default
|
|
299
|
+
expect(isFeature(feature)).toBe(true)
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
// Test coverage for existing Definition types - ensure old style is rejected
|
|
304
|
+
describe('Type Coverage - Consolidation', () => {
|
|
305
|
+
it('AppDefinition should be replaced by App with Zod', () => {
|
|
306
|
+
// Old style should not work
|
|
307
|
+
const oldStyle = {
|
|
308
|
+
id: 'app-1',
|
|
309
|
+
type: 'app',
|
|
310
|
+
name: 'Old Style App',
|
|
311
|
+
description: 'Uses old pattern',
|
|
312
|
+
version: '1.0.0'
|
|
313
|
+
}
|
|
314
|
+
const result = AppSchema.safeParse(oldStyle)
|
|
315
|
+
expect(result.success).toBe(false)
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it('APIDefinition should be replaced by API with Zod', () => {
|
|
319
|
+
const oldStyle = {
|
|
320
|
+
id: 'api-1',
|
|
321
|
+
type: 'api',
|
|
322
|
+
name: 'Old Style API',
|
|
323
|
+
description: 'Uses old pattern',
|
|
324
|
+
version: '1.0.0'
|
|
325
|
+
}
|
|
326
|
+
const result = APISchema.safeParse(oldStyle)
|
|
327
|
+
expect(result.success).toBe(false)
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('SiteDefinition should be replaced by Site with Zod', () => {
|
|
331
|
+
const oldStyle = {
|
|
332
|
+
id: 'site-1',
|
|
333
|
+
type: 'site',
|
|
334
|
+
name: 'Old Style Site',
|
|
335
|
+
description: 'Uses old pattern',
|
|
336
|
+
version: '1.0.0'
|
|
337
|
+
}
|
|
338
|
+
const result = SiteSchema.safeParse(oldStyle)
|
|
339
|
+
expect(result.success).toBe(false)
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('DigitalProduct base type should be deprecated', () => {
|
|
343
|
+
// Old DigitalProduct uses id/name/description/version/status
|
|
344
|
+
// New Product uses $id/$type/name/description/status
|
|
345
|
+
const oldDigitalProduct = {
|
|
346
|
+
id: 'dp-1',
|
|
347
|
+
name: 'Old',
|
|
348
|
+
description: 'Old style',
|
|
349
|
+
version: '1.0.0',
|
|
350
|
+
status: 'active'
|
|
351
|
+
}
|
|
352
|
+
const result = ProductSchema.safeParse(oldDigitalProduct)
|
|
353
|
+
expect(result.success).toBe(false)
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
// Schema validation edge cases
|
|
358
|
+
describe('Schema Validation Edge Cases', () => {
|
|
359
|
+
describe('ProductSchema', () => {
|
|
360
|
+
it('should require $id', () => {
|
|
361
|
+
const missing = {
|
|
362
|
+
$type: 'https://schema.org.ai/Product' as const,
|
|
363
|
+
name: 'Test',
|
|
364
|
+
description: 'Test',
|
|
365
|
+
status: 'active' as const
|
|
366
|
+
}
|
|
367
|
+
const result = ProductSchema.safeParse(missing)
|
|
368
|
+
expect(result.success).toBe(false)
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
it('should require $type', () => {
|
|
372
|
+
const missing = {
|
|
373
|
+
$id: 'https://schema.org.ai/products/test',
|
|
374
|
+
name: 'Test',
|
|
375
|
+
description: 'Test',
|
|
376
|
+
status: 'active' as const
|
|
377
|
+
}
|
|
378
|
+
const result = ProductSchema.safeParse(missing)
|
|
379
|
+
expect(result.success).toBe(false)
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
it('should require name', () => {
|
|
383
|
+
const missing = {
|
|
384
|
+
$id: 'https://schema.org.ai/products/test',
|
|
385
|
+
$type: 'https://schema.org.ai/Product' as const,
|
|
386
|
+
description: 'Test',
|
|
387
|
+
status: 'active' as const
|
|
388
|
+
}
|
|
389
|
+
const result = ProductSchema.safeParse(missing)
|
|
390
|
+
expect(result.success).toBe(false)
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('should require description', () => {
|
|
394
|
+
const missing = {
|
|
395
|
+
$id: 'https://schema.org.ai/products/test',
|
|
396
|
+
$type: 'https://schema.org.ai/Product' as const,
|
|
397
|
+
name: 'Test',
|
|
398
|
+
status: 'active' as const
|
|
399
|
+
}
|
|
400
|
+
const result = ProductSchema.safeParse(missing)
|
|
401
|
+
expect(result.success).toBe(false)
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
it('should require status', () => {
|
|
405
|
+
const missing = {
|
|
406
|
+
$id: 'https://schema.org.ai/products/test',
|
|
407
|
+
$type: 'https://schema.org.ai/Product' as const,
|
|
408
|
+
name: 'Test',
|
|
409
|
+
description: 'Test'
|
|
410
|
+
}
|
|
411
|
+
const result = ProductSchema.safeParse(missing)
|
|
412
|
+
expect(result.success).toBe(false)
|
|
413
|
+
})
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
describe('AppSchema', () => {
|
|
417
|
+
it('should require platform', () => {
|
|
418
|
+
const missing = {
|
|
419
|
+
$id: 'https://schema.org.ai/apps/test',
|
|
420
|
+
$type: 'https://schema.org.ai/App' as const,
|
|
421
|
+
name: 'Test',
|
|
422
|
+
description: 'Test',
|
|
423
|
+
status: 'active' as const,
|
|
424
|
+
url: 'https://test.com'
|
|
425
|
+
}
|
|
426
|
+
const result = AppSchema.safeParse(missing)
|
|
427
|
+
expect(result.success).toBe(false)
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
it('should require url', () => {
|
|
431
|
+
const missing = {
|
|
432
|
+
$id: 'https://schema.org.ai/apps/test',
|
|
433
|
+
$type: 'https://schema.org.ai/App' as const,
|
|
434
|
+
name: 'Test',
|
|
435
|
+
description: 'Test',
|
|
436
|
+
status: 'active' as const,
|
|
437
|
+
platform: 'web' as const
|
|
438
|
+
}
|
|
439
|
+
const result = AppSchema.safeParse(missing)
|
|
440
|
+
expect(result.success).toBe(false)
|
|
441
|
+
})
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
describe('APISchema', () => {
|
|
445
|
+
it('should require baseUrl', () => {
|
|
446
|
+
const missing = {
|
|
447
|
+
$id: 'https://schema.org.ai/apis/test',
|
|
448
|
+
$type: 'https://schema.org.ai/API' as const,
|
|
449
|
+
name: 'Test',
|
|
450
|
+
description: 'Test',
|
|
451
|
+
status: 'active' as const,
|
|
452
|
+
version: '1.0.0',
|
|
453
|
+
authentication: 'bearer' as const
|
|
454
|
+
}
|
|
455
|
+
const result = APISchema.safeParse(missing)
|
|
456
|
+
expect(result.success).toBe(false)
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
it('should require version', () => {
|
|
460
|
+
const missing = {
|
|
461
|
+
$id: 'https://schema.org.ai/apis/test',
|
|
462
|
+
$type: 'https://schema.org.ai/API' as const,
|
|
463
|
+
name: 'Test',
|
|
464
|
+
description: 'Test',
|
|
465
|
+
status: 'active' as const,
|
|
466
|
+
baseUrl: 'https://api.test.com',
|
|
467
|
+
authentication: 'bearer' as const
|
|
468
|
+
}
|
|
469
|
+
const result = APISchema.safeParse(missing)
|
|
470
|
+
expect(result.success).toBe(false)
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
it('should require authentication', () => {
|
|
474
|
+
const missing = {
|
|
475
|
+
$id: 'https://schema.org.ai/apis/test',
|
|
476
|
+
$type: 'https://schema.org.ai/API' as const,
|
|
477
|
+
name: 'Test',
|
|
478
|
+
description: 'Test',
|
|
479
|
+
status: 'active' as const,
|
|
480
|
+
baseUrl: 'https://api.test.com',
|
|
481
|
+
version: '1.0.0'
|
|
482
|
+
}
|
|
483
|
+
const result = APISchema.safeParse(missing)
|
|
484
|
+
expect(result.success).toBe(false)
|
|
485
|
+
})
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
describe('SiteSchema', () => {
|
|
489
|
+
it('should require url', () => {
|
|
490
|
+
const missing = {
|
|
491
|
+
$id: 'https://schema.org.ai/sites/test',
|
|
492
|
+
$type: 'https://schema.org.ai/Site' as const,
|
|
493
|
+
name: 'Test',
|
|
494
|
+
description: 'Test',
|
|
495
|
+
status: 'active' as const,
|
|
496
|
+
siteType: 'docs' as const
|
|
497
|
+
}
|
|
498
|
+
const result = SiteSchema.safeParse(missing)
|
|
499
|
+
expect(result.success).toBe(false)
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
it('should require siteType', () => {
|
|
503
|
+
const missing = {
|
|
504
|
+
$id: 'https://schema.org.ai/sites/test',
|
|
505
|
+
$type: 'https://schema.org.ai/Site' as const,
|
|
506
|
+
name: 'Test',
|
|
507
|
+
description: 'Test',
|
|
508
|
+
status: 'active' as const,
|
|
509
|
+
url: 'https://test.com'
|
|
510
|
+
}
|
|
511
|
+
const result = SiteSchema.safeParse(missing)
|
|
512
|
+
expect(result.success).toBe(false)
|
|
513
|
+
})
|
|
514
|
+
})
|
|
515
|
+
|
|
516
|
+
describe('ServiceSchema', () => {
|
|
517
|
+
it('should allow empty endpoints array', () => {
|
|
518
|
+
const withEmpty = {
|
|
519
|
+
$id: 'https://schema.org.ai/services/test',
|
|
520
|
+
$type: 'https://schema.org.ai/Service' as const,
|
|
521
|
+
name: 'Test',
|
|
522
|
+
description: 'Test',
|
|
523
|
+
status: 'active' as const,
|
|
524
|
+
endpoints: []
|
|
525
|
+
}
|
|
526
|
+
const result = ServiceSchema.safeParse(withEmpty)
|
|
527
|
+
expect(result.success).toBe(true)
|
|
528
|
+
})
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
describe('FeatureSchema', () => {
|
|
532
|
+
it('should require productId', () => {
|
|
533
|
+
const missing = {
|
|
534
|
+
$id: 'https://schema.org.ai/features/test',
|
|
535
|
+
$type: 'https://schema.org.ai/Feature' as const,
|
|
536
|
+
name: 'Test',
|
|
537
|
+
description: 'Test',
|
|
538
|
+
status: 'draft' as const
|
|
539
|
+
}
|
|
540
|
+
const result = FeatureSchema.safeParse(missing)
|
|
541
|
+
expect(result.success).toBe(false)
|
|
542
|
+
})
|
|
543
|
+
|
|
544
|
+
it('should validate feature status enum', () => {
|
|
545
|
+
const invalidStatus = {
|
|
546
|
+
$id: 'https://schema.org.ai/features/test',
|
|
547
|
+
$type: 'https://schema.org.ai/Feature' as const,
|
|
548
|
+
name: 'Test',
|
|
549
|
+
description: 'Test',
|
|
550
|
+
productId: 'https://schema.org.ai/products/main',
|
|
551
|
+
status: 'active' // 'active' is not valid for Feature - should be draft/beta/ga/deprecated
|
|
552
|
+
}
|
|
553
|
+
const result = FeatureSchema.safeParse(invalidStatus)
|
|
554
|
+
expect(result.success).toBe(false)
|
|
555
|
+
})
|
|
556
|
+
})
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
// Type inference tests - ensure Zod infers correct TypeScript types
|
|
560
|
+
describe('Type Inference', () => {
|
|
561
|
+
it('ProductSchema.parse should return Product type', () => {
|
|
562
|
+
const input = {
|
|
563
|
+
$id: 'https://schema.org.ai/products/test',
|
|
564
|
+
$type: 'https://schema.org.ai/Product' as const,
|
|
565
|
+
name: 'Test',
|
|
566
|
+
description: 'Test',
|
|
567
|
+
status: 'active' as const
|
|
568
|
+
}
|
|
569
|
+
const result = ProductSchema.parse(input)
|
|
570
|
+
// TypeScript should infer result as Product type
|
|
571
|
+
const _typeCheck: typeof result.$type = 'https://schema.org.ai/Product'
|
|
572
|
+
expect(result.$type).toBe('https://schema.org.ai/Product')
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
it('AppSchema.parse should return App type', () => {
|
|
576
|
+
const input = {
|
|
577
|
+
$id: 'https://schema.org.ai/apps/test',
|
|
578
|
+
$type: 'https://schema.org.ai/App' as const,
|
|
579
|
+
name: 'Test',
|
|
580
|
+
description: 'Test',
|
|
581
|
+
status: 'active' as const,
|
|
582
|
+
platform: 'web' as const,
|
|
583
|
+
url: 'https://test.com'
|
|
584
|
+
}
|
|
585
|
+
const result = AppSchema.parse(input)
|
|
586
|
+
const _typeCheck: typeof result.$type = 'https://schema.org.ai/App'
|
|
587
|
+
expect(result.$type).toBe('https://schema.org.ai/App')
|
|
588
|
+
})
|
|
589
|
+
})
|