@seamless-auth/types 0.1.0 → 0.1.1
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/dist/index.d.ts +5 -5
- package/dist/index.js +5 -5
- package/dist/schemas/{authEvent.schema.js → authEvent/schema.js} +1 -1
- package/dist/schemas/authEvent/schema.test.d.ts +1 -0
- package/dist/schemas/authEvent/schema.test.js +71 -0
- package/dist/schemas/{credential.schema.d.ts → credential/schema.d.ts} +24 -6
- package/dist/schemas/{credential.schema.js → credential/schema.js} +8 -4
- package/dist/schemas/credential/schema.test.d.ts +1 -0
- package/dist/schemas/credential/schema.test.js +74 -0
- package/dist/schemas/session/schema.test.d.ts +1 -0
- package/dist/schemas/session/schema.test.js +61 -0
- package/dist/schemas/{user.schema.d.ts → user/schema.d.ts} +1 -1
- package/dist/schemas/{user.schema.js → user/schema.js} +2 -2
- package/dist/schemas/user/schema.test.d.ts +1 -0
- package/dist/schemas/user/schema.test.js +115 -0
- package/package.json +8 -8
- /package/dist/schemas/{auth.schema.d.ts → auth/auth.schema.d.ts} +0 -0
- /package/dist/schemas/{auth.schema.js → auth/auth.schema.js} +0 -0
- /package/dist/schemas/{authEvent.schema.d.ts → authEvent/schema.d.ts} +0 -0
- /package/dist/schemas/{sessions.schema.d.ts → session/schema.d.ts} +0 -0
- /package/dist/schemas/{sessions.schema.js → session/schema.js} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from './schemas/user
|
|
2
|
-
export * from './schemas/credential
|
|
3
|
-
export * from './schemas/auth.schema';
|
|
4
|
-
export * from './schemas/authEvent
|
|
5
|
-
export * from './schemas/
|
|
1
|
+
export * from './schemas/user/schema';
|
|
2
|
+
export * from './schemas/credential/schema';
|
|
3
|
+
export * from './schemas/auth/auth.schema';
|
|
4
|
+
export * from './schemas/authEvent/schema';
|
|
5
|
+
export * from './schemas/session/schema';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from './schemas/user
|
|
2
|
-
export * from './schemas/credential
|
|
3
|
-
export * from './schemas/auth.schema';
|
|
4
|
-
export * from './schemas/authEvent
|
|
5
|
-
export * from './schemas/
|
|
1
|
+
export * from './schemas/user/schema';
|
|
2
|
+
export * from './schemas/credential/schema';
|
|
3
|
+
export * from './schemas/auth/auth.schema';
|
|
4
|
+
export * from './schemas/authEvent/schema';
|
|
5
|
+
export * from './schemas/session/schema';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { AuthEventSchema } from './schema';
|
|
3
|
+
const now = new Date().toISOString();
|
|
4
|
+
describe('AuthEventSchema', () => {
|
|
5
|
+
const baseEvent = {
|
|
6
|
+
id: 'event_123',
|
|
7
|
+
user_id: 'user_123',
|
|
8
|
+
type: 'login',
|
|
9
|
+
ip_address: '127.0.0.1',
|
|
10
|
+
user_agent: 'Mozilla/5.0',
|
|
11
|
+
metadata: {
|
|
12
|
+
device: 'desktop',
|
|
13
|
+
success: true,
|
|
14
|
+
},
|
|
15
|
+
created_at: now,
|
|
16
|
+
updated_at: now,
|
|
17
|
+
};
|
|
18
|
+
it('parses a valid auth event', () => {
|
|
19
|
+
expect(() => AuthEventSchema.parse(baseEvent)).not.toThrow();
|
|
20
|
+
});
|
|
21
|
+
it('allows nullable optional fields', () => {
|
|
22
|
+
const minimal = {
|
|
23
|
+
id: 'event_123',
|
|
24
|
+
type: 'login',
|
|
25
|
+
metadata: null,
|
|
26
|
+
created_at: now,
|
|
27
|
+
updated_at: now,
|
|
28
|
+
};
|
|
29
|
+
expect(() => AuthEventSchema.parse(minimal)).not.toThrow();
|
|
30
|
+
});
|
|
31
|
+
it('allows missing optional fields', () => {
|
|
32
|
+
const { ...rest } = baseEvent;
|
|
33
|
+
expect(() => AuthEventSchema.parse(rest)).not.toThrow();
|
|
34
|
+
});
|
|
35
|
+
it('fails if required fields are missing', () => {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
37
|
+
const { id, ...rest } = baseEvent;
|
|
38
|
+
expect(() => AuthEventSchema.parse(rest)).toThrow();
|
|
39
|
+
});
|
|
40
|
+
it('fails if metadata is not an object or null', () => {
|
|
41
|
+
expect(() => AuthEventSchema.parse({
|
|
42
|
+
...baseEvent,
|
|
43
|
+
metadata: 'invalid',
|
|
44
|
+
})).toThrow();
|
|
45
|
+
});
|
|
46
|
+
it('allows metadata with arbitrary values', () => {
|
|
47
|
+
expect(() => AuthEventSchema.parse({
|
|
48
|
+
...baseEvent,
|
|
49
|
+
metadata: {
|
|
50
|
+
string: 'value',
|
|
51
|
+
number: 123,
|
|
52
|
+
boolean: true,
|
|
53
|
+
nested: { key: 'value' },
|
|
54
|
+
array: [1, 2, 3],
|
|
55
|
+
},
|
|
56
|
+
})).not.toThrow();
|
|
57
|
+
});
|
|
58
|
+
it('fails on invalid ISO date', () => {
|
|
59
|
+
expect(() => AuthEventSchema.parse({
|
|
60
|
+
...baseEvent,
|
|
61
|
+
created_at: 'not-a-date',
|
|
62
|
+
})).toThrow();
|
|
63
|
+
});
|
|
64
|
+
it('fails when metadata is undefined (not nullable)', () => {
|
|
65
|
+
const { ...rest } = baseEvent;
|
|
66
|
+
expect(() => AuthEventSchema.parse({
|
|
67
|
+
...rest,
|
|
68
|
+
metadata: undefined,
|
|
69
|
+
})).toThrow();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
2
|
export declare const CredentialSchema: z.ZodObject<{
|
|
3
3
|
id: z.ZodString;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
backedUp: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
4
|
+
userId: z.ZodString;
|
|
5
|
+
publicKey: z.ZodString;
|
|
7
6
|
counter: z.ZodNumber;
|
|
7
|
+
transports: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
8
|
+
ble: "ble";
|
|
9
|
+
internal: "internal";
|
|
10
|
+
nfc: "nfc";
|
|
11
|
+
usb: "usb";
|
|
12
|
+
}>>>;
|
|
13
|
+
deviceType: z.ZodOptional<z.ZodEnum<{
|
|
14
|
+
singleDevice: "singleDevice";
|
|
15
|
+
multiDevice: "multiDevice";
|
|
16
|
+
}>>;
|
|
17
|
+
backedUp: z.ZodBoolean;
|
|
8
18
|
friendlyName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
9
19
|
lastUsedAt: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodCoercedDate<unknown>, z.ZodTransform<string, Date>>>>;
|
|
10
20
|
platform: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -29,10 +39,18 @@ export declare const CredentialApiSchema: z.ZodObject<{
|
|
|
29
39
|
id: z.ZodString;
|
|
30
40
|
browser: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
31
41
|
createdAt: z.ZodPipe<z.ZodCoercedDate<unknown>, z.ZodTransform<string, Date>>;
|
|
32
|
-
transports: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
33
|
-
deviceType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
34
|
-
backedUp: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
35
42
|
counter: z.ZodNumber;
|
|
43
|
+
transports: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
44
|
+
ble: "ble";
|
|
45
|
+
internal: "internal";
|
|
46
|
+
nfc: "nfc";
|
|
47
|
+
usb: "usb";
|
|
48
|
+
}>>>;
|
|
49
|
+
deviceType: z.ZodOptional<z.ZodEnum<{
|
|
50
|
+
singleDevice: "singleDevice";
|
|
51
|
+
multiDevice: "multiDevice";
|
|
52
|
+
}>>;
|
|
53
|
+
backedUp: z.ZodBoolean;
|
|
36
54
|
friendlyName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
37
55
|
lastUsedAt: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodCoercedDate<unknown>, z.ZodTransform<string, Date>>>>;
|
|
38
56
|
deviceInfo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
|
-
import { IsoDate } from '
|
|
2
|
+
import { IsoDate } from '../../shared';
|
|
3
|
+
const TransportSchema = z.enum(['usb', 'ble', 'nfc', 'internal']);
|
|
4
|
+
const DeviceTypeSchema = z.enum(['singleDevice', 'multiDevice']);
|
|
3
5
|
export const CredentialSchema = z.object({
|
|
4
6
|
id: z.string(),
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
backedUp: z.boolean().nullable().optional(),
|
|
7
|
+
userId: z.string(),
|
|
8
|
+
publicKey: z.string(),
|
|
8
9
|
counter: z.number(),
|
|
10
|
+
transports: z.array(TransportSchema).optional(),
|
|
11
|
+
deviceType: DeviceTypeSchema.optional(),
|
|
12
|
+
backedUp: z.boolean(),
|
|
9
13
|
friendlyName: z.string().nullable().optional(),
|
|
10
14
|
lastUsedAt: IsoDate.nullable().optional(),
|
|
11
15
|
platform: z.string().nullable().optional(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { CredentialSchema } from './schema';
|
|
3
|
+
const now = new Date().toISOString();
|
|
4
|
+
describe('CredentialSchema', () => {
|
|
5
|
+
const baseCredential = {
|
|
6
|
+
id: 'credential_id_base64url',
|
|
7
|
+
userId: crypto.randomUUID(),
|
|
8
|
+
publicKey: 'public_key_base64url',
|
|
9
|
+
counter: 0,
|
|
10
|
+
transports: ['internal'],
|
|
11
|
+
deviceType: 'singleDevice',
|
|
12
|
+
backedUp: false,
|
|
13
|
+
friendlyName: 'My Device',
|
|
14
|
+
lastUsedAt: now,
|
|
15
|
+
platform: 'ios',
|
|
16
|
+
browser: 'safari',
|
|
17
|
+
deviceInfo: 'iPhone',
|
|
18
|
+
createdAt: now,
|
|
19
|
+
updatedAt: now,
|
|
20
|
+
};
|
|
21
|
+
it('parses a valid credential', () => {
|
|
22
|
+
expect(() => CredentialSchema.parse(baseCredential)).not.toThrow();
|
|
23
|
+
});
|
|
24
|
+
it('fails when required fields are missing', () => {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
26
|
+
const { id, ...rest } = baseCredential;
|
|
27
|
+
expect(() => CredentialSchema.parse(rest)).toThrow();
|
|
28
|
+
});
|
|
29
|
+
it('fails when publicKey is not a string', () => {
|
|
30
|
+
expect(() => CredentialSchema.parse({
|
|
31
|
+
...baseCredential,
|
|
32
|
+
publicKey: 123,
|
|
33
|
+
})).toThrow();
|
|
34
|
+
});
|
|
35
|
+
it('allows optional metadata fields to be omitted', () => {
|
|
36
|
+
const { ...minimal } = baseCredential;
|
|
37
|
+
expect(() => CredentialSchema.parse(minimal)).not.toThrow();
|
|
38
|
+
});
|
|
39
|
+
it('allows nullable optional fields', () => {
|
|
40
|
+
expect(() => CredentialSchema.parse({
|
|
41
|
+
...baseCredential,
|
|
42
|
+
friendlyName: null,
|
|
43
|
+
platform: null,
|
|
44
|
+
browser: null,
|
|
45
|
+
deviceInfo: null,
|
|
46
|
+
})).not.toThrow();
|
|
47
|
+
});
|
|
48
|
+
it('allows missing transports', () => {
|
|
49
|
+
const { ...rest } = baseCredential;
|
|
50
|
+
expect(() => CredentialSchema.parse(rest)).not.toThrow();
|
|
51
|
+
});
|
|
52
|
+
it('fails on invalid transport value', () => {
|
|
53
|
+
expect(() => CredentialSchema.parse({
|
|
54
|
+
...baseCredential,
|
|
55
|
+
transports: ['invalid'],
|
|
56
|
+
})).toThrow();
|
|
57
|
+
});
|
|
58
|
+
it('fails on invalid deviceType', () => {
|
|
59
|
+
expect(() => CredentialSchema.parse({
|
|
60
|
+
...baseCredential,
|
|
61
|
+
deviceType: 'invalidType',
|
|
62
|
+
})).toThrow();
|
|
63
|
+
});
|
|
64
|
+
it('fails on invalid ISO date', () => {
|
|
65
|
+
expect(() => CredentialSchema.parse({
|
|
66
|
+
...baseCredential,
|
|
67
|
+
createdAt: 'not-a-date',
|
|
68
|
+
})).toThrow();
|
|
69
|
+
});
|
|
70
|
+
it('allows lastUsedAt to be omitted', () => {
|
|
71
|
+
const { ...rest } = baseCredential;
|
|
72
|
+
expect(() => CredentialSchema.parse(rest)).not.toThrow();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { SessionSchema } from './schema';
|
|
3
|
+
const now = new Date().toISOString();
|
|
4
|
+
const later = new Date(Date.now() + 1000 * 60 * 60).toISOString();
|
|
5
|
+
describe('SessionSchema', () => {
|
|
6
|
+
const baseSession = {
|
|
7
|
+
id: 'session_123',
|
|
8
|
+
deviceName: 'MacBook Pro',
|
|
9
|
+
ipAddress: '127.0.0.1',
|
|
10
|
+
userAgent: 'Mozilla/5.0',
|
|
11
|
+
lastUsedAt: now,
|
|
12
|
+
expiresAt: later,
|
|
13
|
+
current: true,
|
|
14
|
+
};
|
|
15
|
+
it('parses a valid session', () => {
|
|
16
|
+
expect(() => SessionSchema.parse(baseSession)).not.toThrow();
|
|
17
|
+
});
|
|
18
|
+
it('allows optional nullable fields to be omitted', () => {
|
|
19
|
+
const { ...minimal } = baseSession;
|
|
20
|
+
expect(() => SessionSchema.parse(minimal)).not.toThrow();
|
|
21
|
+
});
|
|
22
|
+
it('allows optional nullable fields to be null', () => {
|
|
23
|
+
expect(() => SessionSchema.parse({
|
|
24
|
+
...baseSession,
|
|
25
|
+
deviceName: null,
|
|
26
|
+
ipAddress: null,
|
|
27
|
+
userAgent: null,
|
|
28
|
+
})).not.toThrow();
|
|
29
|
+
});
|
|
30
|
+
it('fails when required fields are missing', () => {
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
32
|
+
const { id, ...rest } = baseSession;
|
|
33
|
+
expect(() => SessionSchema.parse(rest)).toThrow();
|
|
34
|
+
});
|
|
35
|
+
it('fails when current is not a boolean', () => {
|
|
36
|
+
expect(() => SessionSchema.parse({
|
|
37
|
+
...baseSession,
|
|
38
|
+
current: 'true',
|
|
39
|
+
})).toThrow();
|
|
40
|
+
});
|
|
41
|
+
it('fails when lastUsedAt is not a string', () => {
|
|
42
|
+
expect(() => SessionSchema.parse({
|
|
43
|
+
...baseSession,
|
|
44
|
+
lastUsedAt: 123,
|
|
45
|
+
})).toThrow();
|
|
46
|
+
});
|
|
47
|
+
it('fails when expiresAt is not a string', () => {
|
|
48
|
+
expect(() => SessionSchema.parse({
|
|
49
|
+
...baseSession,
|
|
50
|
+
expiresAt: 123,
|
|
51
|
+
})).toThrow();
|
|
52
|
+
});
|
|
53
|
+
it('allows different valid session shapes', () => {
|
|
54
|
+
expect(() => SessionSchema.parse({
|
|
55
|
+
id: 'session_456',
|
|
56
|
+
lastUsedAt: now,
|
|
57
|
+
expiresAt: later,
|
|
58
|
+
current: false,
|
|
59
|
+
})).not.toThrow();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -24,5 +24,5 @@ export declare const UpdateUserSchema: z.ZodObject<{
|
|
|
24
24
|
phone: z.ZodOptional<z.ZodString>;
|
|
25
25
|
emailVerified: z.ZodOptional<z.ZodBoolean>;
|
|
26
26
|
phoneVerified: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
-
roles: z.ZodArray<z.ZodString
|
|
27
|
+
roles: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
28
28
|
}, z.core.$strict>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { IsoDate } from '
|
|
2
|
+
import { IsoDate } from '../../shared';
|
|
3
3
|
export const RoleSchema = z.string().regex(/^(?!.*[_/\\\s])[A-Za-z0-9-]{1,31}$/);
|
|
4
4
|
export const UserSchema = z.object({
|
|
5
5
|
id: z.uuid(),
|
|
@@ -25,6 +25,6 @@ export const UpdateUserSchema = z
|
|
|
25
25
|
phone: z.string().min(5).optional(),
|
|
26
26
|
emailVerified: z.boolean().optional(),
|
|
27
27
|
phoneVerified: z.boolean().optional(),
|
|
28
|
-
roles: z.array(RoleSchema).min(1),
|
|
28
|
+
roles: z.array(RoleSchema).min(1).optional(),
|
|
29
29
|
})
|
|
30
30
|
.strict();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { UserSchema, CreateUserSchema, UpdateUserSchema } from './schema';
|
|
3
|
+
const now = new Date().toISOString();
|
|
4
|
+
describe('UserSchema', () => {
|
|
5
|
+
const baseUser = {
|
|
6
|
+
id: crypto.randomUUID(),
|
|
7
|
+
email: 'test@example.com',
|
|
8
|
+
phone: '1234567890',
|
|
9
|
+
roles: ['user'],
|
|
10
|
+
revoked: false,
|
|
11
|
+
emailVerified: true,
|
|
12
|
+
phoneVerified: false,
|
|
13
|
+
verified: true,
|
|
14
|
+
lastLogin: now,
|
|
15
|
+
createdAt: now,
|
|
16
|
+
updatedAt: now,
|
|
17
|
+
};
|
|
18
|
+
it('parses a valid user', () => {
|
|
19
|
+
expect(() => UserSchema.parse(baseUser)).not.toThrow();
|
|
20
|
+
});
|
|
21
|
+
it('applies defaults when optional fields are missing', () => {
|
|
22
|
+
const minimal = {
|
|
23
|
+
id: crypto.randomUUID(),
|
|
24
|
+
email: 'test@example.com',
|
|
25
|
+
phone: '1234567890',
|
|
26
|
+
createdAt: now,
|
|
27
|
+
};
|
|
28
|
+
const parsed = UserSchema.parse(minimal);
|
|
29
|
+
expect(parsed.roles).toEqual([]);
|
|
30
|
+
expect(parsed.revoked).toBe(false);
|
|
31
|
+
expect(parsed.emailVerified).toBe(false);
|
|
32
|
+
expect(parsed.phoneVerified).toBe(false);
|
|
33
|
+
expect(parsed.verified).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
it('fails on invalid email', () => {
|
|
36
|
+
expect(() => UserSchema.parse({
|
|
37
|
+
...baseUser,
|
|
38
|
+
email: 'invalid-email',
|
|
39
|
+
})).toThrow();
|
|
40
|
+
});
|
|
41
|
+
it('fails on invalid role format', () => {
|
|
42
|
+
expect(() => UserSchema.parse({
|
|
43
|
+
...baseUser,
|
|
44
|
+
roles: ['bad role'], // contains space
|
|
45
|
+
})).toThrow();
|
|
46
|
+
});
|
|
47
|
+
it('allows nullable lastLogin', () => {
|
|
48
|
+
expect(() => UserSchema.parse({
|
|
49
|
+
...baseUser,
|
|
50
|
+
lastLogin: null,
|
|
51
|
+
})).not.toThrow();
|
|
52
|
+
});
|
|
53
|
+
it('allows missing optional fields', () => {
|
|
54
|
+
const { ...rest } = baseUser;
|
|
55
|
+
expect(() => UserSchema.parse(rest)).not.toThrow();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('CreateUserSchema', () => {
|
|
59
|
+
it('parses valid input', () => {
|
|
60
|
+
expect(() => CreateUserSchema.parse({
|
|
61
|
+
email: 'test@example.com',
|
|
62
|
+
phone: '1234567890',
|
|
63
|
+
roles: ['admin'],
|
|
64
|
+
})).not.toThrow();
|
|
65
|
+
});
|
|
66
|
+
it('fails if roles are empty', () => {
|
|
67
|
+
expect(() => CreateUserSchema.parse({
|
|
68
|
+
email: 'test@example.com',
|
|
69
|
+
phone: '1234567890',
|
|
70
|
+
roles: [],
|
|
71
|
+
})).toThrow();
|
|
72
|
+
});
|
|
73
|
+
it('fails on invalid email', () => {
|
|
74
|
+
expect(() => CreateUserSchema.parse({
|
|
75
|
+
email: 'bad-email',
|
|
76
|
+
phone: '1234567890',
|
|
77
|
+
roles: ['user'],
|
|
78
|
+
})).toThrow();
|
|
79
|
+
});
|
|
80
|
+
it('fails on invalid role format', () => {
|
|
81
|
+
expect(() => CreateUserSchema.parse({
|
|
82
|
+
email: 'test@example.com',
|
|
83
|
+
phone: '1234567890',
|
|
84
|
+
roles: ['bad role'],
|
|
85
|
+
})).toThrow();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('UpdateUserSchema', () => {
|
|
89
|
+
it('parses valid partial update', () => {
|
|
90
|
+
expect(() => UpdateUserSchema.parse({
|
|
91
|
+
email: 'new@example.com',
|
|
92
|
+
})).not.toThrow();
|
|
93
|
+
});
|
|
94
|
+
it('requires roles if provided and must be non-empty', () => {
|
|
95
|
+
expect(() => UpdateUserSchema.parse({
|
|
96
|
+
roles: [],
|
|
97
|
+
})).toThrow();
|
|
98
|
+
});
|
|
99
|
+
it('fails on short phone number', () => {
|
|
100
|
+
expect(() => UpdateUserSchema.parse({
|
|
101
|
+
phone: '123',
|
|
102
|
+
})).toThrow();
|
|
103
|
+
});
|
|
104
|
+
it('fails on invalid role format', () => {
|
|
105
|
+
expect(() => UpdateUserSchema.parse({
|
|
106
|
+
roles: ['invalid role'],
|
|
107
|
+
})).toThrow();
|
|
108
|
+
});
|
|
109
|
+
it('fails on unknown fields due to strict()', () => {
|
|
110
|
+
expect(() => UpdateUserSchema.parse({
|
|
111
|
+
email: 'test@example.com',
|
|
112
|
+
unknownField: true,
|
|
113
|
+
})).toThrow();
|
|
114
|
+
});
|
|
115
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamless-auth/types",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Shared TypeScript types and Zod schemas for SeamlessAuth.",
|
|
5
5
|
"author": "Fells Code, LLC",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -8,10 +8,7 @@
|
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
|
-
".":
|
|
12
|
-
"types": "./dist/index.d.ts",
|
|
13
|
-
"import": "./dist/index.js"
|
|
14
|
-
}
|
|
11
|
+
".": "./dist/index.js"
|
|
15
12
|
},
|
|
16
13
|
"files": [
|
|
17
14
|
"dist"
|
|
@@ -43,7 +40,9 @@
|
|
|
43
40
|
"format": "prettier --write .",
|
|
44
41
|
"format:check": "prettier --check .",
|
|
45
42
|
"prepare": "husky",
|
|
46
|
-
"prepublishOnly": "npm run build"
|
|
43
|
+
"prepublishOnly": "npm run build",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest"
|
|
47
46
|
},
|
|
48
47
|
"lint-staged": {
|
|
49
48
|
"*.ts": [
|
|
@@ -64,7 +63,8 @@
|
|
|
64
63
|
"husky": "^9.1.7",
|
|
65
64
|
"lint-staged": "^16.4.0",
|
|
66
65
|
"prettier": "^3.8.1",
|
|
67
|
-
"typescript": "^5.9.3"
|
|
66
|
+
"typescript": "^5.9.3",
|
|
67
|
+
"vitest": "^4.1.1"
|
|
68
68
|
},
|
|
69
69
|
"engines": {
|
|
70
70
|
"node": ">=20"
|
|
@@ -72,4 +72,4 @@
|
|
|
72
72
|
"publishConfig": {
|
|
73
73
|
"access": "public"
|
|
74
74
|
}
|
|
75
|
-
}
|
|
75
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|