@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.
Files changed (134) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapter.d.ts +20 -0
  3. package/dist/adapter.d.ts.map +1 -0
  4. package/dist/adapter.js +2 -0
  5. package/dist/adapter.js.map +1 -0
  6. package/dist/additional-fields.d.ts +31 -0
  7. package/dist/additional-fields.d.ts.map +1 -0
  8. package/dist/additional-fields.js +2 -0
  9. package/dist/additional-fields.js.map +1 -0
  10. package/dist/auth.d.ts +26 -0
  11. package/dist/auth.d.ts.map +1 -0
  12. package/dist/auth.js +280 -0
  13. package/dist/auth.js.map +1 -0
  14. package/dist/config.d.ts +55 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +2 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/cookies.d.ts +29 -0
  19. package/dist/cookies.d.ts.map +1 -0
  20. package/dist/cookies.js +98 -0
  21. package/dist/cookies.js.map +1 -0
  22. package/dist/crypto.d.ts +23 -0
  23. package/dist/crypto.d.ts.map +1 -0
  24. package/dist/crypto.js +57 -0
  25. package/dist/crypto.js.map +1 -0
  26. package/dist/csrf.d.ts +6 -0
  27. package/dist/csrf.d.ts.map +1 -0
  28. package/dist/csrf.js +24 -0
  29. package/dist/csrf.js.map +1 -0
  30. package/dist/encryption.d.ts +10 -0
  31. package/dist/encryption.d.ts.map +1 -0
  32. package/dist/encryption.js +61 -0
  33. package/dist/encryption.js.map +1 -0
  34. package/dist/errors.d.ts +29 -0
  35. package/dist/errors.d.ts.map +1 -0
  36. package/dist/errors.js +57 -0
  37. package/dist/errors.js.map +1 -0
  38. package/dist/hooks.d.ts +45 -0
  39. package/dist/hooks.d.ts.map +1 -0
  40. package/dist/hooks.js +2 -0
  41. package/dist/hooks.js.map +1 -0
  42. package/dist/http.d.ts +23 -0
  43. package/dist/http.d.ts.map +1 -0
  44. package/dist/http.js +126 -0
  45. package/dist/http.js.map +1 -0
  46. package/dist/index.d.ts +23 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +53 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/provider.d.ts +19 -0
  51. package/dist/provider.d.ts.map +1 -0
  52. package/dist/provider.js +2 -0
  53. package/dist/provider.js.map +1 -0
  54. package/dist/rate-limiter.d.ts +33 -0
  55. package/dist/rate-limiter.d.ts.map +1 -0
  56. package/dist/rate-limiter.js +45 -0
  57. package/dist/rate-limiter.js.map +1 -0
  58. package/dist/test/adapter-conformance.d.ts +13 -0
  59. package/dist/test/adapter-conformance.d.ts.map +1 -0
  60. package/dist/test/adapter-conformance.js +212 -0
  61. package/dist/test/adapter-conformance.js.map +1 -0
  62. package/dist/test/cookies.test.d.ts +2 -0
  63. package/dist/test/cookies.test.d.ts.map +1 -0
  64. package/dist/test/cookies.test.js +83 -0
  65. package/dist/test/cookies.test.js.map +1 -0
  66. package/dist/test/crypto.test.d.ts +2 -0
  67. package/dist/test/crypto.test.d.ts.map +1 -0
  68. package/dist/test/crypto.test.js +84 -0
  69. package/dist/test/crypto.test.js.map +1 -0
  70. package/dist/test/encryption.test.d.ts +2 -0
  71. package/dist/test/encryption.test.d.ts.map +1 -0
  72. package/dist/test/encryption.test.js +34 -0
  73. package/dist/test/encryption.test.js.map +1 -0
  74. package/dist/test/factories.d.ts +11 -0
  75. package/dist/test/factories.d.ts.map +1 -0
  76. package/dist/test/factories.js +110 -0
  77. package/dist/test/factories.js.map +1 -0
  78. package/dist/test/index.d.ts +6 -0
  79. package/dist/test/index.d.ts.map +1 -0
  80. package/dist/test/index.js +4 -0
  81. package/dist/test/index.js.map +1 -0
  82. package/dist/test/mock-provider.d.ts +34 -0
  83. package/dist/test/mock-provider.d.ts.map +1 -0
  84. package/dist/test/mock-provider.js +99 -0
  85. package/dist/test/mock-provider.js.map +1 -0
  86. package/dist/test/rate-limiter.test.d.ts +2 -0
  87. package/dist/test/rate-limiter.test.d.ts.map +1 -0
  88. package/dist/test/rate-limiter.test.js +38 -0
  89. package/dist/test/rate-limiter.test.js.map +1 -0
  90. package/dist/test/url.test.d 2.ts +2 -0
  91. package/dist/test/url.test.d.ts +2 -0
  92. package/dist/test/url.test.d.ts 2.map +1 -0
  93. package/dist/test/url.test.d.ts.map +1 -0
  94. package/dist/test/url.test.js +40 -0
  95. package/dist/test/url.test.js 2.map +1 -0
  96. package/dist/test/url.test.js.map +1 -0
  97. package/dist/types.d.ts +109 -0
  98. package/dist/types.d.ts.map +1 -0
  99. package/dist/types.js +2 -0
  100. package/dist/types.js.map +1 -0
  101. package/dist/url.d.ts +11 -0
  102. package/dist/url.d.ts.map +1 -0
  103. package/dist/url.js +35 -0
  104. package/dist/url.js.map +1 -0
  105. package/package.json +27 -0
  106. package/src/adapter.ts +39 -0
  107. package/src/additional-fields.ts +53 -0
  108. package/src/auth.ts +355 -0
  109. package/src/config.ts +62 -0
  110. package/src/cookies.ts +123 -0
  111. package/src/crypto.ts +62 -0
  112. package/src/csrf.ts +27 -0
  113. package/src/encryption.ts +88 -0
  114. package/src/errors.ts +65 -0
  115. package/src/hooks.ts +54 -0
  116. package/src/http.ts +192 -0
  117. package/src/index.ts +161 -0
  118. package/src/provider.ts +21 -0
  119. package/src/rate-limiter.ts +64 -0
  120. package/src/test/adapter-conformance.ts +267 -0
  121. package/src/test/cookies.test.ts +99 -0
  122. package/src/test/crypto.test.ts +103 -0
  123. package/src/test/encryption.test.ts +40 -0
  124. package/src/test/factories.ts +139 -0
  125. package/src/test/index.ts +17 -0
  126. package/src/test/mock-provider.ts +130 -0
  127. package/src/test/rate-limiter.test.ts +49 -0
  128. package/src/test/url.test.ts +48 -0
  129. package/src/types.ts +122 -0
  130. package/src/url.ts +35 -0
  131. package/tsconfig 2.tsbuildinfo +1 -0
  132. package/tsconfig.json +11 -0
  133. package/tsconfig.tsbuildinfo +1 -0
  134. package/vitest.config.ts +14 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Generate a cryptographically secure random session token (256-bit).
3
+ * Returns a base64url-encoded string.
4
+ */
5
+ export declare function generateSessionToken(): string;
6
+ /**
7
+ * Hash a session token using SHA-256.
8
+ * Returns a hex-encoded string for database storage.
9
+ */
10
+ export declare function hashToken(token: string): Promise<string>;
11
+ /**
12
+ * Generate a PKCE code verifier (64 random bytes, base64url encoded).
13
+ */
14
+ export declare function generateCodeVerifier(): string;
15
+ /**
16
+ * Generate an S256 PKCE code challenge from a code verifier.
17
+ */
18
+ export declare function generateCodeChallenge(verifier: string): Promise<string>;
19
+ /**
20
+ * Compare two strings in constant time to prevent timing attacks.
21
+ */
22
+ export declare function constantTimeEqual(a: string, b: string): boolean;
23
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG9D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAS/D"}
package/dist/crypto.js ADDED
@@ -0,0 +1,57 @@
1
+ function base64url(bytes) {
2
+ return btoa(String.fromCharCode(...bytes))
3
+ .replace(/\+/g, '-')
4
+ .replace(/\//g, '_')
5
+ .replace(/=+$/, '');
6
+ }
7
+ function hex(bytes) {
8
+ return Array.from(bytes)
9
+ .map((b) => b.toString(16).padStart(2, '0'))
10
+ .join('');
11
+ }
12
+ /**
13
+ * Generate a cryptographically secure random session token (256-bit).
14
+ * Returns a base64url-encoded string.
15
+ */
16
+ export function generateSessionToken() {
17
+ const bytes = new Uint8Array(32);
18
+ crypto.getRandomValues(bytes);
19
+ return base64url(bytes);
20
+ }
21
+ /**
22
+ * Hash a session token using SHA-256.
23
+ * Returns a hex-encoded string for database storage.
24
+ */
25
+ export async function hashToken(token) {
26
+ const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(token));
27
+ return hex(new Uint8Array(hash));
28
+ }
29
+ /**
30
+ * Generate a PKCE code verifier (64 random bytes, base64url encoded).
31
+ */
32
+ export function generateCodeVerifier() {
33
+ const bytes = new Uint8Array(64);
34
+ crypto.getRandomValues(bytes);
35
+ return base64url(bytes);
36
+ }
37
+ /**
38
+ * Generate an S256 PKCE code challenge from a code verifier.
39
+ */
40
+ export async function generateCodeChallenge(verifier) {
41
+ const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
42
+ return base64url(new Uint8Array(hash));
43
+ }
44
+ /**
45
+ * Compare two strings in constant time to prevent timing attacks.
46
+ */
47
+ export function constantTimeEqual(a, b) {
48
+ if (a.length !== b.length) {
49
+ return false;
50
+ }
51
+ let result = 0;
52
+ for (let i = 0; i < a.length; i++) {
53
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
54
+ }
55
+ return result === 0;
56
+ }
57
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,SAAS,SAAS,CAAC,KAAiB;IAClC,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,CAAC;SACvC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AACvB,CAAC;AAED,SAAS,GAAG,CAAC,KAAiB;IAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IAChC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;IAC7B,OAAO,SAAS,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAa;IAC3C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;IACnF,OAAO,GAAG,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IAChC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;IAC7B,OAAO,SAAS,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAgB;IAC1D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IACtF,OAAO,SAAS,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAS,EAAE,CAAS;IACpD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IAC7C,CAAC;IACD,OAAO,MAAM,KAAK,CAAC,CAAA;AACrB,CAAC"}
package/dist/csrf.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Validate that a request's Origin or Referer header matches a trusted origin.
3
+ * This is a basic CSRF protection for POST endpoints (logout, account linking).
4
+ */
5
+ export declare function validateCsrf(request: Request, trustedOrigins: string[]): boolean;
6
+ //# sourceMappingURL=csrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAoBhF"}
package/dist/csrf.js ADDED
@@ -0,0 +1,24 @@
1
+ import { isTrustedOrigin } from './url.js';
2
+ /**
3
+ * Validate that a request's Origin or Referer header matches a trusted origin.
4
+ * This is a basic CSRF protection for POST endpoints (logout, account linking).
5
+ */
6
+ export function validateCsrf(request, trustedOrigins) {
7
+ // Check Origin header first (more reliable)
8
+ const origin = request.headers.get('origin');
9
+ if (origin && isTrustedOrigin(origin, trustedOrigins)) {
10
+ return true;
11
+ }
12
+ // Fall back to Referer header
13
+ const referer = request.headers.get('referer');
14
+ if (referer && isTrustedOrigin(referer, trustedOrigins)) {
15
+ return true;
16
+ }
17
+ // If no Origin or Referer header, allow through (e.g., server-to-server)
18
+ // In production, this should be handled by SameSite cookies
19
+ if (!origin && !referer) {
20
+ return true;
21
+ }
22
+ return false;
23
+ }
24
+ //# sourceMappingURL=csrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAgB,EAAE,cAAwB;IACrE,4CAA4C;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC5C,IAAI,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,8BAA8B;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC9C,IAAI,OAAO,IAAI,eAAe,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC;QACxD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,yEAAyE;IACzE,4DAA4D;IAC5D,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACxB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Encrypt a plaintext string using AES-256-GCM.
3
+ * Returns a base64url-encoded string containing salt + iv + ciphertext.
4
+ */
5
+ export declare function encrypt(plaintext: string, secret: string): Promise<string>;
6
+ /**
7
+ * Decrypt a base64url-encoded string that was encrypted with encrypt().
8
+ */
9
+ export declare function decrypt(encoded: string, secret: string): Promise<string>;
10
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AA+BA;;;GAGG;AACH,wBAAsB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBhF;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW9E"}
@@ -0,0 +1,61 @@
1
+ const ALGORITHM = 'AES-GCM';
2
+ const KEY_LENGTH = 256;
3
+ const IV_LENGTH = 12;
4
+ /**
5
+ * Derive an AES-256-GCM key from a secret using PBKDF2.
6
+ * This allows using any string as the encryption key.
7
+ */
8
+ async function deriveKey(secret, salt) {
9
+ const keyMaterial = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), 'PBKDF2', false, ['deriveKey']);
10
+ return crypto.subtle.deriveKey({
11
+ name: 'PBKDF2',
12
+ salt,
13
+ iterations: 100_000,
14
+ hash: 'SHA-256',
15
+ }, keyMaterial, { name: ALGORITHM, length: KEY_LENGTH }, false, ['encrypt', 'decrypt']);
16
+ }
17
+ /**
18
+ * Encrypt a plaintext string using AES-256-GCM.
19
+ * Returns a base64url-encoded string containing salt + iv + ciphertext.
20
+ */
21
+ export async function encrypt(plaintext, secret) {
22
+ const salt = crypto.getRandomValues(new Uint8Array(16));
23
+ const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
24
+ const key = await deriveKey(secret, salt);
25
+ const ciphertext = await crypto.subtle.encrypt({ name: ALGORITHM, iv }, key, new TextEncoder().encode(plaintext));
26
+ // Combine salt + iv + ciphertext into a single base64url string
27
+ const combined = new Uint8Array(salt.length + iv.length + ciphertext.byteLength);
28
+ combined.set(salt, 0);
29
+ combined.set(iv, salt.length);
30
+ combined.set(new Uint8Array(ciphertext), salt.length + iv.length);
31
+ return base64url(combined);
32
+ }
33
+ /**
34
+ * Decrypt a base64url-encoded string that was encrypted with encrypt().
35
+ */
36
+ export async function decrypt(encoded, secret) {
37
+ const combined = base64urlDecode(encoded);
38
+ const salt = combined.slice(0, 16);
39
+ const iv = combined.slice(16, 16 + IV_LENGTH);
40
+ const ciphertext = combined.slice(16 + IV_LENGTH);
41
+ const key = await deriveKey(secret, salt);
42
+ const plaintext = await crypto.subtle.decrypt({ name: ALGORITHM, iv }, key, ciphertext);
43
+ return new TextDecoder().decode(plaintext);
44
+ }
45
+ function base64url(bytes) {
46
+ return btoa(String.fromCharCode(...bytes))
47
+ .replace(/\+/g, '-')
48
+ .replace(/\//g, '_')
49
+ .replace(/=+$/, '');
50
+ }
51
+ function base64urlDecode(str) {
52
+ const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
53
+ const padding = base64.length % 4 === 0 ? '' : '='.repeat(4 - (base64.length % 4));
54
+ const binary = atob(base64 + padding);
55
+ const bytes = new Uint8Array(binary.length);
56
+ for (let i = 0; i < binary.length; i++) {
57
+ bytes[i] = binary.charCodeAt(i);
58
+ }
59
+ return bytes;
60
+ }
61
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export declare class AuthError extends Error {
2
+ readonly code: string;
3
+ constructor(code: string, message: string);
4
+ }
5
+ export declare class OAuthCallbackError extends AuthError {
6
+ constructor(message: string, code?: string);
7
+ }
8
+ export declare class InvalidStateError extends AuthError {
9
+ constructor(message?: string);
10
+ }
11
+ export declare class ProviderProfileError extends AuthError {
12
+ constructor(message?: string);
13
+ }
14
+ export declare class ProviderUnreachableError extends AuthError {
15
+ constructor(message?: string);
16
+ }
17
+ export declare class AccountLinkingError extends AuthError {
18
+ constructor(message: string, code?: string);
19
+ }
20
+ export declare class SessionExpiredError extends AuthError {
21
+ constructor(message?: string);
22
+ }
23
+ export declare class UnauthorizedError extends AuthError {
24
+ constructor(message?: string);
25
+ }
26
+ export declare class ForbiddenCallbackURLError extends AuthError {
27
+ constructor(message?: string);
28
+ }
29
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAgB,IAAI,EAAE,MAAM,CAAA;gBAEhB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,EAAE,MAAM,EAAE,IAAI,SAA0B;CAI5D;AAED,qBAAa,iBAAkB,SAAQ,SAAS;gBAClC,OAAO,SAAqD;CAIzE;AAED,qBAAa,oBAAqB,SAAQ,SAAS;gBACrC,OAAO,SAAqC;CAIzD;AAED,qBAAa,wBAAyB,SAAQ,SAAS;gBACzC,OAAO,SAAyC;CAI7D;AAED,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,EAAE,MAAM,EAAE,IAAI,SAA2B;CAI7D;AAED,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,SAAwB;CAI5C;AAED,qBAAa,iBAAkB,SAAQ,SAAS;gBAClC,OAAO,SAA4B;CAIhD;AAED,qBAAa,yBAA0B,SAAQ,SAAS;gBAC1C,OAAO,SAA2C;CAI/D"}
package/dist/errors.js ADDED
@@ -0,0 +1,57 @@
1
+ export class AuthError extends Error {
2
+ code;
3
+ constructor(code, message) {
4
+ super(message);
5
+ this.name = 'AuthError';
6
+ this.code = code;
7
+ }
8
+ }
9
+ export class OAuthCallbackError extends AuthError {
10
+ constructor(message, code = 'OAUTH_CALLBACK_FAILED') {
11
+ super(code, message);
12
+ this.name = 'OAuthCallbackError';
13
+ }
14
+ }
15
+ export class InvalidStateError extends AuthError {
16
+ constructor(message = 'OAuth state is invalid, expired, or already used') {
17
+ super('INVALID_STATE', message);
18
+ this.name = 'InvalidStateError';
19
+ }
20
+ }
21
+ export class ProviderProfileError extends AuthError {
22
+ constructor(message = 'Failed to fetch provider profile') {
23
+ super('PROVIDER_PROFILE_FAILED', message);
24
+ this.name = 'ProviderProfileError';
25
+ }
26
+ }
27
+ export class ProviderUnreachableError extends AuthError {
28
+ constructor(message = 'Provider is unreachable or timed out') {
29
+ super('PROVIDER_UNREACHABLE', message);
30
+ this.name = 'ProviderUnreachableError';
31
+ }
32
+ }
33
+ export class AccountLinkingError extends AuthError {
34
+ constructor(message, code = 'ACCOUNT_LINKING_FAILED') {
35
+ super(code, message);
36
+ this.name = 'AccountLinkingError';
37
+ }
38
+ }
39
+ export class SessionExpiredError extends AuthError {
40
+ constructor(message = 'Session has expired') {
41
+ super('SESSION_EXPIRED', message);
42
+ this.name = 'SessionExpiredError';
43
+ }
44
+ }
45
+ export class UnauthorizedError extends AuthError {
46
+ constructor(message = 'Authentication required') {
47
+ super('UNAUTHORIZED', message);
48
+ this.name = 'UnauthorizedError';
49
+ }
50
+ }
51
+ export class ForbiddenCallbackURLError extends AuthError {
52
+ constructor(message = 'Callback URL is not in trusted origins') {
53
+ super('INVALID_CALLBACK_URL', message);
54
+ this.name = 'ForbiddenCallbackURLError';
55
+ }
56
+ }
57
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClB,IAAI,CAAQ;IAE5B,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,SAAS;IAC/C,YAAY,OAAe,EAAE,IAAI,GAAG,uBAAuB;QACzD,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACpB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;IAClC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IAC9C,YAAY,OAAO,GAAG,kDAAkD;QACtE,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;QAC/B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;IACjC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IACjD,YAAY,OAAO,GAAG,kCAAkC;QACtD,KAAK,CAAC,yBAAyB,EAAE,OAAO,CAAC,CAAA;QACzC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;IACpC,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,SAAS;IACrD,YAAY,OAAO,GAAG,sCAAsC;QAC1D,KAAK,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAA;IACxC,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,YAAY,OAAe,EAAE,IAAI,GAAG,wBAAwB;QAC1D,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACpB,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,YAAY,OAAO,GAAG,qBAAqB;QACzC,KAAK,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAA;QACjC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IAC9C,YAAY,OAAO,GAAG,yBAAyB;QAC7C,KAAK,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;IACjC,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,SAAS;IACtD,YAAY,OAAO,GAAG,wCAAwC;QAC5D,KAAK,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAA;IACzC,CAAC;CACF"}
@@ -0,0 +1,45 @@
1
+ import type { User, Account, Session, ProviderProfile } from './types.js';
2
+ import type { AuthAdapter } from './adapter.js';
3
+ export interface HookContext {
4
+ adapter: AuthAdapter;
5
+ request?: Request;
6
+ }
7
+ export interface BeforeSignInCtx extends HookContext {
8
+ profile: ProviderProfile;
9
+ }
10
+ export interface AfterSignInCtx extends HookContext {
11
+ session: Session;
12
+ user: User;
13
+ profile: ProviderProfile;
14
+ }
15
+ export interface OnUserCreatedCtx extends HookContext {
16
+ user: User;
17
+ }
18
+ export interface OnAccountLinkedCtx extends HookContext {
19
+ account: Account;
20
+ user: User;
21
+ }
22
+ export interface BeforeSessionCreatedCtx extends HookContext {
23
+ user: User;
24
+ }
25
+ export interface AfterSessionCreatedCtx extends HookContext {
26
+ session: Session;
27
+ user: User;
28
+ }
29
+ export interface BeforeLogoutCtx extends HookContext {
30
+ session: Session;
31
+ }
32
+ export interface AfterLogoutCtx extends HookContext {
33
+ session: Session;
34
+ }
35
+ export interface HooksConfig {
36
+ beforeSignIn?: (ctx: BeforeSignInCtx) => Promise<void>;
37
+ afterSignIn?: (ctx: AfterSignInCtx) => Promise<void>;
38
+ onUserCreated?: (ctx: OnUserCreatedCtx) => Promise<void>;
39
+ onAccountLinked?: (ctx: OnAccountLinkedCtx) => Promise<void>;
40
+ beforeSessionCreated?: (ctx: BeforeSessionCreatedCtx) => Promise<void>;
41
+ afterSessionCreated?: (ctx: AfterSessionCreatedCtx) => Promise<void>;
42
+ beforeLogout?: (ctx: BeforeLogoutCtx) => Promise<void>;
43
+ afterLogout?: (ctx: AfterLogoutCtx) => Promise<void>;
44
+ }
45
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,OAAO,EAAE,eAAe,CAAA;CACzB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,eAAe,CAAA;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,IAAI,EAAE,IAAI,CAAA;CACX;AAED,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,IAAI,CAAA;CACX;AAED,MAAM,WAAW,uBAAwB,SAAQ,WAAW;IAC1D,IAAI,EAAE,IAAI,CAAA;CACX;AAED,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,IAAI,CAAA;CACX;AAED,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxD,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACtE,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACrD"}
package/dist/hooks.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":""}
package/dist/http.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { TokenSet, ProviderProfile } from './types.js';
2
+ export interface ProviderHttpOptions {
3
+ timeout?: number;
4
+ retries?: number;
5
+ retryDelay?: number;
6
+ }
7
+ /**
8
+ * Exchange an authorization code for tokens at the provider's token endpoint.
9
+ * Uses POST with application/x-www-form-urlencoded body.
10
+ */
11
+ export declare function exchangeCode(tokenEndpoint: string, params: {
12
+ clientId: string;
13
+ clientSecret: string;
14
+ code: string;
15
+ codeVerifier: string;
16
+ redirectUri: string;
17
+ }, options?: ProviderHttpOptions): Promise<TokenSet>;
18
+ /**
19
+ * Fetch a provider's user profile from the userinfo endpoint.
20
+ * The access token is sent as a Bearer token in the Authorization header.
21
+ */
22
+ export declare function fetchProfile(userinfoEndpoint: string, accessToken: string, options?: ProviderHttpOptions): Promise<ProviderProfile>;
23
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAG3D,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AA2DD;;;GAGG;AACH,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE;IACN,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACpB,EACD,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAwDnB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,eAAe,CAAC,CA6C1B"}
package/dist/http.js ADDED
@@ -0,0 +1,126 @@
1
+ import { ProviderUnreachableError, ProviderProfileError } from './errors.js';
2
+ const DEFAULT_TIMEOUT = 10_000; // 10 seconds
3
+ const DEFAULT_RETRIES = 0;
4
+ const DEFAULT_RETRY_DELAY = 1_000; // 1 second
5
+ async function fetchWithTimeout(url, options) {
6
+ const timeout = options.timeout ?? DEFAULT_TIMEOUT;
7
+ const controller = new AbortController();
8
+ const timeoutId = setTimeout(() => {
9
+ controller.abort();
10
+ }, timeout);
11
+ try {
12
+ const response = await fetch(url, {
13
+ ...options,
14
+ signal: controller.signal,
15
+ });
16
+ return response;
17
+ }
18
+ finally {
19
+ clearTimeout(timeoutId);
20
+ }
21
+ }
22
+ function isNetworkError(error) {
23
+ return (error instanceof TypeError || (error instanceof DOMException && error.name === 'AbortError'));
24
+ }
25
+ function sleep(ms) {
26
+ return new Promise((resolve) => {
27
+ setTimeout(resolve, ms);
28
+ });
29
+ }
30
+ /**
31
+ * Exchange an authorization code for tokens at the provider's token endpoint.
32
+ * Uses POST with application/x-www-form-urlencoded body.
33
+ */
34
+ export async function exchangeCode(tokenEndpoint, params, options) {
35
+ const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
36
+ const retries = options?.retries ?? DEFAULT_RETRIES;
37
+ const retryDelay = options?.retryDelay ?? DEFAULT_RETRY_DELAY;
38
+ const body = new URLSearchParams({
39
+ client_id: params.clientId,
40
+ client_secret: params.clientSecret,
41
+ code: params.code,
42
+ code_verifier: params.codeVerifier,
43
+ redirect_uri: params.redirectUri,
44
+ grant_type: 'authorization_code',
45
+ });
46
+ let lastError;
47
+ for (let attempt = 0; attempt <= retries; attempt++) {
48
+ try {
49
+ const response = await fetchWithTimeout(tokenEndpoint, {
50
+ method: 'POST',
51
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
52
+ body,
53
+ timeout,
54
+ });
55
+ if (response.ok) {
56
+ const data = (await response.json());
57
+ return {
58
+ accessToken: data.access_token ?? '',
59
+ refreshToken: data.refresh_token,
60
+ idToken: data.id_token,
61
+ scope: data.scope,
62
+ tokenType: data.token_type,
63
+ expiresAt: data.expires_in,
64
+ };
65
+ }
66
+ // Non-retryable HTTP error
67
+ const errorBody = await response.text().catch(() => 'unknown error');
68
+ throw new ProviderUnreachableError(`Token endpoint returned ${String(response.status)}: ${errorBody}`);
69
+ }
70
+ catch (error) {
71
+ lastError = error;
72
+ // Only retry on network errors, not 4xx/5xx responses
73
+ if (isNetworkError(error) && attempt < retries) {
74
+ await sleep(retryDelay);
75
+ continue;
76
+ }
77
+ throw error;
78
+ }
79
+ }
80
+ throw lastError;
81
+ }
82
+ /**
83
+ * Fetch a provider's user profile from the userinfo endpoint.
84
+ * The access token is sent as a Bearer token in the Authorization header.
85
+ */
86
+ export async function fetchProfile(userinfoEndpoint, accessToken, options) {
87
+ const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
88
+ const retries = options?.retries ?? DEFAULT_RETRIES;
89
+ const retryDelay = options?.retryDelay ?? DEFAULT_RETRY_DELAY;
90
+ let lastError;
91
+ for (let attempt = 0; attempt <= retries; attempt++) {
92
+ try {
93
+ const response = await fetchWithTimeout(userinfoEndpoint, {
94
+ method: 'GET',
95
+ headers: {
96
+ Authorization: `Bearer ${accessToken}`,
97
+ Accept: 'application/json',
98
+ },
99
+ timeout,
100
+ });
101
+ if (response.ok) {
102
+ const data = (await response.json());
103
+ return {
104
+ provider: data.provider ?? '',
105
+ providerAccountId: data.sub ?? data.id ?? '',
106
+ email: data.email,
107
+ emailVerified: data.email_verified,
108
+ name: data.name,
109
+ image: data.picture,
110
+ raw: data,
111
+ };
112
+ }
113
+ throw new ProviderProfileError(`Userinfo endpoint returned ${String(response.status)}`);
114
+ }
115
+ catch (error) {
116
+ lastError = error;
117
+ if (isNetworkError(error) && attempt < retries) {
118
+ await sleep(retryDelay);
119
+ continue;
120
+ }
121
+ throw error;
122
+ }
123
+ }
124
+ throw lastError;
125
+ }
126
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAQ5E,MAAM,eAAe,GAAG,MAAM,CAAA,CAAC,aAAa;AAC5C,MAAM,eAAe,GAAG,CAAC,CAAA;AACzB,MAAM,mBAAmB,GAAG,KAAK,CAAA,CAAC,WAAW;AAsB7C,KAAK,UAAU,gBAAgB,CAC7B,GAAW,EACX,OAA2C;IAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,eAAe,CAAA;IAClD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,UAAU,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC,EAAE,OAAO,CAAC,CAAA;IAEX,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,GAAG,OAAO;YACV,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAA;QACF,OAAO,QAAQ,CAAA;IACjB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,CACL,KAAK,YAAY,SAAS,IAAI,CAAC,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAC7F,CAAA;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,aAAqB,EACrB,MAMC,EACD,OAA6B;IAE7B,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,eAAe,CAAA;IACnD,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,eAAe,CAAA;IACnD,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,mBAAmB,CAAA;IAE7D,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,aAAa,EAAE,MAAM,CAAC,YAAY;QAClC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,aAAa,EAAE,MAAM,CAAC,YAAY;QAClC,YAAY,EAAE,MAAM,CAAC,WAAW;QAChC,UAAU,EAAE,oBAAoB;KACjC,CAAC,CAAA;IAEF,IAAI,SAAkB,CAAA;IAEtB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,aAAa,EAAE;gBACrD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;gBAChE,IAAI;gBACJ,OAAO;aACR,CAAC,CAAA;YAEF,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAChB,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA0B,CAAA;gBAC7D,OAAO;oBACL,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,EAAE;oBACpC,YAAY,EAAE,IAAI,CAAC,aAAa;oBAChC,OAAO,EAAE,IAAI,CAAC,QAAQ;oBACtB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,SAAS,EAAE,IAAI,CAAC,UAAU;oBAC1B,SAAS,EAAE,IAAI,CAAC,UAAU;iBAC3B,CAAA;YACH,CAAC;YAED,2BAA2B;YAC3B,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAA;YACpE,MAAM,IAAI,wBAAwB,CAChC,2BAA2B,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CACnE,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAA;YAEjB,sDAAsD;YACtD,IAAI,cAAc,CAAC,KAAK,CAAC,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;gBAC/C,MAAM,KAAK,CAAC,UAAU,CAAC,CAAA;gBACvB,SAAQ;YACV,CAAC;YAED,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAA;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,gBAAwB,EACxB,WAAmB,EACnB,OAA6B;IAE7B,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,eAAe,CAAA;IACnD,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,eAAe,CAAA;IACnD,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,mBAAmB,CAAA;IAE7D,IAAI,SAAkB,CAAA;IAEtB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,gBAAgB,EAAE;gBACxD,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,WAAW,EAAE;oBACtC,MAAM,EAAE,kBAAkB;iBAC3B;gBACD,OAAO;aACR,CAAC,CAAA;YAEF,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAChB,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAA;gBACxD,OAAO;oBACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;oBAC7B,iBAAiB,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE;oBAC5C,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,aAAa,EAAE,IAAI,CAAC,cAAc;oBAClC,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE,IAAI,CAAC,OAAO;oBACnB,GAAG,EAAE,IAAI;iBACV,CAAA;YACH,CAAC;YAED,MAAM,IAAI,oBAAoB,CAAC,8BAA8B,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACzF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAA;YAEjB,IAAI,cAAc,CAAC,KAAK,CAAC,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;gBAC/C,MAAM,KAAK,CAAC,UAAU,CAAC,CAAA;gBACvB,SAAQ;YACV,CAAC;YAED,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAA;AACjB,CAAC"}
@@ -0,0 +1,23 @@
1
+ export type { User, Account, Session, SessionWithUser, OAuthState, ProviderProfile, TokenSet, CreateUserInput, UpdateUserInput, CreateAccountInput, CreateSessionInput, UpdateSessionInput, CreateOAuthStateInput, } from './types.js';
2
+ export type { AuthProvider, AuthorizationParams, ExchangeCodeParams } from './provider.js';
3
+ export type { AuthAdapter } from './adapter.js';
4
+ export { AuthError, OAuthCallbackError, InvalidStateError, ProviderProfileError, ProviderUnreachableError, AccountLinkingError, SessionExpiredError, UnauthorizedError, ForbiddenCallbackURLError, } from './errors.js';
5
+ export type { AdditionalField, AdditionalFieldsConfig, StringField, BooleanField, NumberField, DateField, InferFieldType, InferAdditionalFields, InferTypes, } from './additional-fields.js';
6
+ export type { HookContext, BeforeSignInCtx, AfterSignInCtx, OnUserCreatedCtx, OnAccountLinkedCtx, BeforeSessionCreatedCtx, AfterSessionCreatedCtx, BeforeLogoutCtx, AfterLogoutCtx, HooksConfig, } from './hooks.js';
7
+ export type { SessionConfig, UserConfig, AccountLinkingConfig, SecurityConfig, AuthConfig, CloudAuthInstance, } from './config.js';
8
+ export { generateSessionToken, hashToken, generateCodeVerifier, generateCodeChallenge, constantTimeEqual, } from './crypto.js';
9
+ export { serializeCookie, parseCookie, signCookie, verifyCookie } from './cookies.js';
10
+ export type { CookieOptions } from './cookies.js';
11
+ export { isTrustedOrigin, buildCallbackURL } from './url.js';
12
+ export { exchangeCode, fetchProfile } from './http.js';
13
+ export type { ProviderHttpOptions } from './http.js';
14
+ export { inMemoryRateLimiter, defaultRateLimits } from './rate-limiter.js';
15
+ export type { RateLimiter, RateLimitResult } from './rate-limiter.js';
16
+ export { validateCsrf } from './csrf.js';
17
+ export { encrypt, decrypt } from './encryption.js';
18
+ export { createAuthUrl, handleCallback, getSession as getSessionFromAuth, signOut as signOutFromAuth, } from './auth.js';
19
+ export type { AuthResponse } from './auth.js';
20
+ import type { AuthConfig, CloudAuthInstance } from './config.js';
21
+ export declare function cloudAuth(config: AuthConfig): CloudAuthInstance;
22
+ export declare const version = "0.0.1";
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,IAAI,EACJ,OAAO,EACP,OAAO,EACP,eAAe,EACf,UAAU,EACV,eAAe,EACf,QAAQ,EACR,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,YAAY,CAAA;AAGnB,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAG1F,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAG/C,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,aAAa,CAAA;AAGpB,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,SAAS,EACT,cAAc,EACd,qBAAqB,EACrB,UAAU,GACX,MAAM,wBAAwB,CAAA;AAG/B,YAAY,EACV,WAAW,EACX,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,WAAW,GACZ,MAAM,YAAY,CAAA;AAGnB,YAAY,EACV,aAAa,EACb,UAAU,EACV,oBAAoB,EACpB,cAAc,EACd,UAAU,EACV,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACrF,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAGjD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAG5D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAGpD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1E,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAGxC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAGlD,OAAO,EACL,aAAa,EACb,cAAc,EACd,UAAU,IAAI,kBAAkB,EAChC,OAAO,IAAI,eAAe,GAC3B,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAI7C,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAQhE,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,iBAAiB,CAoC/D;AAED,eAAO,MAAM,OAAO,UAAU,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,53 @@
1
+ // Errors
2
+ export { AuthError, OAuthCallbackError, InvalidStateError, ProviderProfileError, ProviderUnreachableError, AccountLinkingError, SessionExpiredError, UnauthorizedError, ForbiddenCallbackURLError, } from './errors.js';
3
+ // Crypto utilities
4
+ export { generateSessionToken, hashToken, generateCodeVerifier, generateCodeChallenge, constantTimeEqual, } from './crypto.js';
5
+ // Cookie utilities
6
+ export { serializeCookie, parseCookie, signCookie, verifyCookie } from './cookies.js';
7
+ // URL utilities
8
+ export { isTrustedOrigin, buildCallbackURL } from './url.js';
9
+ // Provider HTTP client
10
+ export { exchangeCode, fetchProfile } from './http.js';
11
+ // Rate limiter
12
+ export { inMemoryRateLimiter, defaultRateLimits } from './rate-limiter.js';
13
+ // CSRF protection
14
+ export { validateCsrf } from './csrf.js';
15
+ // Token encryption
16
+ export { encrypt, decrypt } from './encryption.js';
17
+ // Auth engine
18
+ export { createAuthUrl, handleCallback, getSession as getSessionFromAuth, signOut as signOutFromAuth, } from './auth.js';
19
+ import { createAuthUrl, handleCallback, getSession as getSessionFromAuth, signOut as signOutFromAuth, } from './auth.js';
20
+ export function cloudAuth(config) {
21
+ // Validate required config
22
+ if (!config.appName) {
23
+ throw new Error('cloudAuth: appName is required');
24
+ }
25
+ if (!config.baseURL) {
26
+ throw new Error('cloudAuth: baseURL is required');
27
+ }
28
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition */
29
+ if (!config.providers || config.providers.length === 0) {
30
+ throw new Error('cloudAuth: at least one provider is required');
31
+ }
32
+ if (!config.database) {
33
+ throw new Error('cloudAuth: database adapter is required');
34
+ }
35
+ /* eslint-enable @typescript-eslint/no-unnecessary-condition */
36
+ return {
37
+ $Infer: {},
38
+ createAuthUrl(providerId, request) {
39
+ return createAuthUrl(config, providerId, request);
40
+ },
41
+ handleCallback(providerId, request) {
42
+ return handleCallback(config, providerId, request, config.hooks);
43
+ },
44
+ getSession(request) {
45
+ return getSessionFromAuth(config, request);
46
+ },
47
+ signOut(request) {
48
+ return signOutFromAuth(config, request, config.hooks);
49
+ },
50
+ };
51
+ }
52
+ export const version = '0.0.1';
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAuBA,SAAS;AACT,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,aAAa,CAAA;AAuCpB,mBAAmB;AACnB,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAEpB,mBAAmB;AACnB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAGrF,gBAAgB;AAChB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAE5D,uBAAuB;AACvB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAGtD,eAAe;AACf,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAG1E,kBAAkB;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC,mBAAmB;AACnB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAElD,cAAc;AACd,OAAO,EACL,aAAa,EACb,cAAc,EACd,UAAU,IAAI,kBAAkB,EAChC,OAAO,IAAI,eAAe,GAC3B,MAAM,WAAW,CAAA;AAMlB,OAAO,EACL,aAAa,EACb,cAAc,EACd,UAAU,IAAI,kBAAkB,EAChC,OAAO,IAAI,eAAe,GAC3B,MAAM,WAAW,CAAA;AAElB,MAAM,UAAU,SAAS,CAAC,MAAkB;IAC1C,2BAA2B;IAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IACD,gEAAgE;IAChE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;IACjE,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;IAC5D,CAAC;IACD,+DAA+D;IAE/D,OAAO;QACL,MAAM,EAAE,EAAiC;QAEzC,aAAa,CAAC,UAAkB,EAAE,OAAiB;YACjD,OAAO,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;QACnD,CAAC;QAED,cAAc,CAAC,UAAkB,EAAE,OAAgB;YACjD,OAAO,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,UAAU,CAAC,OAAgB;YACzB,OAAO,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC5C,CAAC;QAED,OAAO,CAAC,OAAgB;YACtB,OAAO,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QACvD,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"}