@cloudauth/core 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/LICENSE +21 -0
- package/dist/adapter.d.ts +20 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +2 -0
- package/dist/adapter.js.map +1 -0
- package/dist/additional-fields.d.ts +31 -0
- package/dist/additional-fields.d.ts.map +1 -0
- package/dist/additional-fields.js +2 -0
- package/dist/additional-fields.js.map +1 -0
- package/dist/auth.d.ts +26 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +280 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +55 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -0
- package/dist/cookies.d.ts +29 -0
- package/dist/cookies.d.ts.map +1 -0
- package/dist/cookies.js +98 -0
- package/dist/cookies.js.map +1 -0
- package/dist/crypto.d.ts +23 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +57 -0
- package/dist/crypto.js.map +1 -0
- package/dist/csrf.d.ts +6 -0
- package/dist/csrf.d.ts.map +1 -0
- package/dist/csrf.js +24 -0
- package/dist/csrf.js.map +1 -0
- package/dist/encryption.d.ts +10 -0
- package/dist/encryption.d.ts.map +1 -0
- package/dist/encryption.js +61 -0
- package/dist/encryption.js.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/hooks.d.ts +45 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +2 -0
- package/dist/hooks.js.map +1 -0
- package/dist/http.d.ts +23 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +126 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +19 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +2 -0
- package/dist/provider.js.map +1 -0
- package/dist/rate-limiter.d.ts +33 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +45 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/test/adapter-conformance.d.ts +13 -0
- package/dist/test/adapter-conformance.d.ts.map +1 -0
- package/dist/test/adapter-conformance.js +212 -0
- package/dist/test/adapter-conformance.js.map +1 -0
- package/dist/test/cookies.test.d.ts +2 -0
- package/dist/test/cookies.test.d.ts.map +1 -0
- package/dist/test/cookies.test.js +83 -0
- package/dist/test/cookies.test.js.map +1 -0
- package/dist/test/crypto.test.d.ts +2 -0
- package/dist/test/crypto.test.d.ts.map +1 -0
- package/dist/test/crypto.test.js +84 -0
- package/dist/test/crypto.test.js.map +1 -0
- package/dist/test/encryption.test.d.ts +2 -0
- package/dist/test/encryption.test.d.ts.map +1 -0
- package/dist/test/encryption.test.js +34 -0
- package/dist/test/encryption.test.js.map +1 -0
- package/dist/test/factories.d.ts +11 -0
- package/dist/test/factories.d.ts.map +1 -0
- package/dist/test/factories.js +110 -0
- package/dist/test/factories.js.map +1 -0
- package/dist/test/index.d.ts +6 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +4 -0
- package/dist/test/index.js.map +1 -0
- package/dist/test/mock-provider.d.ts +34 -0
- package/dist/test/mock-provider.d.ts.map +1 -0
- package/dist/test/mock-provider.js +99 -0
- package/dist/test/mock-provider.js.map +1 -0
- package/dist/test/rate-limiter.test.d.ts +2 -0
- package/dist/test/rate-limiter.test.d.ts.map +1 -0
- package/dist/test/rate-limiter.test.js +38 -0
- package/dist/test/rate-limiter.test.js.map +1 -0
- package/dist/test/url.test.d 2.ts +2 -0
- package/dist/test/url.test.d.ts +2 -0
- package/dist/test/url.test.d.ts 2.map +1 -0
- package/dist/test/url.test.d.ts.map +1 -0
- package/dist/test/url.test.js +40 -0
- package/dist/test/url.test.js 2.map +1 -0
- package/dist/test/url.test.js.map +1 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/url.d.ts +11 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +35 -0
- package/dist/url.js.map +1 -0
- package/package.json +27 -0
- package/src/adapter.ts +39 -0
- package/src/additional-fields.ts +53 -0
- package/src/auth.ts +355 -0
- package/src/config.ts +62 -0
- package/src/cookies.ts +123 -0
- package/src/crypto.ts +62 -0
- package/src/csrf.ts +27 -0
- package/src/encryption.ts +88 -0
- package/src/errors.ts +65 -0
- package/src/hooks.ts +54 -0
- package/src/http.ts +192 -0
- package/src/index.ts +161 -0
- package/src/provider.ts +21 -0
- package/src/rate-limiter.ts +64 -0
- package/src/test/adapter-conformance.ts +267 -0
- package/src/test/cookies.test.ts +99 -0
- package/src/test/crypto.test.ts +103 -0
- package/src/test/encryption.test.ts +40 -0
- package/src/test/factories.ts +139 -0
- package/src/test/index.ts +17 -0
- package/src/test/mock-provider.ts +130 -0
- package/src/test/rate-limiter.test.ts +49 -0
- package/src/test/url.test.ts +48 -0
- package/src/types.ts +122 -0
- package/src/url.ts +35 -0
- package/tsconfig 2.tsbuildinfo +1 -0
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ProviderProfile, TokenSet } from './types.js';
|
|
2
|
+
export interface AuthorizationParams {
|
|
3
|
+
state: string;
|
|
4
|
+
codeVerifier: string;
|
|
5
|
+
redirectUri: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ExchangeCodeParams {
|
|
8
|
+
code: string;
|
|
9
|
+
codeVerifier: string;
|
|
10
|
+
redirectUri: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AuthProvider {
|
|
13
|
+
id: string;
|
|
14
|
+
type: 'oauth' | 'oidc';
|
|
15
|
+
authorizationUrl(params: AuthorizationParams): URL;
|
|
16
|
+
exchangeCode(params: ExchangeCodeParams): Promise<TokenSet>;
|
|
17
|
+
getProfile(tokens: TokenSet): Promise<ProviderProfile>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE3D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;IACtB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,GAAG,GAAG,CAAA;IAClD,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC3D,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CACvD"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface RateLimitResult {
|
|
2
|
+
allowed: boolean;
|
|
3
|
+
remaining: number;
|
|
4
|
+
resetAt: Date;
|
|
5
|
+
}
|
|
6
|
+
export interface RateLimiter {
|
|
7
|
+
check(key: string, limit: number, windowMs: number): Promise<RateLimitResult>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* In-memory sliding window rate limiter.
|
|
11
|
+
* Suitable for single-instance development, NOT for production multi-instance use.
|
|
12
|
+
* For production, provide a Redis/D1-based implementation.
|
|
13
|
+
*/
|
|
14
|
+
export declare function inMemoryRateLimiter(): RateLimiter;
|
|
15
|
+
export declare const defaultRateLimits: {
|
|
16
|
+
readonly signIn: {
|
|
17
|
+
readonly limit: 10;
|
|
18
|
+
readonly windowMs: 60000;
|
|
19
|
+
};
|
|
20
|
+
readonly callback: {
|
|
21
|
+
readonly limit: 20;
|
|
22
|
+
readonly windowMs: 60000;
|
|
23
|
+
};
|
|
24
|
+
readonly logout: {
|
|
25
|
+
readonly limit: 30;
|
|
26
|
+
readonly windowMs: 60000;
|
|
27
|
+
};
|
|
28
|
+
readonly linkAccount: {
|
|
29
|
+
readonly limit: 5;
|
|
30
|
+
readonly windowMs: 60000;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,IAAI,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAC9E;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,CAqCjD;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;CAKpB,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory sliding window rate limiter.
|
|
3
|
+
* Suitable for single-instance development, NOT for production multi-instance use.
|
|
4
|
+
* For production, provide a Redis/D1-based implementation.
|
|
5
|
+
*/
|
|
6
|
+
export function inMemoryRateLimiter() {
|
|
7
|
+
const windows = new Map();
|
|
8
|
+
return {
|
|
9
|
+
check(key, limit, windowMs) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const now = Date.now();
|
|
12
|
+
let entry = windows.get(key);
|
|
13
|
+
if (!entry) {
|
|
14
|
+
entry = { timestamps: [] };
|
|
15
|
+
windows.set(key, entry);
|
|
16
|
+
}
|
|
17
|
+
// Remove timestamps outside the current window
|
|
18
|
+
const active = entry.timestamps.filter((ts) => now - ts < windowMs);
|
|
19
|
+
entry.timestamps = active;
|
|
20
|
+
if (active.length >= limit) {
|
|
21
|
+
const oldest = active[0] ?? now;
|
|
22
|
+
resolve({
|
|
23
|
+
allowed: false,
|
|
24
|
+
remaining: 0,
|
|
25
|
+
resetAt: new Date(oldest + windowMs),
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
active.push(now);
|
|
30
|
+
resolve({
|
|
31
|
+
allowed: true,
|
|
32
|
+
remaining: limit - active.length,
|
|
33
|
+
resetAt: new Date(now + windowMs),
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export const defaultRateLimits = {
|
|
40
|
+
signIn: { limit: 10, windowMs: 60_000 },
|
|
41
|
+
callback: { limit: 20, windowMs: 60_000 },
|
|
42
|
+
logout: { limit: 30, windowMs: 60_000 },
|
|
43
|
+
linkAccount: { limit: 5, windowMs: 60_000 },
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAA;IAE9C,OAAO;QACL,KAAK,CAAC,GAAW,EAAE,KAAa,EAAE,QAAgB;YAChD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;gBACtB,IAAI,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;gBAE5B,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,KAAK,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,CAAA;oBAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;gBACzB,CAAC;gBAED,+CAA+C;gBAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAA;gBACnE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAA;gBAEzB,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;oBAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;oBAC/B,OAAO,CAAC;wBACN,OAAO,EAAE,KAAK;wBACd,SAAS,EAAE,CAAC;wBACZ,OAAO,EAAE,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;qBACrC,CAAC,CAAA;oBACF,OAAM;gBACR,CAAC;gBAED,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBAChB,OAAO,CAAC;oBACN,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM;oBAChC,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC;iBAClC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IACvC,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IACzC,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IACvC,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE;CACnC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthAdapter } from '../adapter.js';
|
|
2
|
+
export interface AdapterConformanceOptions {
|
|
3
|
+
name: string;
|
|
4
|
+
createAdapter: () => AuthAdapter;
|
|
5
|
+
setup?: () => Promise<void>;
|
|
6
|
+
teardown?: () => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Run the standard adapter conformance test suite.
|
|
10
|
+
* Any adapter implementation must pass all tests in this suite.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runAdapterConformanceTests(options: AdapterConformanceOptions): void;
|
|
13
|
+
//# sourceMappingURL=adapter-conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-conformance.d.ts","sourceRoot":"","sources":["../../src/test/adapter-conformance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAGhD,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,WAAW,CAAA;IAChC,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,yBAAyB,GAAG,IAAI,CA2PnF"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'vitest';
|
|
2
|
+
/**
|
|
3
|
+
* Run the standard adapter conformance test suite.
|
|
4
|
+
* Any adapter implementation must pass all tests in this suite.
|
|
5
|
+
*/
|
|
6
|
+
export function runAdapterConformanceTests(options) {
|
|
7
|
+
const { name, createAdapter, setup, teardown } = options;
|
|
8
|
+
describe(`Adapter conformance: ${name}`, () => {
|
|
9
|
+
let adapter;
|
|
10
|
+
const testUser = {
|
|
11
|
+
email: 'conformance@example.com',
|
|
12
|
+
emailVerified: true,
|
|
13
|
+
name: 'Conformance Test',
|
|
14
|
+
image: null,
|
|
15
|
+
};
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
await setup?.();
|
|
18
|
+
});
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
adapter = createAdapter();
|
|
21
|
+
});
|
|
22
|
+
afterAll(async () => {
|
|
23
|
+
await teardown?.();
|
|
24
|
+
});
|
|
25
|
+
// --- User operations ---
|
|
26
|
+
it('should create and retrieve a user', async () => {
|
|
27
|
+
const user = await adapter.createUser(testUser);
|
|
28
|
+
expect(user.id).toBeDefined();
|
|
29
|
+
expect(user.email).toBe('conformance@example.com');
|
|
30
|
+
expect(user.emailVerified).toBe(true);
|
|
31
|
+
expect(user.name).toBe('Conformance Test');
|
|
32
|
+
const retrieved = await adapter.getUserById(user.id);
|
|
33
|
+
expect(retrieved).not.toBeNull();
|
|
34
|
+
if (retrieved) {
|
|
35
|
+
expect(retrieved.id).toBe(user.id);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
it('should return null for non-existent user by id', async () => {
|
|
39
|
+
const result = await adapter.getUserById('non_existent_id');
|
|
40
|
+
expect(result).toBeNull();
|
|
41
|
+
});
|
|
42
|
+
it('should find user by email', async () => {
|
|
43
|
+
const user = await adapter.createUser(testUser);
|
|
44
|
+
const found = await adapter.getUserByEmail(user.email ?? '');
|
|
45
|
+
expect(found).not.toBeNull();
|
|
46
|
+
if (found) {
|
|
47
|
+
expect(found.id).toBe(user.id);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
it('should return null for non-existent email', async () => {
|
|
51
|
+
const result = await adapter.getUserByEmail('nonexistent@example.com');
|
|
52
|
+
expect(result).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
it('should partially update a user', async () => {
|
|
55
|
+
const user = await adapter.createUser(testUser);
|
|
56
|
+
const updated = await adapter.updateUser(user.id, { name: 'Updated Name' });
|
|
57
|
+
expect(updated.name).toBe('Updated Name');
|
|
58
|
+
expect(updated.email).toBe(user.email);
|
|
59
|
+
});
|
|
60
|
+
// --- Account operations ---
|
|
61
|
+
it('should create and retrieve an account', async () => {
|
|
62
|
+
const user = await adapter.createUser(testUser);
|
|
63
|
+
const account = await adapter.createAccount({
|
|
64
|
+
userId: user.id,
|
|
65
|
+
provider: 'google',
|
|
66
|
+
providerAccountId: 'google_123',
|
|
67
|
+
});
|
|
68
|
+
expect(account.id).toBeDefined();
|
|
69
|
+
expect(account.provider).toBe('google');
|
|
70
|
+
expect(account.providerAccountId).toBe('google_123');
|
|
71
|
+
const retrieved = await adapter.getAccount('google', 'google_123');
|
|
72
|
+
expect(retrieved).not.toBeNull();
|
|
73
|
+
if (retrieved) {
|
|
74
|
+
expect(retrieved.id).toBe(account.id);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
it('should enforce unique (provider, providerAccountId)', async () => {
|
|
78
|
+
const user = await adapter.createUser(testUser);
|
|
79
|
+
await adapter.createAccount({
|
|
80
|
+
userId: user.id,
|
|
81
|
+
provider: 'google',
|
|
82
|
+
providerAccountId: 'unique_test_123',
|
|
83
|
+
});
|
|
84
|
+
await expect(adapter.createAccount({
|
|
85
|
+
userId: user.id,
|
|
86
|
+
provider: 'google',
|
|
87
|
+
providerAccountId: 'unique_test_123',
|
|
88
|
+
})).rejects.toThrow();
|
|
89
|
+
});
|
|
90
|
+
it('should get accounts by user id', async () => {
|
|
91
|
+
const user = await adapter.createUser(testUser);
|
|
92
|
+
await adapter.createAccount({
|
|
93
|
+
userId: user.id,
|
|
94
|
+
provider: 'google',
|
|
95
|
+
providerAccountId: 'google_1',
|
|
96
|
+
});
|
|
97
|
+
await adapter.createAccount({
|
|
98
|
+
userId: user.id,
|
|
99
|
+
provider: 'github',
|
|
100
|
+
providerAccountId: 'github_1',
|
|
101
|
+
});
|
|
102
|
+
const accounts = await adapter.getAccountsByUserId(user.id);
|
|
103
|
+
expect(accounts).toHaveLength(2);
|
|
104
|
+
});
|
|
105
|
+
it('should link an account to an existing user', async () => {
|
|
106
|
+
const user = await adapter.createUser(testUser);
|
|
107
|
+
const linked = await adapter.linkAccount(user.id, {
|
|
108
|
+
userId: user.id,
|
|
109
|
+
provider: 'github',
|
|
110
|
+
providerAccountId: 'github_linked',
|
|
111
|
+
});
|
|
112
|
+
expect(linked.userId).toBe(user.id);
|
|
113
|
+
expect(linked.provider).toBe('github');
|
|
114
|
+
});
|
|
115
|
+
it('should delete an account', async () => {
|
|
116
|
+
const user = await adapter.createUser(testUser);
|
|
117
|
+
const account = await adapter.createAccount({
|
|
118
|
+
userId: user.id,
|
|
119
|
+
provider: 'google',
|
|
120
|
+
providerAccountId: 'to_delete',
|
|
121
|
+
});
|
|
122
|
+
await adapter.deleteAccount(account.id);
|
|
123
|
+
const retrieved = await adapter.getAccount('google', 'to_delete');
|
|
124
|
+
expect(retrieved).toBeNull();
|
|
125
|
+
});
|
|
126
|
+
// --- Session operations ---
|
|
127
|
+
it('should create and retrieve a session with user', async () => {
|
|
128
|
+
const user = await adapter.createUser(testUser);
|
|
129
|
+
const session = await adapter.createSession({
|
|
130
|
+
userId: user.id,
|
|
131
|
+
tokenHash: 'session_hash_1',
|
|
132
|
+
expiresAt: new Date(Date.now() + 86_400_000),
|
|
133
|
+
});
|
|
134
|
+
expect(session.id).toBeDefined();
|
|
135
|
+
expect(session.tokenHash).toBe('session_hash_1');
|
|
136
|
+
const retrieved = await adapter.getSessionByTokenHash('session_hash_1');
|
|
137
|
+
expect(retrieved).not.toBeNull();
|
|
138
|
+
if (retrieved) {
|
|
139
|
+
expect(retrieved.session.id).toBe(session.id);
|
|
140
|
+
expect(retrieved.user.id).toBe(user.id);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
it('should return null for unknown session token hash', async () => {
|
|
144
|
+
const result = await adapter.getSessionByTokenHash('unknown_hash');
|
|
145
|
+
expect(result).toBeNull();
|
|
146
|
+
});
|
|
147
|
+
it('should update a session', async () => {
|
|
148
|
+
const user = await adapter.createUser(testUser);
|
|
149
|
+
const session = await adapter.createSession({
|
|
150
|
+
userId: user.id,
|
|
151
|
+
tokenHash: 'session_to_update',
|
|
152
|
+
expiresAt: new Date(Date.now() + 86_400_000),
|
|
153
|
+
});
|
|
154
|
+
const newExpiry = new Date(Date.now() + 172_800_000);
|
|
155
|
+
const updated = await adapter.updateSession(session.id, {
|
|
156
|
+
expiresAt: newExpiry,
|
|
157
|
+
});
|
|
158
|
+
expect(updated.expiresAt.getTime()).toBe(newExpiry.getTime());
|
|
159
|
+
});
|
|
160
|
+
it('should delete a session', async () => {
|
|
161
|
+
const user = await adapter.createUser(testUser);
|
|
162
|
+
await adapter.createSession({
|
|
163
|
+
userId: user.id,
|
|
164
|
+
tokenHash: 'session_to_delete',
|
|
165
|
+
expiresAt: new Date(Date.now() + 86_400_000),
|
|
166
|
+
});
|
|
167
|
+
await adapter.deleteSession('session_to_delete');
|
|
168
|
+
const retrieved = await adapter.getSessionByTokenHash('session_to_delete');
|
|
169
|
+
expect(retrieved).toBeNull();
|
|
170
|
+
});
|
|
171
|
+
it('should delete only expired sessions', async () => {
|
|
172
|
+
const user = await adapter.createUser(testUser);
|
|
173
|
+
await adapter.createSession({
|
|
174
|
+
userId: user.id,
|
|
175
|
+
tokenHash: 'expired_session',
|
|
176
|
+
expiresAt: new Date(Date.now() - 86_400_000),
|
|
177
|
+
});
|
|
178
|
+
await adapter.createSession({
|
|
179
|
+
userId: user.id,
|
|
180
|
+
tokenHash: 'active_session',
|
|
181
|
+
expiresAt: new Date(Date.now() + 86_400_000),
|
|
182
|
+
});
|
|
183
|
+
await adapter.deleteExpiredSessions();
|
|
184
|
+
const expired = await adapter.getSessionByTokenHash('expired_session');
|
|
185
|
+
expect(expired).toBeNull();
|
|
186
|
+
const active = await adapter.getSessionByTokenHash('active_session');
|
|
187
|
+
expect(active).not.toBeNull();
|
|
188
|
+
});
|
|
189
|
+
// --- OAuth state operations ---
|
|
190
|
+
it('should create and consume OAuth state (single-use)', async () => {
|
|
191
|
+
const stateInput = {
|
|
192
|
+
stateHash: 'state_single_use',
|
|
193
|
+
codeVerifier: 'verifier_123',
|
|
194
|
+
provider: 'google',
|
|
195
|
+
expiresAt: new Date(Date.now() + 600_000),
|
|
196
|
+
};
|
|
197
|
+
await adapter.createOAuthState(stateInput);
|
|
198
|
+
const first = await adapter.consumeOAuthState('state_single_use');
|
|
199
|
+
expect(first).not.toBeNull();
|
|
200
|
+
if (first) {
|
|
201
|
+
expect(first.codeVerifier).toBe('verifier_123');
|
|
202
|
+
}
|
|
203
|
+
const second = await adapter.consumeOAuthState('state_single_use');
|
|
204
|
+
expect(second).toBeNull();
|
|
205
|
+
});
|
|
206
|
+
it('should return null for unknown OAuth state', async () => {
|
|
207
|
+
const result = await adapter.consumeOAuthState('unknown_state');
|
|
208
|
+
expect(result).toBeNull();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=adapter-conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-conformance.js","sourceRoot":"","sources":["../../src/test/adapter-conformance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.test.d.ts","sourceRoot":"","sources":["../../src/test/cookies.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { serializeCookie, parseCookie, signCookie, verifyCookie } from '../cookies.js';
|
|
3
|
+
describe('serializeCookie', () => {
|
|
4
|
+
it('should serialize a simple cookie', () => {
|
|
5
|
+
const result = serializeCookie('name', 'value');
|
|
6
|
+
expect(result).toBe('name=value');
|
|
7
|
+
});
|
|
8
|
+
it('should serialize with options', () => {
|
|
9
|
+
const result = serializeCookie('session', 'abc123', {
|
|
10
|
+
maxAge: 3600,
|
|
11
|
+
path: '/',
|
|
12
|
+
secure: true,
|
|
13
|
+
httpOnly: true,
|
|
14
|
+
sameSite: 'lax',
|
|
15
|
+
});
|
|
16
|
+
expect(result).toContain('session=abc123');
|
|
17
|
+
expect(result).toContain('Max-Age=3600');
|
|
18
|
+
expect(result).toContain('Path=/');
|
|
19
|
+
expect(result).toContain('Secure');
|
|
20
|
+
expect(result).toContain('HttpOnly');
|
|
21
|
+
expect(result).toContain('SameSite=lax');
|
|
22
|
+
});
|
|
23
|
+
it('should encode special characters', () => {
|
|
24
|
+
const result = serializeCookie('session id', 'value with spaces');
|
|
25
|
+
expect(result).toContain(encodeURIComponent('session id'));
|
|
26
|
+
expect(result).toContain(encodeURIComponent('value with spaces'));
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('parseCookie', () => {
|
|
30
|
+
it('should parse a simple cookie header', () => {
|
|
31
|
+
const result = parseCookie('name=value');
|
|
32
|
+
expect(result).toEqual({ name: 'value' });
|
|
33
|
+
});
|
|
34
|
+
it('should parse multiple cookies', () => {
|
|
35
|
+
const result = parseCookie('name=value; session=abc123');
|
|
36
|
+
expect(result).toEqual({ name: 'value', session: 'abc123' });
|
|
37
|
+
});
|
|
38
|
+
it('should ignore cookie attributes', () => {
|
|
39
|
+
const result = parseCookie('session=abc123; Path=/; Secure; HttpOnly');
|
|
40
|
+
expect(result).toEqual({ session: 'abc123' });
|
|
41
|
+
});
|
|
42
|
+
it('should trim whitespace', () => {
|
|
43
|
+
const result = parseCookie(' name = value ; session=abc123 ');
|
|
44
|
+
expect(result).toEqual({ name: 'value', session: 'abc123' });
|
|
45
|
+
});
|
|
46
|
+
it('should handle empty header', () => {
|
|
47
|
+
const result = parseCookie('');
|
|
48
|
+
expect(result).toEqual({});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('signCookie and verifyCookie', () => {
|
|
52
|
+
const secret = 'test-secret-that-is-at-least-32-characters-long!!';
|
|
53
|
+
it('should sign and verify a cookie value', async () => {
|
|
54
|
+
const signed = await signCookie('session_token_123', secret);
|
|
55
|
+
expect(signed).toContain('session_token_123.');
|
|
56
|
+
const verified = await verifyCookie(signed, secret);
|
|
57
|
+
expect(verified).toBe('session_token_123');
|
|
58
|
+
});
|
|
59
|
+
it('should reject tampered cookies', async () => {
|
|
60
|
+
const signed = await signCookie('session_token_123', secret);
|
|
61
|
+
// Tamper with the signature
|
|
62
|
+
const tampered = signed.replace(/[^.\n]+$/, 'tampered_signature');
|
|
63
|
+
const verified = await verifyCookie(tampered, secret);
|
|
64
|
+
expect(verified).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
it('should return null for malformed cookies', async () => {
|
|
67
|
+
const verified = await verifyCookie('no-separator', secret);
|
|
68
|
+
expect(verified).toBeNull();
|
|
69
|
+
const verified2 = await verifyCookie('.', secret);
|
|
70
|
+
expect(verified2).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
it('should fail verification with wrong secret', async () => {
|
|
73
|
+
const signed = await signCookie('session_token', secret);
|
|
74
|
+
const verified = await verifyCookie(signed, 'different-secret-value!!!!!');
|
|
75
|
+
expect(verified).toBeNull();
|
|
76
|
+
});
|
|
77
|
+
it('should produce different signatures for different values', async () => {
|
|
78
|
+
const signed1 = await signCookie('token_a', secret);
|
|
79
|
+
const signed2 = await signCookie('token_b', secret);
|
|
80
|
+
expect(signed1).not.toBe(signed2);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=cookies.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.test.js","sourceRoot":"","sources":["../../src/test/cookies.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.test.d.ts","sourceRoot":"","sources":["../../src/test/crypto.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { generateSessionToken, hashToken, generateCodeVerifier, generateCodeChallenge, constantTimeEqual, } from '../crypto.js';
|
|
3
|
+
describe('generateSessionToken', () => {
|
|
4
|
+
it('should generate a base64url string', () => {
|
|
5
|
+
const token = generateSessionToken();
|
|
6
|
+
expect(token).toBeTruthy();
|
|
7
|
+
expect(typeof token).toBe('string');
|
|
8
|
+
// base64url should only contain alphanumeric, hyphen, underscore
|
|
9
|
+
expect(/^[A-Za-z0-9\-_]+$/.test(token)).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
it('should generate 256-bit tokens (43 chars base64url without padding)', () => {
|
|
12
|
+
const token = generateSessionToken();
|
|
13
|
+
// 32 bytes → 43 base64url chars (without padding)
|
|
14
|
+
expect(token.length).toBe(43);
|
|
15
|
+
});
|
|
16
|
+
it('should generate unique tokens on each call', () => {
|
|
17
|
+
const tokens = new Set(Array.from({ length: 100 }, () => generateSessionToken()));
|
|
18
|
+
expect(tokens.size).toBe(100);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('hashToken', () => {
|
|
22
|
+
it('should produce a hex string', async () => {
|
|
23
|
+
const hash = await hashToken('test-token');
|
|
24
|
+
expect(hash).toBeTruthy();
|
|
25
|
+
expect(typeof hash).toBe('string');
|
|
26
|
+
// hex string should be 64 chars (SHA-256)
|
|
27
|
+
expect(hash.length).toBe(64);
|
|
28
|
+
expect(/^[0-9a-f]+$/.test(hash)).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it('should produce deterministic hashes', async () => {
|
|
31
|
+
const hash1 = await hashToken('same-token');
|
|
32
|
+
const hash2 = await hashToken('same-token');
|
|
33
|
+
expect(hash1).toBe(hash2);
|
|
34
|
+
});
|
|
35
|
+
it('should produce different hashes for different inputs', async () => {
|
|
36
|
+
const hash1 = await hashToken('token-a');
|
|
37
|
+
const hash2 = await hashToken('token-b');
|
|
38
|
+
expect(hash1).not.toBe(hash2);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('generateCodeVerifier', () => {
|
|
42
|
+
it('should generate a base64url string', () => {
|
|
43
|
+
const verifier = generateCodeVerifier();
|
|
44
|
+
expect(verifier).toBeTruthy();
|
|
45
|
+
expect(/^[A-Za-z0-9\-_]+$/.test(verifier)).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
it('should generate unique verifiers', () => {
|
|
48
|
+
const verifiers = new Set(Array.from({ length: 100 }, () => generateCodeVerifier()));
|
|
49
|
+
expect(verifiers.size).toBe(100);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('generateCodeChallenge', () => {
|
|
53
|
+
it('should produce a base64url string from a verifier', async () => {
|
|
54
|
+
const verifier = generateCodeVerifier();
|
|
55
|
+
const challenge = await generateCodeChallenge(verifier);
|
|
56
|
+
expect(challenge).toBeTruthy();
|
|
57
|
+
expect(/^[A-Za-z0-9\-_]+$/.test(challenge)).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
it('should produce deterministic challenges for same verifier', async () => {
|
|
60
|
+
const verifier = 'same-verifier-value';
|
|
61
|
+
const challenge1 = await generateCodeChallenge(verifier);
|
|
62
|
+
const challenge2 = await generateCodeChallenge(verifier);
|
|
63
|
+
expect(challenge1).toBe(challenge2);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('constantTimeEqual', () => {
|
|
67
|
+
it('should return true for equal strings', () => {
|
|
68
|
+
expect(constantTimeEqual('hello', 'hello')).toBe(true);
|
|
69
|
+
expect(constantTimeEqual('', '')).toBe(true);
|
|
70
|
+
expect(constantTimeEqual('a', 'a')).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
it('should return false for different strings', () => {
|
|
73
|
+
expect(constantTimeEqual('hello', 'world')).toBe(false);
|
|
74
|
+
expect(constantTimeEqual('a', 'b')).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
it('should return false for different length strings', () => {
|
|
77
|
+
expect(constantTimeEqual('abc', 'abcd')).toBe(false);
|
|
78
|
+
expect(constantTimeEqual('', 'a')).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
it('should return false for similar strings', () => {
|
|
81
|
+
expect(constantTimeEqual('token_a', 'token_b')).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=crypto.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.test.js","sourceRoot":"","sources":["../../src/test/crypto.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.test.d.ts","sourceRoot":"","sources":["../../src/test/encryption.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { encrypt, decrypt } from '../encryption.js';
|
|
3
|
+
const SECRET = 'test-encryption-secret-that-is-long-enough-for-testing!';
|
|
4
|
+
describe('encrypt and decrypt', () => {
|
|
5
|
+
it('should encrypt and decrypt a string', async () => {
|
|
6
|
+
const original = 'hello world';
|
|
7
|
+
const encoded = await encrypt(original, SECRET);
|
|
8
|
+
expect(encoded).toBeTruthy();
|
|
9
|
+
expect(encoded).not.toBe(original);
|
|
10
|
+
const decoded = await decrypt(encoded, SECRET);
|
|
11
|
+
expect(decoded).toBe(original);
|
|
12
|
+
});
|
|
13
|
+
it('should produce different outputs for the same input (salt + iv)', async () => {
|
|
14
|
+
const out1 = await encrypt('same text', SECRET);
|
|
15
|
+
const out2 = await encrypt('same text', SECRET);
|
|
16
|
+
expect(out1).not.toBe(out2);
|
|
17
|
+
});
|
|
18
|
+
it('should fail decryption with wrong secret', async () => {
|
|
19
|
+
const encoded = await encrypt('secret data', SECRET);
|
|
20
|
+
await expect(decrypt(encoded, 'wrong-secret-that-is-completely-different!!')).rejects.toThrow();
|
|
21
|
+
});
|
|
22
|
+
it('should handle empty string', async () => {
|
|
23
|
+
const encoded = await encrypt('', SECRET);
|
|
24
|
+
const decoded = await decrypt(encoded, SECRET);
|
|
25
|
+
expect(decoded).toBe('');
|
|
26
|
+
});
|
|
27
|
+
it('should handle long strings', async () => {
|
|
28
|
+
const long = 'a'.repeat(10_000);
|
|
29
|
+
const encoded = await encrypt(long, SECRET);
|
|
30
|
+
const decoded = await decrypt(encoded, SECRET);
|
|
31
|
+
expect(decoded).toBe(long);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=encryption.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.test.js","sourceRoot":"","sources":["../../src/test/encryption.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAEnD,MAAM,MAAM,GAAG,yDAAyD,CAAA;AAExE,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,QAAQ,GAAG,aAAa,CAAA;QAC9B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAC/C,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAA;QAC5B,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAElC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAChC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QAC/C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;QACpD,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,6CAA6C,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;IACjG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QACzC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC1B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC/B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { User, Account, Session, OAuthState, CreateUserInput, CreateAccountInput, CreateSessionInput, CreateOAuthStateInput } from '../types.js';
|
|
2
|
+
export declare function resetIds(): void;
|
|
3
|
+
export declare function createUser(overrides?: Partial<CreateUserInput>): CreateUserInput;
|
|
4
|
+
export declare function createAccount(userId: string, overrides?: Partial<CreateAccountInput>): CreateAccountInput;
|
|
5
|
+
export declare function createSession(userId: string, tokenHash: string, overrides?: Partial<CreateSessionInput>): CreateSessionInput;
|
|
6
|
+
export declare function createOAuthState(overrides?: Partial<CreateOAuthStateInput>): CreateOAuthStateInput;
|
|
7
|
+
export declare function buildUser(overrides?: Partial<User>): User;
|
|
8
|
+
export declare function buildAccount(userId: string, overrides?: Partial<Account>): Account;
|
|
9
|
+
export declare function buildSession(userId: string, overrides?: Partial<Session>): Session;
|
|
10
|
+
export declare function buildOAuthState(overrides?: Partial<OAuthState>): OAuthState;
|
|
11
|
+
//# sourceMappingURL=factories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../src/test/factories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,IAAI,EACJ,OAAO,EACP,OAAO,EACP,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,aAAa,CAAA;AAUpB,wBAAgB,QAAQ,IAAI,IAAI,CAG/B;AAED,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAQhF;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACtC,kBAAkB,CAapB;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACtC,kBAAkB,CASpB;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,GACzC,qBAAqB,CAUvB;AAED,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAWzD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAgBlF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAYlF;AAED,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAY3E"}
|