@draftlab/auth 0.0.3 → 0.0.4

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 (74) hide show
  1. package/dist/allow.d.ts +58 -1
  2. package/dist/allow.js +61 -2
  3. package/dist/client.d.ts +2 -3
  4. package/dist/client.js +2 -2
  5. package/dist/core.d.ts +128 -8
  6. package/dist/core.js +496 -12
  7. package/dist/error.d.ts +242 -1
  8. package/dist/error.js +235 -1
  9. package/dist/index.d.ts +1 -8
  10. package/dist/index.js +1 -12
  11. package/dist/keys.d.ts +1 -1
  12. package/dist/keys.js +138 -3
  13. package/dist/pkce.js +160 -1
  14. package/dist/provider/code.d.ts +211 -3
  15. package/dist/provider/code.js +1 -1
  16. package/dist/provider/facebook.d.ts +2 -3
  17. package/dist/provider/facebook.js +1 -5
  18. package/dist/provider/github.d.ts +2 -3
  19. package/dist/provider/github.js +1 -5
  20. package/dist/provider/google.d.ts +2 -3
  21. package/dist/provider/google.js +1 -5
  22. package/dist/provider/oauth2.d.ts +175 -3
  23. package/dist/provider/oauth2.js +153 -5
  24. package/dist/provider/password.d.ts +384 -3
  25. package/dist/provider/password.js +4 -4
  26. package/dist/provider/provider.d.ts +226 -2
  27. package/dist/random.js +85 -1
  28. package/dist/storage/memory.d.ts +1 -1
  29. package/dist/storage/memory.js +1 -1
  30. package/dist/storage/storage.d.ts +161 -1
  31. package/dist/storage/storage.js +60 -1
  32. package/dist/storage/turso.d.ts +1 -1
  33. package/dist/storage/turso.js +1 -1
  34. package/dist/storage/unstorage.d.ts +1 -1
  35. package/dist/storage/unstorage.js +1 -1
  36. package/dist/subject.d.ts +61 -2
  37. package/dist/themes/theme.d.ts +208 -1
  38. package/dist/themes/theme.js +118 -1
  39. package/dist/ui/base.js +420 -2
  40. package/dist/ui/code.d.ts +1 -3
  41. package/dist/ui/code.js +3 -4
  42. package/dist/ui/form.js +59 -1
  43. package/dist/ui/icon.js +190 -1
  44. package/dist/ui/password.d.ts +1 -3
  45. package/dist/ui/password.js +2 -3
  46. package/dist/ui/select.js +278 -4
  47. package/dist/util.d.ts +71 -1
  48. package/dist/util.js +106 -1
  49. package/package.json +2 -2
  50. package/dist/allow-CixonwTW.d.ts +0 -59
  51. package/dist/allow-DX5cehSc.js +0 -63
  52. package/dist/base-DRutbxgL.js +0 -422
  53. package/dist/code-DJxdFR7p.d.ts +0 -212
  54. package/dist/core-BZHEAefX.d.ts +0 -129
  55. package/dist/core-CDM5o4rs.js +0 -498
  56. package/dist/error-CWAdNAzm.d.ts +0 -243
  57. package/dist/error-DgAKK7b2.js +0 -237
  58. package/dist/form-6XKM_cOk.js +0 -61
  59. package/dist/icon-Ci5uqGB_.js +0 -192
  60. package/dist/keys-EEfxEGfO.js +0 -140
  61. package/dist/oauth2-B7-6Z7Lc.js +0 -155
  62. package/dist/oauth2-CXHukHf2.d.ts +0 -176
  63. package/dist/password-C4KLmO0O.d.ts +0 -385
  64. package/dist/pkce-276Za_rZ.js +0 -162
  65. package/dist/provider-tndlqCzp.d.ts +0 -227
  66. package/dist/random-SXMYlaVr.js +0 -87
  67. package/dist/select-BjySLL8I.js +0 -280
  68. package/dist/storage-BEaqEPNQ.js +0 -62
  69. package/dist/storage-CxKerLlc.d.ts +0 -162
  70. package/dist/subject-DMIMVtaT.d.ts +0 -62
  71. package/dist/theme-C9by7VXf.d.ts +0 -209
  72. package/dist/theme-CswaLtbW.js +0 -120
  73. package/dist/util-CSdHUFOo.js +0 -108
  74. package/dist/util-DbSKG1Xm.d.ts +0 -72
@@ -1,3 +1,227 @@
1
- import "../storage-CxKerLlc.js";
2
- import { Provider, ProviderError, ProviderOptions, ProviderRoute, ProviderUnknownError } from "../provider-tndlqCzp.js";
1
+ import { StorageAdapter } from "../storage/storage.js";
2
+ import { Router } from "@draftlab/auth-router";
3
+ import { RouterContext } from "@draftlab/auth-router/types";
4
+
5
+ //#region src/provider/provider.d.ts
6
+
7
+ /**
8
+ * OAuth provider system for Draft Auth.
9
+ * Defines the interfaces and utilities for implementing authentication providers
10
+ * that integrate with various OAuth 2.0 services.
11
+ *
12
+ * ## Creating a Provider
13
+ *
14
+ * ```ts
15
+ * export const MyProvider = (config: MyConfig): Provider<MyUserData> => ({
16
+ * type: "my-provider",
17
+ *
18
+ * init(routes, ctx) {
19
+ * routes.get("/authorize", async (c) => {
20
+ * // Redirect to provider's auth URL
21
+ * return c.redirect(authUrl)
22
+ * })
23
+ *
24
+ * routes.get("/callback", async (c) => {
25
+ * // Handle callback and extract user data
26
+ * const userData = await processCallback(c)
27
+ * return await ctx.success(c, userData)
28
+ * })
29
+ * }
30
+ * })
31
+ * ```
32
+ *
33
+ * ## Using Providers
34
+ *
35
+ * ```ts
36
+ * export default issuer({
37
+ * providers: {
38
+ * github: GithubProvider({ ... }),
39
+ * google: GoogleProvider({ ... })
40
+ * }
41
+ * })
42
+ * ```
43
+ */
44
+ /**
45
+ * Router instance used for provider route definitions.
46
+ * Providers use this to register their authorization and callback endpoints.
47
+ */
48
+ type ProviderRoute = Router;
49
+ /**
50
+ * Authentication provider interface that handles OAuth flows.
51
+ * Each provider implements authentication with a specific service (GitHub, Google, etc.).
52
+ *
53
+ * @template Properties - Type of user data returned by successful authentication
54
+ */
55
+ interface Provider<Properties = Record<string, unknown>> {
56
+ /**
57
+ * Unique identifier for this provider type.
58
+ * Used in URLs and provider selection UI.
59
+ *
60
+ * @example "github", "google", "steam"
61
+ */
62
+ readonly type: string;
63
+ /**
64
+ * Initializes the provider by registering required routes.
65
+ * Called during issuer setup to configure authorization and callback endpoints.
66
+ *
67
+ * @param route - Router instance for registering provider endpoints
68
+ * @param options - Provider utilities and configuration
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * init(routes, ctx) {
73
+ * routes.get("/authorize", async (c) => {
74
+ * // Redirect to OAuth provider
75
+ * return c.redirect(buildAuthUrl())
76
+ * })
77
+ *
78
+ * routes.get("/callback", async (c) => {
79
+ * // Process callback and return user data
80
+ * const userData = await handleCallback(c)
81
+ * return await ctx.success(c, userData)
82
+ * })
83
+ * }
84
+ * ```
85
+ */
86
+ init: (route: ProviderRoute, options: ProviderOptions<Properties>) => void;
87
+ }
88
+ /**
89
+ * Utilities and callbacks provided to providers during initialization.
90
+ * Contains methods for state management, user flow completion, and storage access.
91
+ *
92
+ * @template Properties - Type of user data handled by the provider
93
+ */
94
+ interface ProviderOptions<Properties> {
95
+ /**
96
+ * Name of the provider instance as configured in the issuer.
97
+ * Corresponds to the key used in the providers object.
98
+ */
99
+ readonly name: string;
100
+ /**
101
+ * Completes the authentication flow with user data.
102
+ * Called when the provider successfully authenticates a user.
103
+ *
104
+ * @param ctx - Router request context
105
+ * @param properties - User data extracted from the provider
106
+ * @param opts - Optional utilities for session management
107
+ * @returns Response that completes the OAuth flow
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * const userData = { userId: "123", email: "user@example.com" }
112
+ * return await ctx.success(c, userData)
113
+ * ```
114
+ */
115
+ success: (ctx: RouterContext, properties: Properties, opts?: {
116
+ /** Function to invalidate existing user sessions */
117
+ readonly invalidate?: (subject: string) => Promise<void>;
118
+ }) => Promise<Response>;
119
+ /**
120
+ * Forwards a response through the provider context.
121
+ * Used for redirects and custom responses within the OAuth flow.
122
+ *
123
+ * @param ctx - Router request context
124
+ * @param response - Response to forward
125
+ * @returns Forwarded response
126
+ */
127
+ forward: (ctx: RouterContext, response: Response) => Response;
128
+ /**
129
+ * Stores a temporary value with expiration for the current session.
130
+ * Useful for storing OAuth state, PKCE verifiers, and other temporary data.
131
+ *
132
+ * @param ctx - Router request context
133
+ * @param key - Storage key identifier
134
+ * @param maxAge - TTL in seconds
135
+ * @param value - Value to store
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * // Store OAuth state for 10 minutes
140
+ * await ctx.set(c, "oauth_state", 600, { state, redirectUri })
141
+ * ```
142
+ */
143
+ set: <T>(ctx: RouterContext, key: string, maxAge: number, value: T) => Promise<void>;
144
+ /**
145
+ * Retrieves a previously stored temporary value.
146
+ *
147
+ * @param ctx - Router request context
148
+ * @param key - Storage key identifier
149
+ * @returns Promise resolving to the stored value or undefined if not found/expired
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * const oauthState = await ctx.get<OAuthState>(c, "oauth_state")
154
+ * if (!oauthState) {
155
+ * throw new Error("OAuth state expired")
156
+ * }
157
+ * ```
158
+ */
159
+ get: <T>(ctx: RouterContext, key: string) => Promise<T | undefined>;
160
+ /**
161
+ * Removes a stored temporary value.
162
+ *
163
+ * @param ctx - Router request context
164
+ * @param key - Storage key identifier
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * // Clean up OAuth state after use
169
+ * await ctx.unset(c, "oauth_state")
170
+ * ```
171
+ */
172
+ unset: (ctx: RouterContext, key: string) => Promise<void>;
173
+ /**
174
+ * Invalidates all sessions for a given subject (user).
175
+ * Forces logout across all devices and applications.
176
+ *
177
+ * @param subject - Subject identifier to invalidate
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * // Force logout on password change
182
+ * await ctx.invalidate(userId)
183
+ * ```
184
+ */
185
+ invalidate: (subject: string) => Promise<void>;
186
+ /**
187
+ * Storage adapter for persistent data operations.
188
+ * Provides access to the configured storage backend.
189
+ */
190
+ readonly storage: StorageAdapter;
191
+ }
192
+ /**
193
+ * Base error class for provider-related errors.
194
+ * Extend this class to create specific provider error types.
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * export class GitHubApiError extends ProviderError {
199
+ * constructor(message: string, public readonly statusCode: number) {
200
+ * super(message)
201
+ * }
202
+ * }
203
+ * ```
204
+ */
205
+ declare class ProviderError extends Error {
206
+ constructor(message: string);
207
+ }
208
+ /**
209
+ * Error thrown when a provider encounters an unknown or unexpected error.
210
+ * Used as a fallback for unhandled error conditions.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * catch (error) {
215
+ * if (error instanceof SomeSpecificError) {
216
+ * // Handle specific error
217
+ * } else {
218
+ * throw new ProviderUnknownError(`Unexpected error: ${error}`)
219
+ * }
220
+ * }
221
+ * ```
222
+ */
223
+ declare class ProviderUnknownError extends ProviderError {
224
+ constructor(message?: string);
225
+ }
226
+ //#endregion
3
227
  export { Provider, ProviderError, ProviderOptions, ProviderRoute, ProviderUnknownError };
package/dist/random.js CHANGED
@@ -1,3 +1,87 @@
1
- import { generateSecureToken, generateUnbiasedDigits, timingSafeCompare } from "./random-SXMYlaVr.js";
1
+ import { timingSafeEqual } from "node:crypto";
2
2
 
3
+ //#region src/random.ts
4
+ /**
5
+ * Cryptographic utilities for secure random generation and comparison operations.
6
+ * These functions are designed to prevent timing attacks and provide unbiased randomness.
7
+ */
8
+ /**
9
+ * Generates a cryptographically secure token with enhanced entropy.
10
+ * Uses Web Crypto API and provides 256 bits of entropy
11
+ *
12
+ * @param length - Length of random data in bytes (default: 32 for 256-bit security)
13
+ * @returns Base64url-encoded secure token
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const authCode = generateSecureToken()
18
+ * // Returns: "7B8kJ9mN3pQ2rS5tU8vW0xY1zA3bC6dE9fG2hI5jK8lM" (example)
19
+ *
20
+ * const refreshToken = generateSecureToken(24) // 192-bit token
21
+ * // Returns: "4A7bC9dF2gH5iJ8kL1mN4pQ7rS0tU" (example)
22
+ * ```
23
+ */
24
+ const generateSecureToken = (length = 32) => {
25
+ if (length <= 0 || !Number.isInteger(length)) throw new RangeError("Token length must be a positive integer");
26
+ const randomBytes$1 = new Uint8Array(length);
27
+ crypto.getRandomValues(randomBytes$1);
28
+ const base64 = btoa(String.fromCharCode.apply(null, Array.from(randomBytes$1)));
29
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
30
+ };
31
+ /**
32
+ * Generates a cryptographically secure string of random digits without modulo bias.
33
+ * Uses rejection sampling to ensure each digit (0-9) has an equal probability of being selected.
34
+ *
35
+ * @param length - Number of digits to generate (must be positive)
36
+ * @returns String containing exactly the specified number of random digits
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const pinCode = generateUnbiasedDigits(6)
41
+ * // Returns: "492847" (example - actual result is random)
42
+ *
43
+ * const shortCode = generateUnbiasedDigits(4)
44
+ * // Returns: "7291" (example - actual result is random)
45
+ * ```
46
+ *
47
+ * @throws {RangeError} If length is not a positive number
48
+ */
49
+ const generateUnbiasedDigits = (length) => {
50
+ if (length <= 0 || !Number.isInteger(length)) throw new RangeError("Length must be a positive integer");
51
+ const result = [];
52
+ while (result.length < length) {
53
+ const buffer = crypto.getRandomValues(new Uint8Array(length * 2));
54
+ for (const byte of buffer) if (byte < 250 && result.length < length) result.push(byte % 10);
55
+ }
56
+ return result.join("");
57
+ };
58
+ /**
59
+ * Performs a timing-safe comparison of two strings to prevent timing attacks.
60
+ * Always takes the same amount of time regardless of where the strings differ,
61
+ * making it safe for comparing sensitive values like tokens or passwords.
62
+ *
63
+ * @param a - First string to compare
64
+ * @param b - Second string to compare
65
+ * @returns True if strings are identical, false otherwise
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * // Safe for comparing sensitive values
70
+ * const isValidToken = timingSafeCompare(userToken, expectedToken)
71
+ *
72
+ * // Safe for password verification
73
+ * const isValidPassword = timingSafeCompare(hashedInput, storedHash)
74
+ *
75
+ * // Returns false for different types or lengths
76
+ * timingSafeCompare("abc", 123 as any) // false
77
+ * timingSafeCompare("abc", "abcd") // false
78
+ * ```
79
+ */
80
+ const timingSafeCompare = (a, b) => {
81
+ if (typeof a !== "string" || typeof b !== "string") return false;
82
+ if (a.length !== b.length) return false;
83
+ return timingSafeEqual(Buffer.from(a), Buffer.from(b));
84
+ };
85
+
86
+ //#endregion
3
87
  export { generateSecureToken, generateUnbiasedDigits, timingSafeCompare };
@@ -1,4 +1,4 @@
1
- import { StorageAdapter } from "../storage-CxKerLlc.js";
1
+ import { StorageAdapter } from "./storage.js";
2
2
 
3
3
  //#region src/storage/memory.d.ts
4
4
 
@@ -1,4 +1,4 @@
1
- import { joinKey, splitKey } from "../storage-BEaqEPNQ.js";
1
+ import { joinKey, splitKey } from "./storage.js";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { writeFile } from "node:fs/promises";
4
4
 
@@ -1,2 +1,162 @@
1
- import { Storage, StorageAdapter, joinKey, splitKey } from "../storage-CxKerLlc.js";
1
+ //#region src/storage/storage.d.ts
2
+ /**
3
+ * Storage abstraction layer for Draft Auth persistence operations.
4
+ * Provides a unified interface for different storage backends with key encoding,
5
+ * TTL support, and type-safe operations.
6
+ */
7
+ /**
8
+ * Abstract storage adapter interface that must be implemented by all storage backends.
9
+ * Defines the core operations needed for OAuth data persistence.
10
+ */
11
+ interface StorageAdapter {
12
+ /**
13
+ * Retrieves a value by its key path.
14
+ *
15
+ * @param key - Array of key segments forming the storage path
16
+ * @returns Promise resolving to the stored value or undefined if not found
17
+ */
18
+ get(key: string[]): Promise<Record<string, unknown> | undefined>;
19
+ /**
20
+ * Removes a value by its key path.
21
+ *
22
+ * @param key - Array of key segments forming the storage path
23
+ * @returns Promise that resolves when removal is complete
24
+ */
25
+ remove(key: string[]): Promise<void>;
26
+ /**
27
+ * Stores a value with an optional expiration date.
28
+ *
29
+ * @param key - Array of key segments forming the storage path
30
+ * @param value - The value to store
31
+ * @param expiry - Optional expiration date for automatic cleanup
32
+ * @returns Promise that resolves when storage is complete
33
+ */
34
+ set(key: string[], value: unknown, expiry?: Date): Promise<void>;
35
+ /**
36
+ * Scans for keys matching a prefix pattern.
37
+ *
38
+ * @param prefix - Array of key segments to use as prefix filter
39
+ * @returns Async iterable of key-value pairs matching the prefix
40
+ */
41
+ scan(prefix: string[]): AsyncIterable<readonly [string[], unknown]>;
42
+ }
43
+ /**
44
+ * Joins an array of key segments into a single string using the separator.
45
+ *
46
+ * @param key - Array of key segments to join
47
+ * @returns Single string representing the full key path
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * joinKey(['user', 'session', '123'])
52
+ * // Returns: "user\x1fsession\x1f123"
53
+ * ```
54
+ */
55
+ declare const joinKey: (key: string[]) => string;
56
+ /**
57
+ * Splits a joined key string back into its component segments.
58
+ *
59
+ * @param key - Joined key string to split
60
+ * @returns Array of individual key segments
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * splitKey("user\x1fsession\x1f123")
65
+ * // Returns: ['user', 'session', '123']
66
+ * ```
67
+ */
68
+ declare const splitKey: (key: string) => string[];
69
+ /**
70
+ * High-level storage operations with key encoding and type safety.
71
+ * Provides a convenient interface over storage adapters with additional features
72
+ * like TTL conversion and key sanitization.
73
+ */
74
+ declare const Storage: {
75
+ /**
76
+ * Encodes key segments by removing any separator characters to prevent conflicts.
77
+ * Ensures storage keys don't contain characters that could break key parsing.
78
+ *
79
+ * @param key - Array of key segments to encode
80
+ * @returns Array of sanitized key segments
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * Storage.encode(['user', 'data\x1fwith\x1fseparators'])
85
+ * // Returns: ['user', 'datawithseparators']
86
+ * ```
87
+ */
88
+ readonly encode: (key: string[]) => string[];
89
+ /**
90
+ * Retrieves a typed value from storage.
91
+ *
92
+ * @template T - Expected type of the stored value
93
+ * @param adapter - Storage adapter to use
94
+ * @param key - Array of key segments identifying the value
95
+ * @returns Promise resolving to the typed value or null if not found
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * interface UserSession {
100
+ * userId: string
101
+ * expiresAt: number
102
+ * }
103
+ *
104
+ * const session = await Storage.get<UserSession>(adapter, ['sessions', sessionId])
105
+ * if (session) {
106
+ * // Fully typed: session.userId
107
+ * }
108
+ * ```
109
+ */
110
+ readonly get: <T = Record<string, unknown>>(adapter: StorageAdapter, key: string[]) => Promise<T | null>;
111
+ /**
112
+ * Stores a value with optional time-to-live in seconds.
113
+ *
114
+ * @param adapter - Storage adapter to use
115
+ * @param key - Array of key segments identifying where to store
116
+ * @param value - The value to store
117
+ * @param ttlSeconds - Optional TTL in seconds for automatic expiration
118
+ * @returns Promise that resolves when storage is complete
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * // Store with 1 hour TTL
123
+ * await Storage.set(adapter, ['sessions', sessionId], sessionData, 3600)
124
+ *
125
+ * // Store permanently
126
+ * await Storage.set(adapter, ['users', userId], userData)
127
+ * ```
128
+ */
129
+ readonly set: (adapter: StorageAdapter, key: string[], value: unknown, ttlSeconds?: number) => Promise<void>;
130
+ /**
131
+ * Removes a value from storage.
132
+ *
133
+ * @param adapter - Storage adapter to use
134
+ * @param key - Array of key segments identifying the value to remove
135
+ * @returns Promise that resolves when removal is complete
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * await Storage.remove(adapter, ['sessions', expiredSessionId])
140
+ * ```
141
+ */
142
+ readonly remove: (adapter: StorageAdapter, key: string[]) => Promise<void>;
143
+ /**
144
+ * Scans for entries matching a key prefix with type safety.
145
+ *
146
+ * @template T - Expected type of the stored values
147
+ * @param adapter - Storage adapter to use
148
+ * @param prefix - Array of key segments to use as prefix filter
149
+ * @returns Async iterable of typed key-value pairs
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * // Find all user sessions
154
+ * for await (const [key, session] of Storage.scan<UserSession>(adapter, ['sessions'])) {
155
+ * // Session: `${key.join('/')} expires at ${session.expiresAt}`
156
+ * }
157
+ * ```
158
+ */
159
+ readonly scan: <T = Record<string, unknown>>(adapter: StorageAdapter, prefix: string[]) => AsyncIterable<readonly [string[], T]>;
160
+ };
161
+ //#endregion
2
162
  export { Storage, StorageAdapter, joinKey, splitKey };
@@ -1,3 +1,62 @@
1
- import { Storage, joinKey, splitKey } from "../storage-BEaqEPNQ.js";
1
+ //#region src/storage/storage.ts
2
+ /**
3
+ * ASCII unit separator character used to join key segments.
4
+ * Using a control character ensures it won't conflict with user data.
5
+ */
6
+ const SEPARATOR = String.fromCharCode(31);
7
+ /**
8
+ * Joins an array of key segments into a single string using the separator.
9
+ *
10
+ * @param key - Array of key segments to join
11
+ * @returns Single string representing the full key path
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * joinKey(['user', 'session', '123'])
16
+ * // Returns: "user\x1fsession\x1f123"
17
+ * ```
18
+ */
19
+ const joinKey = (key) => {
20
+ return key.join(SEPARATOR);
21
+ };
22
+ /**
23
+ * Splits a joined key string back into its component segments.
24
+ *
25
+ * @param key - Joined key string to split
26
+ * @returns Array of individual key segments
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * splitKey("user\x1fsession\x1f123")
31
+ * // Returns: ['user', 'session', '123']
32
+ * ```
33
+ */
34
+ const splitKey = (key) => {
35
+ return key.split(SEPARATOR);
36
+ };
37
+ /**
38
+ * High-level storage operations with key encoding and type safety.
39
+ * Provides a convenient interface over storage adapters with additional features
40
+ * like TTL conversion and key sanitization.
41
+ */
42
+ const Storage = {
43
+ encode: (key) => {
44
+ return key.map((segment) => segment.replaceAll(SEPARATOR, ""));
45
+ },
46
+ get: (adapter, key) => {
47
+ return adapter.get(Storage.encode(key));
48
+ },
49
+ set: (adapter, key, value, ttlSeconds) => {
50
+ const expiry = ttlSeconds ? new Date(Date.now() + ttlSeconds * 1e3) : void 0;
51
+ return adapter.set(Storage.encode(key), value, expiry);
52
+ },
53
+ remove: (adapter, key) => {
54
+ return adapter.remove(Storage.encode(key));
55
+ },
56
+ scan: (adapter, prefix) => {
57
+ return adapter.scan(Storage.encode(prefix));
58
+ }
59
+ };
2
60
 
61
+ //#endregion
3
62
  export { Storage, joinKey, splitKey };
@@ -1,4 +1,4 @@
1
- import { StorageAdapter } from "../storage-CxKerLlc.js";
1
+ import { StorageAdapter } from "./storage.js";
2
2
  import { Client } from "@libsql/client";
3
3
 
4
4
  //#region src/storage/turso.d.ts
@@ -1,4 +1,4 @@
1
- import { joinKey, splitKey } from "../storage-BEaqEPNQ.js";
1
+ import { joinKey, splitKey } from "./storage.js";
2
2
 
3
3
  //#region src/storage/turso.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { StorageAdapter } from "../storage-CxKerLlc.js";
1
+ import { StorageAdapter } from "./storage.js";
2
2
  import { Driver } from "unstorage";
3
3
 
4
4
  //#region src/storage/unstorage.d.ts
@@ -1,4 +1,4 @@
1
- import { joinKey, splitKey } from "../storage-BEaqEPNQ.js";
1
+ import { joinKey, splitKey } from "./storage.js";
2
2
  import { createStorage } from "unstorage";
3
3
 
4
4
  //#region src/storage/unstorage.ts
package/dist/subject.d.ts CHANGED
@@ -1,3 +1,62 @@
1
- import "./util-DbSKG1Xm.js";
2
- import { SubjectPayload, SubjectSchema, createSubjects } from "./subject-DMIMVtaT.js";
1
+ import { Prettify } from "./util.js";
2
+ import { StandardSchemaV1 } from "@standard-schema/spec";
3
+
4
+ //#region src/subject.d.ts
5
+
6
+ /**
7
+ * Schema definition for subjects, mapping subject type names to their validation schemas.
8
+ * Each key represents a subject type, and each value is a schema that validates
9
+ * the properties for that subject type.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const schema: SubjectSchema = {
14
+ * user: object({ userID: string() }),
15
+ * admin: object({ userID: string(), workspaceID: string() })
16
+ * }
17
+ * ```
18
+ */
19
+ type SubjectSchema = Record<string, StandardSchemaV1>;
20
+ /**
21
+ * Internal type that transforms a SubjectSchema into a union of subject payload objects.
22
+ * Each payload contains the subject type and its validated properties.
23
+ *
24
+ * @template T - The subject schema to transform
25
+ * @internal
26
+ */
27
+ type SubjectPayload<T extends SubjectSchema> = Prettify<{ [K in keyof T & string]: {
28
+ type: K;
29
+ properties: StandardSchemaV1.InferOutput<T[K]>;
30
+ } }[keyof T & string]>;
31
+ /**
32
+ * Creates a strongly-typed subject schema that can be used throughout your application.
33
+ * The returned schema maintains type information for excellent IDE support and runtime validation.
34
+ *
35
+ * @template Schema - The subject schema type being created
36
+ * @param types - Object mapping subject type names to their validation schemas
37
+ * @returns The same schema object with preserved type information
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * import { object, string, number } from "valibot"
42
+ *
43
+ * const subjects = createSubjects({
44
+ * user: object({
45
+ * userID: string(),
46
+ * createdAt: number()
47
+ * }),
48
+ * admin: object({
49
+ * userID: string(),
50
+ * workspaceID: string(),
51
+ * permissions: array(string())
52
+ * }),
53
+ * service: object({
54
+ * serviceID: string(),
55
+ * apiVersion: string()
56
+ * })
57
+ * })
58
+ * ```
59
+ */
60
+ declare const createSubjects: <Schema extends SubjectSchema>(types: Schema) => Schema;
61
+ //#endregion
3
62
  export { SubjectPayload, SubjectSchema, createSubjects };