id.org.ai 0.1.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/.turbo/turbo-build.log +4 -0
- package/dist/index.d.ts +730 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +555 -0
- package/dist/index.js.map +1 -0
- package/package.json +34 -0
- package/src/index.ts +774 -0
- package/test/agent-identity.test.ts +356 -0
- package/test/credential.test.ts +337 -0
- package/test/identity.test.ts +202 -0
- package/test/session.test.ts +365 -0
- package/test/user.test.ts +307 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Tests - RED PHASE
|
|
3
|
+
*
|
|
4
|
+
* Tests for the User type which extends Identity.
|
|
5
|
+
* These tests WILL FAIL until the implementation is complete in GREEN phase.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect } from 'vitest'
|
|
9
|
+
import {
|
|
10
|
+
User,
|
|
11
|
+
UserSchema,
|
|
12
|
+
isUser,
|
|
13
|
+
createUser,
|
|
14
|
+
} from '../src'
|
|
15
|
+
|
|
16
|
+
describe('User', () => {
|
|
17
|
+
describe('interface shape', () => {
|
|
18
|
+
it('should have required $id field', () => {
|
|
19
|
+
const user: User = {
|
|
20
|
+
$id: 'https://example.com/users/1',
|
|
21
|
+
$type: 'https://schema.org.ai/User',
|
|
22
|
+
email: 'test@example.com',
|
|
23
|
+
name: 'Test User',
|
|
24
|
+
createdAt: new Date().toISOString(),
|
|
25
|
+
updatedAt: new Date().toISOString(),
|
|
26
|
+
}
|
|
27
|
+
expect(user.$id).toBe('https://example.com/users/1')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should have required $type field with correct value', () => {
|
|
31
|
+
const user: User = {
|
|
32
|
+
$id: 'https://example.com/users/1',
|
|
33
|
+
$type: 'https://schema.org.ai/User',
|
|
34
|
+
email: 'test@example.com',
|
|
35
|
+
name: 'Test User',
|
|
36
|
+
createdAt: new Date().toISOString(),
|
|
37
|
+
updatedAt: new Date().toISOString(),
|
|
38
|
+
}
|
|
39
|
+
expect(user.$type).toBe('https://schema.org.ai/User')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should have required email field', () => {
|
|
43
|
+
const user: User = {
|
|
44
|
+
$id: 'https://example.com/users/1',
|
|
45
|
+
$type: 'https://schema.org.ai/User',
|
|
46
|
+
email: 'test@example.com',
|
|
47
|
+
name: 'Test User',
|
|
48
|
+
createdAt: new Date().toISOString(),
|
|
49
|
+
updatedAt: new Date().toISOString(),
|
|
50
|
+
}
|
|
51
|
+
expect(user.email).toBe('test@example.com')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should have required name field', () => {
|
|
55
|
+
const user: User = {
|
|
56
|
+
$id: 'https://example.com/users/1',
|
|
57
|
+
$type: 'https://schema.org.ai/User',
|
|
58
|
+
email: 'test@example.com',
|
|
59
|
+
name: 'Test User',
|
|
60
|
+
createdAt: new Date().toISOString(),
|
|
61
|
+
updatedAt: new Date().toISOString(),
|
|
62
|
+
}
|
|
63
|
+
expect(user.name).toBe('Test User')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should support optional profile field', () => {
|
|
67
|
+
const user: User = {
|
|
68
|
+
$id: 'https://example.com/users/1',
|
|
69
|
+
$type: 'https://schema.org.ai/User',
|
|
70
|
+
email: 'test@example.com',
|
|
71
|
+
name: 'Test User',
|
|
72
|
+
createdAt: new Date().toISOString(),
|
|
73
|
+
updatedAt: new Date().toISOString(),
|
|
74
|
+
profile: {
|
|
75
|
+
avatar: 'https://example.com/avatar.png',
|
|
76
|
+
bio: 'A test user',
|
|
77
|
+
settings: { theme: 'dark' },
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
expect(user.profile).toBeDefined()
|
|
81
|
+
expect(user.profile?.avatar).toBe('https://example.com/avatar.png')
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('should inherit createdAt and updatedAt from Identity', () => {
|
|
85
|
+
const now = new Date().toISOString()
|
|
86
|
+
const user: User = {
|
|
87
|
+
$id: 'https://example.com/users/1',
|
|
88
|
+
$type: 'https://schema.org.ai/User',
|
|
89
|
+
email: 'test@example.com',
|
|
90
|
+
name: 'Test User',
|
|
91
|
+
createdAt: now,
|
|
92
|
+
updatedAt: now,
|
|
93
|
+
}
|
|
94
|
+
expect(user.createdAt).toBe(now)
|
|
95
|
+
expect(user.updatedAt).toBe(now)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
describe('Zod schema validation', () => {
|
|
100
|
+
it('should validate a valid User object', () => {
|
|
101
|
+
const result = UserSchema.safeParse({
|
|
102
|
+
$id: 'https://example.com/users/1',
|
|
103
|
+
$type: 'https://schema.org.ai/User',
|
|
104
|
+
email: 'test@example.com',
|
|
105
|
+
name: 'Test User',
|
|
106
|
+
createdAt: new Date().toISOString(),
|
|
107
|
+
updatedAt: new Date().toISOString(),
|
|
108
|
+
})
|
|
109
|
+
expect(result.success).toBe(true)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('should validate User with optional profile', () => {
|
|
113
|
+
const result = UserSchema.safeParse({
|
|
114
|
+
$id: 'https://example.com/users/1',
|
|
115
|
+
$type: 'https://schema.org.ai/User',
|
|
116
|
+
email: 'test@example.com',
|
|
117
|
+
name: 'Test User',
|
|
118
|
+
createdAt: new Date().toISOString(),
|
|
119
|
+
updatedAt: new Date().toISOString(),
|
|
120
|
+
profile: { avatar: 'https://example.com/avatar.png' },
|
|
121
|
+
})
|
|
122
|
+
expect(result.success).toBe(true)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('should reject User without email', () => {
|
|
126
|
+
const result = UserSchema.safeParse({
|
|
127
|
+
$id: 'https://example.com/users/1',
|
|
128
|
+
$type: 'https://schema.org.ai/User',
|
|
129
|
+
name: 'Test User',
|
|
130
|
+
createdAt: new Date().toISOString(),
|
|
131
|
+
updatedAt: new Date().toISOString(),
|
|
132
|
+
})
|
|
133
|
+
expect(result.success).toBe(false)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('should reject User with invalid email format', () => {
|
|
137
|
+
const result = UserSchema.safeParse({
|
|
138
|
+
$id: 'https://example.com/users/1',
|
|
139
|
+
$type: 'https://schema.org.ai/User',
|
|
140
|
+
email: 'not-an-email',
|
|
141
|
+
name: 'Test User',
|
|
142
|
+
createdAt: new Date().toISOString(),
|
|
143
|
+
updatedAt: new Date().toISOString(),
|
|
144
|
+
})
|
|
145
|
+
expect(result.success).toBe(false)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('should reject User without name', () => {
|
|
149
|
+
const result = UserSchema.safeParse({
|
|
150
|
+
$id: 'https://example.com/users/1',
|
|
151
|
+
$type: 'https://schema.org.ai/User',
|
|
152
|
+
email: 'test@example.com',
|
|
153
|
+
createdAt: new Date().toISOString(),
|
|
154
|
+
updatedAt: new Date().toISOString(),
|
|
155
|
+
})
|
|
156
|
+
expect(result.success).toBe(false)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('should reject User with wrong $type', () => {
|
|
160
|
+
const result = UserSchema.safeParse({
|
|
161
|
+
$id: 'https://example.com/users/1',
|
|
162
|
+
$type: 'https://schema.org.ai/Identity',
|
|
163
|
+
email: 'test@example.com',
|
|
164
|
+
name: 'Test User',
|
|
165
|
+
createdAt: new Date().toISOString(),
|
|
166
|
+
updatedAt: new Date().toISOString(),
|
|
167
|
+
})
|
|
168
|
+
expect(result.success).toBe(false)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should reject completely invalid data', () => {
|
|
172
|
+
const result = UserSchema.safeParse({ invalid: 'data' })
|
|
173
|
+
expect(result.success).toBe(false)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('should reject non-object values', () => {
|
|
177
|
+
expect(UserSchema.safeParse(null).success).toBe(false)
|
|
178
|
+
expect(UserSchema.safeParse(undefined).success).toBe(false)
|
|
179
|
+
expect(UserSchema.safeParse('string').success).toBe(false)
|
|
180
|
+
expect(UserSchema.safeParse(123).success).toBe(false)
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
describe('isUser type guard', () => {
|
|
185
|
+
it('should return true for valid User', () => {
|
|
186
|
+
const user = {
|
|
187
|
+
$id: 'https://example.com/users/1',
|
|
188
|
+
$type: 'https://schema.org.ai/User',
|
|
189
|
+
email: 'test@example.com',
|
|
190
|
+
name: 'Test User',
|
|
191
|
+
createdAt: new Date().toISOString(),
|
|
192
|
+
updatedAt: new Date().toISOString(),
|
|
193
|
+
}
|
|
194
|
+
expect(isUser(user)).toBe(true)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('should return true for User with profile', () => {
|
|
198
|
+
const user = {
|
|
199
|
+
$id: 'https://example.com/users/1',
|
|
200
|
+
$type: 'https://schema.org.ai/User',
|
|
201
|
+
email: 'test@example.com',
|
|
202
|
+
name: 'Test User',
|
|
203
|
+
createdAt: new Date().toISOString(),
|
|
204
|
+
updatedAt: new Date().toISOString(),
|
|
205
|
+
profile: { avatar: 'https://example.com/avatar.png' },
|
|
206
|
+
}
|
|
207
|
+
expect(isUser(user)).toBe(true)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('should return false for invalid data', () => {
|
|
211
|
+
expect(isUser({ invalid: 'data' })).toBe(false)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('should return false for null', () => {
|
|
215
|
+
expect(isUser(null)).toBe(false)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('should return false for undefined', () => {
|
|
219
|
+
expect(isUser(undefined)).toBe(false)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('should return false for Identity (base type)', () => {
|
|
223
|
+
const identity = {
|
|
224
|
+
$id: 'https://example.com/identities/1',
|
|
225
|
+
$type: 'https://schema.org.ai/Identity',
|
|
226
|
+
createdAt: new Date().toISOString(),
|
|
227
|
+
updatedAt: new Date().toISOString(),
|
|
228
|
+
}
|
|
229
|
+
expect(isUser(identity)).toBe(false)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('should return false for AgentIdentity', () => {
|
|
233
|
+
const agent = {
|
|
234
|
+
$id: 'https://example.com/agents/1',
|
|
235
|
+
$type: 'https://schema.org.ai/AgentIdentity',
|
|
236
|
+
model: 'claude-3-opus',
|
|
237
|
+
capabilities: ['text'],
|
|
238
|
+
autonomous: false,
|
|
239
|
+
createdAt: new Date().toISOString(),
|
|
240
|
+
updatedAt: new Date().toISOString(),
|
|
241
|
+
}
|
|
242
|
+
expect(isUser(agent)).toBe(false)
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
describe('createUser factory', () => {
|
|
247
|
+
it('should create a valid User with required fields', () => {
|
|
248
|
+
const user = createUser({
|
|
249
|
+
email: 'test@example.com',
|
|
250
|
+
name: 'Test User',
|
|
251
|
+
})
|
|
252
|
+
expect(user.$type).toBe('https://schema.org.ai/User')
|
|
253
|
+
expect(user.email).toBe('test@example.com')
|
|
254
|
+
expect(user.name).toBe('Test User')
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('should auto-generate $id', () => {
|
|
258
|
+
const user = createUser({
|
|
259
|
+
email: 'test@example.com',
|
|
260
|
+
name: 'Test User',
|
|
261
|
+
})
|
|
262
|
+
expect(user.$id).toBeDefined()
|
|
263
|
+
expect(user.$id).toMatch(/^https:\/\//)
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
it('should auto-generate timestamps', () => {
|
|
267
|
+
const before = new Date().toISOString()
|
|
268
|
+
const user = createUser({
|
|
269
|
+
email: 'test@example.com',
|
|
270
|
+
name: 'Test User',
|
|
271
|
+
})
|
|
272
|
+
const after = new Date().toISOString()
|
|
273
|
+
expect(user.createdAt >= before).toBe(true)
|
|
274
|
+
expect(user.createdAt <= after).toBe(true)
|
|
275
|
+
expect(user.updatedAt >= before).toBe(true)
|
|
276
|
+
expect(user.updatedAt <= after).toBe(true)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('should allow custom $id override', () => {
|
|
280
|
+
const customId = 'https://custom.com/users/custom-1'
|
|
281
|
+
const user = createUser({
|
|
282
|
+
$id: customId,
|
|
283
|
+
email: 'test@example.com',
|
|
284
|
+
name: 'Test User',
|
|
285
|
+
})
|
|
286
|
+
expect(user.$id).toBe(customId)
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
it('should accept optional profile', () => {
|
|
290
|
+
const user = createUser({
|
|
291
|
+
email: 'test@example.com',
|
|
292
|
+
name: 'Test User',
|
|
293
|
+
profile: { avatar: 'https://example.com/avatar.png' },
|
|
294
|
+
})
|
|
295
|
+
expect(user.profile?.avatar).toBe('https://example.com/avatar.png')
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
it('should pass validation after creation', () => {
|
|
299
|
+
const user = createUser({
|
|
300
|
+
email: 'test@example.com',
|
|
301
|
+
name: 'Test User',
|
|
302
|
+
})
|
|
303
|
+
expect(isUser(user)).toBe(true)
|
|
304
|
+
expect(UserSchema.safeParse(user).success).toBe(true)
|
|
305
|
+
})
|
|
306
|
+
})
|
|
307
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
"rootDir": "src",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"isolatedModules": true
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*.ts"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "test"]
|
|
21
|
+
}
|