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,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Tests - RED PHASE
|
|
3
|
+
*
|
|
4
|
+
* Tests for the base Identity interface that all identity types extend.
|
|
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
|
+
Identity,
|
|
11
|
+
IdentitySchema,
|
|
12
|
+
isIdentity,
|
|
13
|
+
createIdentity,
|
|
14
|
+
} from '../src'
|
|
15
|
+
|
|
16
|
+
describe('Identity', () => {
|
|
17
|
+
describe('interface shape', () => {
|
|
18
|
+
it('should have required $id field', () => {
|
|
19
|
+
const identity: Identity = {
|
|
20
|
+
$id: 'https://example.com/identities/1',
|
|
21
|
+
$type: 'https://schema.org.ai/Identity',
|
|
22
|
+
createdAt: new Date().toISOString(),
|
|
23
|
+
updatedAt: new Date().toISOString(),
|
|
24
|
+
}
|
|
25
|
+
expect(identity.$id).toBe('https://example.com/identities/1')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('should have required $type field with correct value', () => {
|
|
29
|
+
const identity: Identity = {
|
|
30
|
+
$id: 'https://example.com/identities/1',
|
|
31
|
+
$type: 'https://schema.org.ai/Identity',
|
|
32
|
+
createdAt: new Date().toISOString(),
|
|
33
|
+
updatedAt: new Date().toISOString(),
|
|
34
|
+
}
|
|
35
|
+
expect(identity.$type).toBe('https://schema.org.ai/Identity')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should have required createdAt timestamp', () => {
|
|
39
|
+
const now = new Date().toISOString()
|
|
40
|
+
const identity: Identity = {
|
|
41
|
+
$id: 'https://example.com/identities/1',
|
|
42
|
+
$type: 'https://schema.org.ai/Identity',
|
|
43
|
+
createdAt: now,
|
|
44
|
+
updatedAt: now,
|
|
45
|
+
}
|
|
46
|
+
expect(identity.createdAt).toBe(now)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should have required updatedAt timestamp', () => {
|
|
50
|
+
const now = new Date().toISOString()
|
|
51
|
+
const identity: Identity = {
|
|
52
|
+
$id: 'https://example.com/identities/1',
|
|
53
|
+
$type: 'https://schema.org.ai/Identity',
|
|
54
|
+
createdAt: now,
|
|
55
|
+
updatedAt: now,
|
|
56
|
+
}
|
|
57
|
+
expect(identity.updatedAt).toBe(now)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('Zod schema validation', () => {
|
|
62
|
+
it('should validate a valid Identity object', () => {
|
|
63
|
+
const result = IdentitySchema.safeParse({
|
|
64
|
+
$id: 'https://example.com/identities/1',
|
|
65
|
+
$type: 'https://schema.org.ai/Identity',
|
|
66
|
+
createdAt: new Date().toISOString(),
|
|
67
|
+
updatedAt: new Date().toISOString(),
|
|
68
|
+
})
|
|
69
|
+
expect(result.success).toBe(true)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('should reject Identity without $id', () => {
|
|
73
|
+
const result = IdentitySchema.safeParse({
|
|
74
|
+
$type: 'https://schema.org.ai/Identity',
|
|
75
|
+
createdAt: new Date().toISOString(),
|
|
76
|
+
updatedAt: new Date().toISOString(),
|
|
77
|
+
})
|
|
78
|
+
expect(result.success).toBe(false)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('should reject Identity with wrong $type', () => {
|
|
82
|
+
const result = IdentitySchema.safeParse({
|
|
83
|
+
$id: 'https://example.com/identities/1',
|
|
84
|
+
$type: 'https://wrong.type/Identity',
|
|
85
|
+
createdAt: new Date().toISOString(),
|
|
86
|
+
updatedAt: new Date().toISOString(),
|
|
87
|
+
})
|
|
88
|
+
expect(result.success).toBe(false)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('should reject Identity without createdAt', () => {
|
|
92
|
+
const result = IdentitySchema.safeParse({
|
|
93
|
+
$id: 'https://example.com/identities/1',
|
|
94
|
+
$type: 'https://schema.org.ai/Identity',
|
|
95
|
+
updatedAt: new Date().toISOString(),
|
|
96
|
+
})
|
|
97
|
+
expect(result.success).toBe(false)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('should reject Identity without updatedAt', () => {
|
|
101
|
+
const result = IdentitySchema.safeParse({
|
|
102
|
+
$id: 'https://example.com/identities/1',
|
|
103
|
+
$type: 'https://schema.org.ai/Identity',
|
|
104
|
+
createdAt: new Date().toISOString(),
|
|
105
|
+
})
|
|
106
|
+
expect(result.success).toBe(false)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should reject completely invalid data', () => {
|
|
110
|
+
const result = IdentitySchema.safeParse({ invalid: 'data' })
|
|
111
|
+
expect(result.success).toBe(false)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('should reject non-object values', () => {
|
|
115
|
+
expect(IdentitySchema.safeParse(null).success).toBe(false)
|
|
116
|
+
expect(IdentitySchema.safeParse(undefined).success).toBe(false)
|
|
117
|
+
expect(IdentitySchema.safeParse('string').success).toBe(false)
|
|
118
|
+
expect(IdentitySchema.safeParse(123).success).toBe(false)
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe('isIdentity type guard', () => {
|
|
123
|
+
it('should return true for valid Identity', () => {
|
|
124
|
+
const identity = {
|
|
125
|
+
$id: 'https://example.com/identities/1',
|
|
126
|
+
$type: 'https://schema.org.ai/Identity',
|
|
127
|
+
createdAt: new Date().toISOString(),
|
|
128
|
+
updatedAt: new Date().toISOString(),
|
|
129
|
+
}
|
|
130
|
+
expect(isIdentity(identity)).toBe(true)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('should return false for invalid data', () => {
|
|
134
|
+
expect(isIdentity({ invalid: 'data' })).toBe(false)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('should return false for null', () => {
|
|
138
|
+
expect(isIdentity(null)).toBe(false)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should return false for undefined', () => {
|
|
142
|
+
expect(isIdentity(undefined)).toBe(false)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('should return false for primitives', () => {
|
|
146
|
+
expect(isIdentity('string')).toBe(false)
|
|
147
|
+
expect(isIdentity(123)).toBe(false)
|
|
148
|
+
expect(isIdentity(true)).toBe(false)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('should return false for objects with wrong $type', () => {
|
|
152
|
+
const notIdentity = {
|
|
153
|
+
$id: 'https://example.com/identities/1',
|
|
154
|
+
$type: 'https://schema.org.ai/User',
|
|
155
|
+
createdAt: new Date().toISOString(),
|
|
156
|
+
updatedAt: new Date().toISOString(),
|
|
157
|
+
}
|
|
158
|
+
expect(isIdentity(notIdentity)).toBe(false)
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe('createIdentity factory', () => {
|
|
163
|
+
it('should create a valid Identity with auto-generated $id', () => {
|
|
164
|
+
const identity = createIdentity()
|
|
165
|
+
expect(identity.$id).toBeDefined()
|
|
166
|
+
expect(identity.$id).toMatch(/^https:\/\//)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('should create Identity with correct $type', () => {
|
|
170
|
+
const identity = createIdentity()
|
|
171
|
+
expect(identity.$type).toBe('https://schema.org.ai/Identity')
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('should auto-generate createdAt timestamp', () => {
|
|
175
|
+
const before = new Date().toISOString()
|
|
176
|
+
const identity = createIdentity()
|
|
177
|
+
const after = new Date().toISOString()
|
|
178
|
+
expect(identity.createdAt >= before).toBe(true)
|
|
179
|
+
expect(identity.createdAt <= after).toBe(true)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('should auto-generate updatedAt timestamp', () => {
|
|
183
|
+
const before = new Date().toISOString()
|
|
184
|
+
const identity = createIdentity()
|
|
185
|
+
const after = new Date().toISOString()
|
|
186
|
+
expect(identity.updatedAt >= before).toBe(true)
|
|
187
|
+
expect(identity.updatedAt <= after).toBe(true)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('should allow custom $id override', () => {
|
|
191
|
+
const customId = 'https://custom.com/identities/custom-1'
|
|
192
|
+
const identity = createIdentity({ $id: customId })
|
|
193
|
+
expect(identity.$id).toBe(customId)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should pass validation after creation', () => {
|
|
197
|
+
const identity = createIdentity()
|
|
198
|
+
expect(isIdentity(identity)).toBe(true)
|
|
199
|
+
expect(IdentitySchema.safeParse(identity).success).toBe(true)
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
})
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Tests - RED PHASE
|
|
3
|
+
*
|
|
4
|
+
* Tests for the Session type used for authentication sessions.
|
|
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
|
+
Session,
|
|
11
|
+
SessionSchema,
|
|
12
|
+
isSession,
|
|
13
|
+
createSession,
|
|
14
|
+
} from '../src'
|
|
15
|
+
|
|
16
|
+
describe('Session', () => {
|
|
17
|
+
describe('interface shape', () => {
|
|
18
|
+
it('should have required $id field', () => {
|
|
19
|
+
const session: Session = {
|
|
20
|
+
$id: 'https://example.com/sessions/1',
|
|
21
|
+
$type: 'https://schema.org.ai/Session',
|
|
22
|
+
identityId: 'https://example.com/users/1',
|
|
23
|
+
token: 'session-token-abc123',
|
|
24
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
25
|
+
}
|
|
26
|
+
expect(session.$id).toBe('https://example.com/sessions/1')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should have required $type field with correct value', () => {
|
|
30
|
+
const session: Session = {
|
|
31
|
+
$id: 'https://example.com/sessions/1',
|
|
32
|
+
$type: 'https://schema.org.ai/Session',
|
|
33
|
+
identityId: 'https://example.com/users/1',
|
|
34
|
+
token: 'session-token-abc123',
|
|
35
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
36
|
+
}
|
|
37
|
+
expect(session.$type).toBe('https://schema.org.ai/Session')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should have required identityId field', () => {
|
|
41
|
+
const session: Session = {
|
|
42
|
+
$id: 'https://example.com/sessions/1',
|
|
43
|
+
$type: 'https://schema.org.ai/Session',
|
|
44
|
+
identityId: 'https://example.com/users/1',
|
|
45
|
+
token: 'session-token-abc123',
|
|
46
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
47
|
+
}
|
|
48
|
+
expect(session.identityId).toBe('https://example.com/users/1')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('should have required token field', () => {
|
|
52
|
+
const session: Session = {
|
|
53
|
+
$id: 'https://example.com/sessions/1',
|
|
54
|
+
$type: 'https://schema.org.ai/Session',
|
|
55
|
+
identityId: 'https://example.com/users/1',
|
|
56
|
+
token: 'session-token-abc123',
|
|
57
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
58
|
+
}
|
|
59
|
+
expect(session.token).toBe('session-token-abc123')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should have required expiresAt field', () => {
|
|
63
|
+
const expiresAt = new Date(Date.now() + 3600000).toISOString()
|
|
64
|
+
const session: Session = {
|
|
65
|
+
$id: 'https://example.com/sessions/1',
|
|
66
|
+
$type: 'https://schema.org.ai/Session',
|
|
67
|
+
identityId: 'https://example.com/users/1',
|
|
68
|
+
token: 'session-token-abc123',
|
|
69
|
+
expiresAt,
|
|
70
|
+
}
|
|
71
|
+
expect(session.expiresAt).toBe(expiresAt)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('should support optional metadata field', () => {
|
|
75
|
+
const session: Session = {
|
|
76
|
+
$id: 'https://example.com/sessions/1',
|
|
77
|
+
$type: 'https://schema.org.ai/Session',
|
|
78
|
+
identityId: 'https://example.com/users/1',
|
|
79
|
+
token: 'session-token-abc123',
|
|
80
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
81
|
+
metadata: {
|
|
82
|
+
userAgent: 'Mozilla/5.0',
|
|
83
|
+
ipAddress: '192.168.1.1',
|
|
84
|
+
device: 'desktop',
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
expect(session.metadata).toBeDefined()
|
|
88
|
+
expect(session.metadata?.userAgent).toBe('Mozilla/5.0')
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
describe('Zod schema validation', () => {
|
|
93
|
+
it('should validate a valid Session object', () => {
|
|
94
|
+
const result = SessionSchema.safeParse({
|
|
95
|
+
$id: 'https://example.com/sessions/1',
|
|
96
|
+
$type: 'https://schema.org.ai/Session',
|
|
97
|
+
identityId: 'https://example.com/users/1',
|
|
98
|
+
token: 'session-token-abc123',
|
|
99
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
100
|
+
})
|
|
101
|
+
expect(result.success).toBe(true)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should validate Session with optional metadata', () => {
|
|
105
|
+
const result = SessionSchema.safeParse({
|
|
106
|
+
$id: 'https://example.com/sessions/1',
|
|
107
|
+
$type: 'https://schema.org.ai/Session',
|
|
108
|
+
identityId: 'https://example.com/users/1',
|
|
109
|
+
token: 'session-token-abc123',
|
|
110
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
111
|
+
metadata: { userAgent: 'Mozilla/5.0' },
|
|
112
|
+
})
|
|
113
|
+
expect(result.success).toBe(true)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('should reject Session without $id', () => {
|
|
117
|
+
const result = SessionSchema.safeParse({
|
|
118
|
+
$type: 'https://schema.org.ai/Session',
|
|
119
|
+
identityId: 'https://example.com/users/1',
|
|
120
|
+
token: 'session-token-abc123',
|
|
121
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
122
|
+
})
|
|
123
|
+
expect(result.success).toBe(false)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('should reject Session without identityId', () => {
|
|
127
|
+
const result = SessionSchema.safeParse({
|
|
128
|
+
$id: 'https://example.com/sessions/1',
|
|
129
|
+
$type: 'https://schema.org.ai/Session',
|
|
130
|
+
token: 'session-token-abc123',
|
|
131
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
132
|
+
})
|
|
133
|
+
expect(result.success).toBe(false)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('should reject Session without token', () => {
|
|
137
|
+
const result = SessionSchema.safeParse({
|
|
138
|
+
$id: 'https://example.com/sessions/1',
|
|
139
|
+
$type: 'https://schema.org.ai/Session',
|
|
140
|
+
identityId: 'https://example.com/users/1',
|
|
141
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
142
|
+
})
|
|
143
|
+
expect(result.success).toBe(false)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('should reject Session without expiresAt', () => {
|
|
147
|
+
const result = SessionSchema.safeParse({
|
|
148
|
+
$id: 'https://example.com/sessions/1',
|
|
149
|
+
$type: 'https://schema.org.ai/Session',
|
|
150
|
+
identityId: 'https://example.com/users/1',
|
|
151
|
+
token: 'session-token-abc123',
|
|
152
|
+
})
|
|
153
|
+
expect(result.success).toBe(false)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should reject Session with empty token', () => {
|
|
157
|
+
const result = SessionSchema.safeParse({
|
|
158
|
+
$id: 'https://example.com/sessions/1',
|
|
159
|
+
$type: 'https://schema.org.ai/Session',
|
|
160
|
+
identityId: 'https://example.com/users/1',
|
|
161
|
+
token: '',
|
|
162
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
163
|
+
})
|
|
164
|
+
expect(result.success).toBe(false)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('should reject Session with wrong $type', () => {
|
|
168
|
+
const result = SessionSchema.safeParse({
|
|
169
|
+
$id: 'https://example.com/sessions/1',
|
|
170
|
+
$type: 'https://schema.org.ai/Credential',
|
|
171
|
+
identityId: 'https://example.com/users/1',
|
|
172
|
+
token: 'session-token-abc123',
|
|
173
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
174
|
+
})
|
|
175
|
+
expect(result.success).toBe(false)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('should reject completely invalid data', () => {
|
|
179
|
+
const result = SessionSchema.safeParse({ invalid: 'data' })
|
|
180
|
+
expect(result.success).toBe(false)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('should reject non-object values', () => {
|
|
184
|
+
expect(SessionSchema.safeParse(null).success).toBe(false)
|
|
185
|
+
expect(SessionSchema.safeParse(undefined).success).toBe(false)
|
|
186
|
+
expect(SessionSchema.safeParse('string').success).toBe(false)
|
|
187
|
+
expect(SessionSchema.safeParse(123).success).toBe(false)
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
describe('isSession type guard', () => {
|
|
192
|
+
it('should return true for valid Session', () => {
|
|
193
|
+
const session = {
|
|
194
|
+
$id: 'https://example.com/sessions/1',
|
|
195
|
+
$type: 'https://schema.org.ai/Session',
|
|
196
|
+
identityId: 'https://example.com/users/1',
|
|
197
|
+
token: 'session-token-abc123',
|
|
198
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
199
|
+
}
|
|
200
|
+
expect(isSession(session)).toBe(true)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('should return true for Session with metadata', () => {
|
|
204
|
+
const session = {
|
|
205
|
+
$id: 'https://example.com/sessions/1',
|
|
206
|
+
$type: 'https://schema.org.ai/Session',
|
|
207
|
+
identityId: 'https://example.com/users/1',
|
|
208
|
+
token: 'session-token-abc123',
|
|
209
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
210
|
+
metadata: { userAgent: 'Mozilla/5.0' },
|
|
211
|
+
}
|
|
212
|
+
expect(isSession(session)).toBe(true)
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('should return false for invalid data', () => {
|
|
216
|
+
expect(isSession({ invalid: 'data' })).toBe(false)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('should return false for null', () => {
|
|
220
|
+
expect(isSession(null)).toBe(false)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
it('should return false for undefined', () => {
|
|
224
|
+
expect(isSession(undefined)).toBe(false)
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it('should return false for Credential type', () => {
|
|
228
|
+
const credential = {
|
|
229
|
+
$id: 'https://example.com/credentials/1',
|
|
230
|
+
$type: 'https://schema.org.ai/Credential',
|
|
231
|
+
identityId: 'https://example.com/users/1',
|
|
232
|
+
credentialType: 'password',
|
|
233
|
+
}
|
|
234
|
+
expect(isSession(credential)).toBe(false)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('should return false for User type', () => {
|
|
238
|
+
const user = {
|
|
239
|
+
$id: 'https://example.com/users/1',
|
|
240
|
+
$type: 'https://schema.org.ai/User',
|
|
241
|
+
email: 'test@example.com',
|
|
242
|
+
name: 'Test User',
|
|
243
|
+
createdAt: new Date().toISOString(),
|
|
244
|
+
updatedAt: new Date().toISOString(),
|
|
245
|
+
}
|
|
246
|
+
expect(isSession(user)).toBe(false)
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
describe('createSession factory', () => {
|
|
251
|
+
it('should create a valid Session with required fields', () => {
|
|
252
|
+
const session = createSession({
|
|
253
|
+
identityId: 'https://example.com/users/1',
|
|
254
|
+
token: 'session-token-abc123',
|
|
255
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
256
|
+
})
|
|
257
|
+
expect(session.$type).toBe('https://schema.org.ai/Session')
|
|
258
|
+
expect(session.identityId).toBe('https://example.com/users/1')
|
|
259
|
+
expect(session.token).toBe('session-token-abc123')
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('should auto-generate $id', () => {
|
|
263
|
+
const session = createSession({
|
|
264
|
+
identityId: 'https://example.com/users/1',
|
|
265
|
+
token: 'session-token-abc123',
|
|
266
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
267
|
+
})
|
|
268
|
+
expect(session.$id).toBeDefined()
|
|
269
|
+
expect(session.$id).toMatch(/^https:\/\//)
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('should allow custom $id override', () => {
|
|
273
|
+
const customId = 'https://custom.com/sessions/custom-1'
|
|
274
|
+
const session = createSession({
|
|
275
|
+
$id: customId,
|
|
276
|
+
identityId: 'https://example.com/users/1',
|
|
277
|
+
token: 'session-token-abc123',
|
|
278
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
279
|
+
})
|
|
280
|
+
expect(session.$id).toBe(customId)
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it('should accept optional metadata', () => {
|
|
284
|
+
const session = createSession({
|
|
285
|
+
identityId: 'https://example.com/users/1',
|
|
286
|
+
token: 'session-token-abc123',
|
|
287
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
288
|
+
metadata: {
|
|
289
|
+
userAgent: 'Mozilla/5.0',
|
|
290
|
+
ipAddress: '192.168.1.1',
|
|
291
|
+
},
|
|
292
|
+
})
|
|
293
|
+
expect(session.metadata?.userAgent).toBe('Mozilla/5.0')
|
|
294
|
+
expect(session.metadata?.ipAddress).toBe('192.168.1.1')
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('should auto-generate token if not provided', () => {
|
|
298
|
+
const session = createSession({
|
|
299
|
+
identityId: 'https://example.com/users/1',
|
|
300
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
301
|
+
})
|
|
302
|
+
expect(session.token).toBeDefined()
|
|
303
|
+
expect(session.token.length).toBeGreaterThan(0)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('should support default expiration duration', () => {
|
|
307
|
+
const before = Date.now()
|
|
308
|
+
const session = createSession({
|
|
309
|
+
identityId: 'https://example.com/users/1',
|
|
310
|
+
token: 'session-token-abc123',
|
|
311
|
+
})
|
|
312
|
+
const after = Date.now()
|
|
313
|
+
|
|
314
|
+
// Default should be some reasonable duration (e.g., 24 hours)
|
|
315
|
+
const expiresAt = new Date(session.expiresAt).getTime()
|
|
316
|
+
expect(expiresAt).toBeGreaterThan(before)
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('should create session for agent identity', () => {
|
|
320
|
+
const session = createSession({
|
|
321
|
+
identityId: 'https://example.com/agents/1',
|
|
322
|
+
token: 'agent-session-token',
|
|
323
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
324
|
+
})
|
|
325
|
+
expect(session.identityId).toBe('https://example.com/agents/1')
|
|
326
|
+
expect(isSession(session)).toBe(true)
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
it('should pass validation after creation', () => {
|
|
330
|
+
const session = createSession({
|
|
331
|
+
identityId: 'https://example.com/users/1',
|
|
332
|
+
token: 'session-token-abc123',
|
|
333
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
334
|
+
})
|
|
335
|
+
expect(isSession(session)).toBe(true)
|
|
336
|
+
expect(SessionSchema.safeParse(session).success).toBe(true)
|
|
337
|
+
})
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
describe('session expiration', () => {
|
|
341
|
+
it('should support checking if session is expired', () => {
|
|
342
|
+
const expiredSession: Session = {
|
|
343
|
+
$id: 'https://example.com/sessions/1',
|
|
344
|
+
$type: 'https://schema.org.ai/Session',
|
|
345
|
+
identityId: 'https://example.com/users/1',
|
|
346
|
+
token: 'session-token-abc123',
|
|
347
|
+
expiresAt: new Date(Date.now() - 3600000).toISOString(), // 1 hour ago
|
|
348
|
+
}
|
|
349
|
+
const expiresAt = new Date(expiredSession.expiresAt).getTime()
|
|
350
|
+
expect(expiresAt < Date.now()).toBe(true)
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('should support checking if session is valid', () => {
|
|
354
|
+
const validSession: Session = {
|
|
355
|
+
$id: 'https://example.com/sessions/1',
|
|
356
|
+
$type: 'https://schema.org.ai/Session',
|
|
357
|
+
identityId: 'https://example.com/users/1',
|
|
358
|
+
token: 'session-token-abc123',
|
|
359
|
+
expiresAt: new Date(Date.now() + 3600000).toISOString(), // 1 hour from now
|
|
360
|
+
}
|
|
361
|
+
const expiresAt = new Date(validSession.expiresAt).getTime()
|
|
362
|
+
expect(expiresAt > Date.now()).toBe(true)
|
|
363
|
+
})
|
|
364
|
+
})
|
|
365
|
+
})
|