@draftlab/auth 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/node.d.ts +18 -0
- package/dist/adapters/node.js +71 -0
- package/dist/allow-CixonwTW.d.ts +59 -0
- package/dist/allow-DX5cehSc.js +63 -0
- package/dist/allow.d.ts +2 -0
- package/dist/allow.js +4 -0
- package/dist/base-DRutbxgL.js +422 -0
- package/dist/client.d.ts +413 -0
- package/dist/client.js +209 -0
- package/dist/code-l_uvMR1j.d.ts +212 -0
- package/dist/core-8WTqfnb4.d.ts +129 -0
- package/dist/core-CncE5rPg.js +498 -0
- package/dist/core.d.ts +9 -0
- package/dist/core.js +14 -0
- package/dist/error-CWAdNAzm.d.ts +243 -0
- package/dist/error-DgAKK7b2.js +237 -0
- package/dist/error.d.ts +2 -0
- package/dist/error.js +3 -0
- package/dist/form-6XKM_cOk.js +61 -0
- package/dist/icon-Ci5uqGB_.js +192 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +14 -0
- package/dist/keys-EEfxEGfO.js +140 -0
- package/dist/keys.d.ts +67 -0
- package/dist/keys.js +5 -0
- package/dist/oauth2-B7-6Z7Lc.js +155 -0
- package/dist/oauth2-DtKwtl8p.d.ts +176 -0
- package/dist/password-Cm0dRMwa.d.ts +385 -0
- package/dist/pkce-276Za_rZ.js +162 -0
- package/dist/pkce.d.ts +72 -0
- package/dist/pkce.js +3 -0
- package/dist/provider/code.d.ts +4 -0
- package/dist/provider/code.js +145 -0
- package/dist/provider/facebook.d.ts +137 -0
- package/dist/provider/facebook.js +85 -0
- package/dist/provider/github.d.ts +141 -0
- package/dist/provider/github.js +88 -0
- package/dist/provider/google.d.ts +113 -0
- package/dist/provider/google.js +62 -0
- package/dist/provider/oauth2.d.ts +4 -0
- package/dist/provider/oauth2.js +7 -0
- package/dist/provider/password.d.ts +4 -0
- package/dist/provider/password.js +366 -0
- package/dist/provider/provider.d.ts +3 -0
- package/dist/provider/provider.js +44 -0
- package/dist/provider-CwWMG-1l.d.ts +227 -0
- package/dist/random-SXMYlaVr.js +87 -0
- package/dist/random.d.ts +66 -0
- package/dist/random.js +3 -0
- package/dist/select-BjySLL8I.js +280 -0
- package/dist/storage/memory.d.ts +82 -0
- package/dist/storage/memory.js +127 -0
- package/dist/storage/storage.d.ts +2 -0
- package/dist/storage/storage.js +3 -0
- package/dist/storage/turso.d.ts +31 -0
- package/dist/storage/turso.js +117 -0
- package/dist/storage/unstorage.d.ts +38 -0
- package/dist/storage/unstorage.js +97 -0
- package/dist/storage-BEaqEPNQ.js +62 -0
- package/dist/storage-CxKerLlc.d.ts +162 -0
- package/dist/subject-DiQdRWGt.d.ts +62 -0
- package/dist/subject.d.ts +3 -0
- package/dist/subject.js +36 -0
- package/dist/theme-C9by7VXf.d.ts +209 -0
- package/dist/theme-CswaLtbW.js +120 -0
- package/dist/themes/theme.d.ts +2 -0
- package/dist/themes/theme.js +3 -0
- package/dist/types.d.ts +94 -0
- package/dist/types.js +0 -0
- package/dist/ui/base.d.ts +43 -0
- package/dist/ui/base.js +4 -0
- package/dist/ui/code.d.ts +158 -0
- package/dist/ui/code.js +197 -0
- package/dist/ui/form.d.ts +31 -0
- package/dist/ui/form.js +3 -0
- package/dist/ui/icon.d.ts +98 -0
- package/dist/ui/icon.js +3 -0
- package/dist/ui/password.d.ts +54 -0
- package/dist/ui/password.js +300 -0
- package/dist/ui/select.d.ts +233 -0
- package/dist/ui/select.js +6 -0
- package/dist/util-CSdHUFOo.js +108 -0
- package/dist/util-ChlgVqPN.d.ts +72 -0
- package/dist/util.d.ts +2 -0
- package/dist/util.js +3 -0
- package/package.json +63 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { joinKey, splitKey } from "../storage-BEaqEPNQ.js";
|
|
2
|
+
|
|
3
|
+
//#region src/storage/turso.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Turso storage adapter using the provided LibSQL client.
|
|
6
|
+
* Automatically initializes the required database table and implements
|
|
7
|
+
* the StorageAdapter interface with efficient SQL operations.
|
|
8
|
+
*
|
|
9
|
+
* @param client - Configured LibSQL client for database operations
|
|
10
|
+
* @returns Storage adapter implementing the StorageAdapter interface
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { createClient } from "@libsql/client"
|
|
15
|
+
*
|
|
16
|
+
* const client = createClient({
|
|
17
|
+
* url: process.env.TURSO_DATABASE_URL,
|
|
18
|
+
* authToken: process.env.TURSO_AUTH_TOKEN
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* const storage = TursoStorage(client)
|
|
22
|
+
*
|
|
23
|
+
* // Now ready to use with Draft Auth
|
|
24
|
+
* const app = issuer({ storage, ... })
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
const TursoStorage = (client) => {
|
|
28
|
+
const TABLE_NAME = "__draftauth__kv_storage";
|
|
29
|
+
client.execute(`
|
|
30
|
+
CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
|
|
31
|
+
key TEXT PRIMARY KEY,
|
|
32
|
+
value TEXT NOT NULL,
|
|
33
|
+
expiry INTEGER
|
|
34
|
+
)
|
|
35
|
+
`);
|
|
36
|
+
client.execute(`
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_${TABLE_NAME}_key_prefix
|
|
38
|
+
ON ${TABLE_NAME} (key)
|
|
39
|
+
`);
|
|
40
|
+
client.execute(`
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_${TABLE_NAME}_expiry
|
|
42
|
+
ON ${TABLE_NAME} (expiry)
|
|
43
|
+
WHERE expiry IS NOT NULL
|
|
44
|
+
`);
|
|
45
|
+
return {
|
|
46
|
+
async get(key) {
|
|
47
|
+
const joinedKey = joinKey(key);
|
|
48
|
+
const { rows } = await client.execute({
|
|
49
|
+
sql: `SELECT value, expiry FROM ${TABLE_NAME} WHERE key = ?`,
|
|
50
|
+
args: [joinedKey]
|
|
51
|
+
});
|
|
52
|
+
const row = rows[0];
|
|
53
|
+
if (!row) return;
|
|
54
|
+
if (row.expiry && row.expiry < Date.now()) {
|
|
55
|
+
await client.execute({
|
|
56
|
+
sql: `DELETE FROM ${TABLE_NAME} WHERE key = ?`,
|
|
57
|
+
args: [joinedKey]
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(row.value);
|
|
63
|
+
} catch {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
async set(key, value, expiry) {
|
|
68
|
+
const joinedKey = joinKey(key);
|
|
69
|
+
const expiryTimestamp = expiry?.getTime() ?? null;
|
|
70
|
+
try {
|
|
71
|
+
const serializedValue = JSON.stringify(value);
|
|
72
|
+
await client.execute({
|
|
73
|
+
sql: `INSERT OR REPLACE INTO ${TABLE_NAME} (key, value, expiry) VALUES (?, ?, ?)`,
|
|
74
|
+
args: [
|
|
75
|
+
joinedKey,
|
|
76
|
+
serializedValue,
|
|
77
|
+
expiryTimestamp
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
} catch {
|
|
81
|
+
throw new Error("Storage operation failed");
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
async remove(key) {
|
|
85
|
+
const joinedKey = joinKey(key);
|
|
86
|
+
await client.execute({
|
|
87
|
+
sql: `DELETE FROM ${TABLE_NAME} WHERE key = ?`,
|
|
88
|
+
args: [joinedKey]
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
async *scan(prefix) {
|
|
92
|
+
const joinedPrefix = joinKey(prefix);
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
const { rows } = await client.execute({
|
|
95
|
+
sql: `
|
|
96
|
+
SELECT key, value, expiry
|
|
97
|
+
FROM ${TABLE_NAME}
|
|
98
|
+
WHERE key LIKE ?
|
|
99
|
+
AND (expiry IS NULL OR expiry >= ?)
|
|
100
|
+
ORDER BY key
|
|
101
|
+
`,
|
|
102
|
+
args: [`${joinedPrefix}%`, now]
|
|
103
|
+
});
|
|
104
|
+
for (const row of rows) try {
|
|
105
|
+
const parsedValue = JSON.parse(row.value);
|
|
106
|
+
yield [splitKey(row.key), parsedValue];
|
|
107
|
+
} catch {}
|
|
108
|
+
client.execute({
|
|
109
|
+
sql: `DELETE FROM ${TABLE_NAME} WHERE expiry IS NOT NULL AND expiry < ?`,
|
|
110
|
+
args: [now]
|
|
111
|
+
}).catch(() => {});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
//#endregion
|
|
117
|
+
export { TursoStorage };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { StorageAdapter } from "../storage-CxKerLlc.js";
|
|
2
|
+
import { Driver } from "unstorage";
|
|
3
|
+
|
|
4
|
+
//#region src/storage/unstorage.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a Draft Auth storage adapter using Unstorage drivers.
|
|
8
|
+
* Supports automatic expiration, error handling, and any Unstorage driver.
|
|
9
|
+
*
|
|
10
|
+
* @param options - Configuration options
|
|
11
|
+
* @param options.driver - Optional Unstorage driver (defaults to memory)
|
|
12
|
+
* @returns Storage adapter compatible with Draft Auth
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { UnStorage } from "@draftauth/core/storage/unstorage"
|
|
17
|
+
* import redisDriver from "unstorage/drivers/redis"
|
|
18
|
+
*
|
|
19
|
+
* // Using Redis driver
|
|
20
|
+
* const storage = UnStorage({
|
|
21
|
+
* driver: redisDriver({
|
|
22
|
+
* host: process.env.REDIS_HOST,
|
|
23
|
+
* port: parseInt(process.env.REDIS_PORT || "6379"),
|
|
24
|
+
* password: process.env.REDIS_PASSWORD
|
|
25
|
+
* })
|
|
26
|
+
* })
|
|
27
|
+
*
|
|
28
|
+
* // Using default memory driver (development only)
|
|
29
|
+
* const memoryStorage = UnStorage()
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare const UnStorage: ({
|
|
33
|
+
driver
|
|
34
|
+
}?: {
|
|
35
|
+
driver?: Driver;
|
|
36
|
+
}) => StorageAdapter;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { UnStorage };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { joinKey, splitKey } from "../storage-BEaqEPNQ.js";
|
|
2
|
+
import { createStorage } from "unstorage";
|
|
3
|
+
|
|
4
|
+
//#region src/storage/unstorage.ts
|
|
5
|
+
/**
|
|
6
|
+
* Creates a Draft Auth storage adapter using Unstorage drivers.
|
|
7
|
+
* Supports automatic expiration, error handling, and any Unstorage driver.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Configuration options
|
|
10
|
+
* @param options.driver - Optional Unstorage driver (defaults to memory)
|
|
11
|
+
* @returns Storage adapter compatible with Draft Auth
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { UnStorage } from "@draftauth/core/storage/unstorage"
|
|
16
|
+
* import redisDriver from "unstorage/drivers/redis"
|
|
17
|
+
*
|
|
18
|
+
* // Using Redis driver
|
|
19
|
+
* const storage = UnStorage({
|
|
20
|
+
* driver: redisDriver({
|
|
21
|
+
* host: process.env.REDIS_HOST,
|
|
22
|
+
* port: parseInt(process.env.REDIS_PORT || "6379"),
|
|
23
|
+
* password: process.env.REDIS_PASSWORD
|
|
24
|
+
* })
|
|
25
|
+
* })
|
|
26
|
+
*
|
|
27
|
+
* // Using default memory driver (development only)
|
|
28
|
+
* const memoryStorage = UnStorage()
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
const UnStorage = ({ driver } = {}) => {
|
|
32
|
+
const store = createStorage({ driver });
|
|
33
|
+
return {
|
|
34
|
+
async get(key) {
|
|
35
|
+
try {
|
|
36
|
+
const keyPath = joinKey(key);
|
|
37
|
+
const entry = await store.getItem(keyPath);
|
|
38
|
+
if (!entry) return void 0;
|
|
39
|
+
if (entry.expiry && Date.now() >= entry.expiry) {
|
|
40
|
+
store.removeItem(keyPath).catch(() => {});
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
return entry.value;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("UnStorage get error:", error);
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
async set(key, value, expiry) {
|
|
50
|
+
try {
|
|
51
|
+
const keyPath = joinKey(key);
|
|
52
|
+
const entry = {
|
|
53
|
+
value,
|
|
54
|
+
expiry: expiry ? expiry.getTime() : void 0
|
|
55
|
+
};
|
|
56
|
+
await store.setItem(keyPath, entry);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error("UnStorage set error:", error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
async remove(key) {
|
|
63
|
+
try {
|
|
64
|
+
const keyPath = joinKey(key);
|
|
65
|
+
await store.removeItem(keyPath);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error("UnStorage remove error:", error);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
async *scan(prefix) {
|
|
71
|
+
try {
|
|
72
|
+
const now = Date.now();
|
|
73
|
+
const prefixPath = joinKey(prefix);
|
|
74
|
+
let keys = await store.getKeys(prefixPath);
|
|
75
|
+
if (keys.length === 0) {
|
|
76
|
+
const allKeys = await store.getKeys();
|
|
77
|
+
if (allKeys.length > 0) keys = allKeys.filter((key) => key.startsWith(prefixPath));
|
|
78
|
+
}
|
|
79
|
+
const limitedKeys = keys.slice(0, 1e3);
|
|
80
|
+
for (const keyPath of limitedKeys) try {
|
|
81
|
+
const entry = await store.getItem(keyPath);
|
|
82
|
+
if (!entry || !entry.value) continue;
|
|
83
|
+
if (entry.expiry && now >= entry.expiry) {
|
|
84
|
+
store.removeItem(keyPath).catch(() => {});
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
yield [splitKey(keyPath), entry.value];
|
|
88
|
+
} catch {}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error("UnStorage scan error:", error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { UnStorage };
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
};
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { Storage, joinKey, splitKey };
|
|
@@ -0,0 +1,162 @@
|
|
|
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
|
|
162
|
+
export { Storage, StorageAdapter, joinKey, splitKey };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Prettify } from "./util-ChlgVqPN.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
|
|
62
|
+
export { SubjectPayload, SubjectSchema, createSubjects };
|
package/dist/subject.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/subject.ts
|
|
2
|
+
/**
|
|
3
|
+
* Creates a strongly-typed subject schema that can be used throughout your application.
|
|
4
|
+
* The returned schema maintains type information for excellent IDE support and runtime validation.
|
|
5
|
+
*
|
|
6
|
+
* @template Schema - The subject schema type being created
|
|
7
|
+
* @param types - Object mapping subject type names to their validation schemas
|
|
8
|
+
* @returns The same schema object with preserved type information
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { object, string, number } from "valibot"
|
|
13
|
+
*
|
|
14
|
+
* const subjects = createSubjects({
|
|
15
|
+
* user: object({
|
|
16
|
+
* userID: string(),
|
|
17
|
+
* createdAt: number()
|
|
18
|
+
* }),
|
|
19
|
+
* admin: object({
|
|
20
|
+
* userID: string(),
|
|
21
|
+
* workspaceID: string(),
|
|
22
|
+
* permissions: array(string())
|
|
23
|
+
* }),
|
|
24
|
+
* service: object({
|
|
25
|
+
* serviceID: string(),
|
|
26
|
+
* apiVersion: string()
|
|
27
|
+
* })
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
const createSubjects = (types) => {
|
|
32
|
+
return { ...types };
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createSubjects };
|