@donotlb/keypal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +1037 -0
- package/dist/drizzle/schema.d.mts +87 -0
- package/dist/drizzle/schema.d.ts +87 -0
- package/dist/drizzle/schema.mjs +7 -0
- package/dist/index.d.mts +606 -0
- package/dist/index.d.ts +606 -0
- package/dist/index.mjs +7 -0
- package/dist/shared/keypal.C-UeOmUF.mjs +7 -0
- package/dist/shared/keypal.kItV-5pB.d.mts +194 -0
- package/dist/shared/keypal.kItV-5pB.d.ts +194 -0
- package/dist/shared/keypal.lTVSZWgp.mjs +7 -0
- package/dist/storage/drizzle.d.mts +192 -0
- package/dist/storage/drizzle.d.ts +192 -0
- package/dist/storage/drizzle.mjs +7 -0
- package/dist/storage/memory.d.mts +27 -0
- package/dist/storage/memory.d.ts +27 -0
- package/dist/storage/memory.mjs +7 -0
- package/dist/storage/redis.d.mts +42 -0
- package/dist/storage/redis.d.ts +42 -0
- package/dist/storage/redis.mjs +7 -0
- package/package.json +122 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Static, Type } from 'typebox';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Metadata associated with an API key
|
|
5
|
+
*/
|
|
6
|
+
declare const ApiKeyMetadataSchema: Type.TObject<{
|
|
7
|
+
/** Unique identifier for the key owner */
|
|
8
|
+
ownerId: Type.TString;
|
|
9
|
+
/** Optional human-readable name for the key */
|
|
10
|
+
name: Type.TOptional<Type.TString>;
|
|
11
|
+
/** Optional description of what this key is used for */
|
|
12
|
+
description: Type.TOptional<Type.TString>;
|
|
13
|
+
/** Scopes/permissions associated with this key */
|
|
14
|
+
scopes: Type.TOptional<Type.TArray<Type.TString>>;
|
|
15
|
+
/** Resource-specific scopes (e.g., { "website:123": ["read"], "project:456": ["write"] }) */
|
|
16
|
+
resources: Type.TOptional<Type.TRecord<"^.*$", Type.TArray<Type.TString>>>;
|
|
17
|
+
/** ISO timestamp when the key expires (null if never expires) */
|
|
18
|
+
expiresAt: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
19
|
+
/** ISO timestamp when the key was created */
|
|
20
|
+
createdAt: Type.TOptional<Type.TString>;
|
|
21
|
+
/** ISO timestamp when the key was last used */
|
|
22
|
+
lastUsedAt: Type.TOptional<Type.TString>;
|
|
23
|
+
/** Whether the key is enabled (default: true) */
|
|
24
|
+
enabled: Type.TOptional<Type.TBoolean>;
|
|
25
|
+
/** ISO timestamp when the key was revoked (null if not revoked) */
|
|
26
|
+
revokedAt: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
27
|
+
/** ID of the key this was rotated to (for key rotation) */
|
|
28
|
+
rotatedTo: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
29
|
+
tags: Type.TOptional<Type.TArray<Type.TString>>;
|
|
30
|
+
}>;
|
|
31
|
+
type ApiKeyMetadata = Static<typeof ApiKeyMetadataSchema>;
|
|
32
|
+
/**
|
|
33
|
+
* Complete API key record stored in the database
|
|
34
|
+
*/
|
|
35
|
+
type ApiKeyRecord = {
|
|
36
|
+
/** Hashed version of the API key */
|
|
37
|
+
keyHash: string;
|
|
38
|
+
/** Unique identifier for this key record */
|
|
39
|
+
id: string;
|
|
40
|
+
/** Metadata associated with the key */
|
|
41
|
+
metadata: ApiKeyMetadata;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Input for creating an API key
|
|
45
|
+
*/
|
|
46
|
+
type CreateApiKeyInput = {
|
|
47
|
+
/** Optional custom prefix */
|
|
48
|
+
prefix?: string;
|
|
49
|
+
/** Optional custom length */
|
|
50
|
+
length?: number;
|
|
51
|
+
/** Metadata to associate with the key */
|
|
52
|
+
metadata: Partial<ApiKeyMetadata>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Audit log action types
|
|
57
|
+
*/
|
|
58
|
+
type AuditAction = "created" | "revoked" | "rotated" | "enabled" | "disabled";
|
|
59
|
+
/**
|
|
60
|
+
* Context for who performed an action
|
|
61
|
+
*/
|
|
62
|
+
type ActionContext = {
|
|
63
|
+
/** User ID who performed the action */
|
|
64
|
+
userId?: string;
|
|
65
|
+
/** IP address of the requester */
|
|
66
|
+
ip?: string;
|
|
67
|
+
/** User agent of the requester */
|
|
68
|
+
userAgent?: string;
|
|
69
|
+
/** Custom metadata about the action */
|
|
70
|
+
metadata?: Record<string, unknown>;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Audit log entry
|
|
74
|
+
*/
|
|
75
|
+
type AuditLog = {
|
|
76
|
+
/** Unique identifier for this log entry */
|
|
77
|
+
id: string;
|
|
78
|
+
/** The action that was performed */
|
|
79
|
+
action: AuditAction;
|
|
80
|
+
/** ID of the API key */
|
|
81
|
+
keyId: string;
|
|
82
|
+
/** ID of the key owner */
|
|
83
|
+
ownerId: string;
|
|
84
|
+
/** ISO timestamp when the action occurred */
|
|
85
|
+
timestamp: string;
|
|
86
|
+
/** Optional additional data about the action */
|
|
87
|
+
data?: Record<string, unknown>;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Options for querying audit logs
|
|
91
|
+
*/
|
|
92
|
+
type AuditLogQuery = {
|
|
93
|
+
/** Filter by key ID */
|
|
94
|
+
keyId?: string;
|
|
95
|
+
/** Filter by owner ID */
|
|
96
|
+
ownerId?: string;
|
|
97
|
+
/** Filter by action */
|
|
98
|
+
action?: AuditAction;
|
|
99
|
+
/** Filter by start date (ISO timestamp) */
|
|
100
|
+
startDate?: string;
|
|
101
|
+
/** Filter by end date (ISO timestamp) */
|
|
102
|
+
endDate?: string;
|
|
103
|
+
/** Maximum number of results to return (default: 100) */
|
|
104
|
+
limit?: number;
|
|
105
|
+
/** Offset for pagination (default: 0) */
|
|
106
|
+
offset?: number;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Statistics about audit logs
|
|
110
|
+
*/
|
|
111
|
+
type AuditLogStats = {
|
|
112
|
+
/** Total number of logs */
|
|
113
|
+
total: number;
|
|
114
|
+
/** Count by action type */
|
|
115
|
+
byAction: Partial<Record<AuditAction, number>>;
|
|
116
|
+
/** ISO timestamp of last activity */
|
|
117
|
+
lastActivity: string | null;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Storage interface for persisting API keys
|
|
122
|
+
*/
|
|
123
|
+
type Storage = {
|
|
124
|
+
/**
|
|
125
|
+
* Save an API key record to storage
|
|
126
|
+
*/
|
|
127
|
+
save(record: ApiKeyRecord): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Find an API key record by its hash
|
|
130
|
+
*/
|
|
131
|
+
findByHash(keyHash: string): Promise<ApiKeyRecord | null>;
|
|
132
|
+
/**
|
|
133
|
+
* Find an API key record by ID
|
|
134
|
+
*/
|
|
135
|
+
findById(id: string): Promise<ApiKeyRecord | null>;
|
|
136
|
+
/**
|
|
137
|
+
* Find all API keys for a specific owner
|
|
138
|
+
*/
|
|
139
|
+
findByOwner(ownerId: string): Promise<ApiKeyRecord[]>;
|
|
140
|
+
/**
|
|
141
|
+
* Find all API keys by tags and optionally by owner
|
|
142
|
+
* @param tags - Tags to search for
|
|
143
|
+
* @param ownerId - Optional owner ID to filter results
|
|
144
|
+
*/
|
|
145
|
+
findByTags(tags: string[], ownerId?: string): Promise<ApiKeyRecord[]>;
|
|
146
|
+
/**
|
|
147
|
+
* Find all API keys by tag and optionally by owner
|
|
148
|
+
* @param tag - Tag to search for
|
|
149
|
+
* @param ownerId - Optional owner ID to filter results
|
|
150
|
+
*/
|
|
151
|
+
findByTag(tag: string, ownerId?: string): Promise<ApiKeyRecord[]>;
|
|
152
|
+
/**
|
|
153
|
+
* Update metadata for an existing key
|
|
154
|
+
*/
|
|
155
|
+
updateMetadata(id: string, metadata: Partial<ApiKeyMetadata>): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Delete an API key record
|
|
158
|
+
*/
|
|
159
|
+
delete(id: string): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Delete all keys for a specific owner
|
|
162
|
+
*/
|
|
163
|
+
deleteByOwner(ownerId: string): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Save an audit log entry (optional, only if audit logging is enabled)
|
|
166
|
+
*/
|
|
167
|
+
saveLog?(log: AuditLog): Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Query audit logs (optional, only if audit logging is enabled)
|
|
170
|
+
*/
|
|
171
|
+
findLogs?(query: AuditLogQuery): Promise<AuditLog[]>;
|
|
172
|
+
/**
|
|
173
|
+
* Count audit logs matching query (optional, only if audit logging is enabled)
|
|
174
|
+
*/
|
|
175
|
+
countLogs?(query: AuditLogQuery): Promise<number>;
|
|
176
|
+
/**
|
|
177
|
+
* Delete audit logs matching query (optional, only if audit logging is enabled)
|
|
178
|
+
* @returns Number of logs deleted
|
|
179
|
+
*/
|
|
180
|
+
deleteLogs?(query: AuditLogQuery): Promise<number>;
|
|
181
|
+
/**
|
|
182
|
+
* Get statistics about audit logs (optional, only if audit logging is enabled)
|
|
183
|
+
*/
|
|
184
|
+
getLogStats?(ownerId: string): Promise<AuditLogStats>;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Options for storage operations
|
|
188
|
+
*/
|
|
189
|
+
type StorageOptions = {
|
|
190
|
+
/** Optional TTL (time to live) in seconds */
|
|
191
|
+
ttl?: number;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export type { ActionContext as A, CreateApiKeyInput as C, Storage as S, ApiKeyRecord as a, ApiKeyMetadata as b, AuditLogQuery as c, AuditLog as d, AuditLogStats as e, AuditAction as f, StorageOptions as g };
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Static, Type } from 'typebox';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Metadata associated with an API key
|
|
5
|
+
*/
|
|
6
|
+
declare const ApiKeyMetadataSchema: Type.TObject<{
|
|
7
|
+
/** Unique identifier for the key owner */
|
|
8
|
+
ownerId: Type.TString;
|
|
9
|
+
/** Optional human-readable name for the key */
|
|
10
|
+
name: Type.TOptional<Type.TString>;
|
|
11
|
+
/** Optional description of what this key is used for */
|
|
12
|
+
description: Type.TOptional<Type.TString>;
|
|
13
|
+
/** Scopes/permissions associated with this key */
|
|
14
|
+
scopes: Type.TOptional<Type.TArray<Type.TString>>;
|
|
15
|
+
/** Resource-specific scopes (e.g., { "website:123": ["read"], "project:456": ["write"] }) */
|
|
16
|
+
resources: Type.TOptional<Type.TRecord<"^.*$", Type.TArray<Type.TString>>>;
|
|
17
|
+
/** ISO timestamp when the key expires (null if never expires) */
|
|
18
|
+
expiresAt: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
19
|
+
/** ISO timestamp when the key was created */
|
|
20
|
+
createdAt: Type.TOptional<Type.TString>;
|
|
21
|
+
/** ISO timestamp when the key was last used */
|
|
22
|
+
lastUsedAt: Type.TOptional<Type.TString>;
|
|
23
|
+
/** Whether the key is enabled (default: true) */
|
|
24
|
+
enabled: Type.TOptional<Type.TBoolean>;
|
|
25
|
+
/** ISO timestamp when the key was revoked (null if not revoked) */
|
|
26
|
+
revokedAt: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
27
|
+
/** ID of the key this was rotated to (for key rotation) */
|
|
28
|
+
rotatedTo: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull]>>;
|
|
29
|
+
tags: Type.TOptional<Type.TArray<Type.TString>>;
|
|
30
|
+
}>;
|
|
31
|
+
type ApiKeyMetadata = Static<typeof ApiKeyMetadataSchema>;
|
|
32
|
+
/**
|
|
33
|
+
* Complete API key record stored in the database
|
|
34
|
+
*/
|
|
35
|
+
type ApiKeyRecord = {
|
|
36
|
+
/** Hashed version of the API key */
|
|
37
|
+
keyHash: string;
|
|
38
|
+
/** Unique identifier for this key record */
|
|
39
|
+
id: string;
|
|
40
|
+
/** Metadata associated with the key */
|
|
41
|
+
metadata: ApiKeyMetadata;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Input for creating an API key
|
|
45
|
+
*/
|
|
46
|
+
type CreateApiKeyInput = {
|
|
47
|
+
/** Optional custom prefix */
|
|
48
|
+
prefix?: string;
|
|
49
|
+
/** Optional custom length */
|
|
50
|
+
length?: number;
|
|
51
|
+
/** Metadata to associate with the key */
|
|
52
|
+
metadata: Partial<ApiKeyMetadata>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Audit log action types
|
|
57
|
+
*/
|
|
58
|
+
type AuditAction = "created" | "revoked" | "rotated" | "enabled" | "disabled";
|
|
59
|
+
/**
|
|
60
|
+
* Context for who performed an action
|
|
61
|
+
*/
|
|
62
|
+
type ActionContext = {
|
|
63
|
+
/** User ID who performed the action */
|
|
64
|
+
userId?: string;
|
|
65
|
+
/** IP address of the requester */
|
|
66
|
+
ip?: string;
|
|
67
|
+
/** User agent of the requester */
|
|
68
|
+
userAgent?: string;
|
|
69
|
+
/** Custom metadata about the action */
|
|
70
|
+
metadata?: Record<string, unknown>;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Audit log entry
|
|
74
|
+
*/
|
|
75
|
+
type AuditLog = {
|
|
76
|
+
/** Unique identifier for this log entry */
|
|
77
|
+
id: string;
|
|
78
|
+
/** The action that was performed */
|
|
79
|
+
action: AuditAction;
|
|
80
|
+
/** ID of the API key */
|
|
81
|
+
keyId: string;
|
|
82
|
+
/** ID of the key owner */
|
|
83
|
+
ownerId: string;
|
|
84
|
+
/** ISO timestamp when the action occurred */
|
|
85
|
+
timestamp: string;
|
|
86
|
+
/** Optional additional data about the action */
|
|
87
|
+
data?: Record<string, unknown>;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Options for querying audit logs
|
|
91
|
+
*/
|
|
92
|
+
type AuditLogQuery = {
|
|
93
|
+
/** Filter by key ID */
|
|
94
|
+
keyId?: string;
|
|
95
|
+
/** Filter by owner ID */
|
|
96
|
+
ownerId?: string;
|
|
97
|
+
/** Filter by action */
|
|
98
|
+
action?: AuditAction;
|
|
99
|
+
/** Filter by start date (ISO timestamp) */
|
|
100
|
+
startDate?: string;
|
|
101
|
+
/** Filter by end date (ISO timestamp) */
|
|
102
|
+
endDate?: string;
|
|
103
|
+
/** Maximum number of results to return (default: 100) */
|
|
104
|
+
limit?: number;
|
|
105
|
+
/** Offset for pagination (default: 0) */
|
|
106
|
+
offset?: number;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Statistics about audit logs
|
|
110
|
+
*/
|
|
111
|
+
type AuditLogStats = {
|
|
112
|
+
/** Total number of logs */
|
|
113
|
+
total: number;
|
|
114
|
+
/** Count by action type */
|
|
115
|
+
byAction: Partial<Record<AuditAction, number>>;
|
|
116
|
+
/** ISO timestamp of last activity */
|
|
117
|
+
lastActivity: string | null;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Storage interface for persisting API keys
|
|
122
|
+
*/
|
|
123
|
+
type Storage = {
|
|
124
|
+
/**
|
|
125
|
+
* Save an API key record to storage
|
|
126
|
+
*/
|
|
127
|
+
save(record: ApiKeyRecord): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Find an API key record by its hash
|
|
130
|
+
*/
|
|
131
|
+
findByHash(keyHash: string): Promise<ApiKeyRecord | null>;
|
|
132
|
+
/**
|
|
133
|
+
* Find an API key record by ID
|
|
134
|
+
*/
|
|
135
|
+
findById(id: string): Promise<ApiKeyRecord | null>;
|
|
136
|
+
/**
|
|
137
|
+
* Find all API keys for a specific owner
|
|
138
|
+
*/
|
|
139
|
+
findByOwner(ownerId: string): Promise<ApiKeyRecord[]>;
|
|
140
|
+
/**
|
|
141
|
+
* Find all API keys by tags and optionally by owner
|
|
142
|
+
* @param tags - Tags to search for
|
|
143
|
+
* @param ownerId - Optional owner ID to filter results
|
|
144
|
+
*/
|
|
145
|
+
findByTags(tags: string[], ownerId?: string): Promise<ApiKeyRecord[]>;
|
|
146
|
+
/**
|
|
147
|
+
* Find all API keys by tag and optionally by owner
|
|
148
|
+
* @param tag - Tag to search for
|
|
149
|
+
* @param ownerId - Optional owner ID to filter results
|
|
150
|
+
*/
|
|
151
|
+
findByTag(tag: string, ownerId?: string): Promise<ApiKeyRecord[]>;
|
|
152
|
+
/**
|
|
153
|
+
* Update metadata for an existing key
|
|
154
|
+
*/
|
|
155
|
+
updateMetadata(id: string, metadata: Partial<ApiKeyMetadata>): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Delete an API key record
|
|
158
|
+
*/
|
|
159
|
+
delete(id: string): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Delete all keys for a specific owner
|
|
162
|
+
*/
|
|
163
|
+
deleteByOwner(ownerId: string): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Save an audit log entry (optional, only if audit logging is enabled)
|
|
166
|
+
*/
|
|
167
|
+
saveLog?(log: AuditLog): Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Query audit logs (optional, only if audit logging is enabled)
|
|
170
|
+
*/
|
|
171
|
+
findLogs?(query: AuditLogQuery): Promise<AuditLog[]>;
|
|
172
|
+
/**
|
|
173
|
+
* Count audit logs matching query (optional, only if audit logging is enabled)
|
|
174
|
+
*/
|
|
175
|
+
countLogs?(query: AuditLogQuery): Promise<number>;
|
|
176
|
+
/**
|
|
177
|
+
* Delete audit logs matching query (optional, only if audit logging is enabled)
|
|
178
|
+
* @returns Number of logs deleted
|
|
179
|
+
*/
|
|
180
|
+
deleteLogs?(query: AuditLogQuery): Promise<number>;
|
|
181
|
+
/**
|
|
182
|
+
* Get statistics about audit logs (optional, only if audit logging is enabled)
|
|
183
|
+
*/
|
|
184
|
+
getLogStats?(ownerId: string): Promise<AuditLogStats>;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Options for storage operations
|
|
188
|
+
*/
|
|
189
|
+
type StorageOptions = {
|
|
190
|
+
/** Optional TTL (time to live) in seconds */
|
|
191
|
+
ttl?: number;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export type { ActionContext as A, CreateApiKeyInput as C, Storage as S, ApiKeyRecord as a, ApiKeyMetadata as b, AuditLogQuery as c, AuditLog as d, AuditLogStats as e, AuditAction as f, StorageOptions as g };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @donotlb/keypal v0.1.0
|
|
3
|
+
* A TypeScript library for secure API key management with cryptographic hashing, expiration, scopes, and pluggable storage
|
|
4
|
+
* © 2026 "donotlb" <donotlb@gmail.com>
|
|
5
|
+
* Released under the MIT License
|
|
6
|
+
* https://github.com/donotlb/keypal#readme
|
|
7
|
+
*/import{customAlphabet as n}from"nanoid";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",l=32,a=n(i,l);function f(o={}){const{prefix:e="",length:r=32,alphabet:s=i}=o,t=r===l&&s===i?a():n(s,r)();return e?`${e}${t}`:t}class h{level;prefix;silent;constructor(e={}){this.level=e.level??"info",this.prefix=e.prefix??"",this.silent=e.silent??!1}shouldLog(e){if(this.silent)return!1;const r=["debug","info","warn","error"],s=r.indexOf(this.level);return r.indexOf(e)>=s}formatMessage(e,r){const s=this.prefix?`[${this.prefix}]`:"",t=e.toUpperCase();return`${s} ${t}: ${r}`}debug(e,...r){this.shouldLog("debug")&&console.debug(this.formatMessage("debug",e),...r)}info(e,...r){this.shouldLog("info")&&console.info(this.formatMessage("info",e),...r)}warn(e,...r){this.shouldLog("warn")&&console.warn(this.formatMessage("warn",e),...r)}error(e,...r){this.shouldLog("error")&&console.error(this.formatMessage("error",e),...r)}}function g(o){return new h(o)}const u=g({prefix:"keypal"});export{f as g,u as l};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { S as Storage, a as ApiKeyRecord, b as ApiKeyMetadata, d as AuditLog, c as AuditLogQuery, e as AuditLogStats } from '../shared/keypal.kItV-5pB.mjs';
|
|
2
|
+
import 'typebox';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Column mapping for API keys table
|
|
6
|
+
*/
|
|
7
|
+
type ApiKeyColumnMapping = {
|
|
8
|
+
/** Column name for the key ID (default: 'id') */
|
|
9
|
+
id?: string;
|
|
10
|
+
/** Column name for the hashed key (default: 'keyHash') */
|
|
11
|
+
keyHash?: string;
|
|
12
|
+
/** Column name for the metadata (default: 'metadata') */
|
|
13
|
+
metadata?: string;
|
|
14
|
+
/** Custom columns mapping for metadata fields */
|
|
15
|
+
metadataColumns?: {
|
|
16
|
+
ownerId?: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
scopes?: string;
|
|
20
|
+
resources?: string;
|
|
21
|
+
rateLimit?: string;
|
|
22
|
+
expiresAt?: string;
|
|
23
|
+
revokedAt?: string;
|
|
24
|
+
lastUsedAt?: string;
|
|
25
|
+
createdAt?: string;
|
|
26
|
+
tags?: string;
|
|
27
|
+
allowedIps?: string;
|
|
28
|
+
allowedOrigins?: string;
|
|
29
|
+
[key: string]: string | undefined;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Column mapping for audit logs table
|
|
34
|
+
*/
|
|
35
|
+
type AuditLogColumnMapping = {
|
|
36
|
+
id?: string;
|
|
37
|
+
keyId?: string;
|
|
38
|
+
ownerId?: string;
|
|
39
|
+
action?: string;
|
|
40
|
+
timestamp?: string;
|
|
41
|
+
data?: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Schema configuration for both tables
|
|
45
|
+
*/
|
|
46
|
+
type SchemaConfig = {
|
|
47
|
+
/** Table name for API keys (default: 'apikey' or 'apikeys') */
|
|
48
|
+
apiKeyTable?: string;
|
|
49
|
+
/** Column mappings for API keys table */
|
|
50
|
+
apiKeyColumns?: ApiKeyColumnMapping;
|
|
51
|
+
/** Table name for audit logs (default: 'auditlog' or 'auditlogs') */
|
|
52
|
+
auditLogTable?: string;
|
|
53
|
+
/** Column mappings for audit logs table */
|
|
54
|
+
auditLogColumns?: AuditLogColumnMapping;
|
|
55
|
+
/** Whether to use flattened schema (metadata as separate columns) */
|
|
56
|
+
flattenMetadata?: boolean;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Generic database interface for Drizzle
|
|
61
|
+
* Supports any Drizzle database type (PostgreSQL, MySQL, SQLite)
|
|
62
|
+
*/
|
|
63
|
+
interface DrizzleDB {
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Generic table interface for Drizzle
|
|
68
|
+
*/
|
|
69
|
+
interface DrizzleTable {
|
|
70
|
+
[key: string]: any;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Configuration for Drizzle adapter
|
|
74
|
+
*/
|
|
75
|
+
interface DrizzleAdapterConfig {
|
|
76
|
+
/**
|
|
77
|
+
* The Drizzle database instance
|
|
78
|
+
* Supports PostgreSQL, MySQL, and SQLite
|
|
79
|
+
*/
|
|
80
|
+
db: DrizzleDB;
|
|
81
|
+
/**
|
|
82
|
+
* The table for API keys
|
|
83
|
+
*/
|
|
84
|
+
table: DrizzleTable;
|
|
85
|
+
/**
|
|
86
|
+
* The database provider
|
|
87
|
+
* Used for provider-specific optimizations
|
|
88
|
+
*/
|
|
89
|
+
provider?: "pg" | "mysql" | "sqlite";
|
|
90
|
+
/**
|
|
91
|
+
* Schema configuration for custom column names and flattened metadata
|
|
92
|
+
*/
|
|
93
|
+
schema?: SchemaConfig;
|
|
94
|
+
/**
|
|
95
|
+
* Optional table for audit logs
|
|
96
|
+
*/
|
|
97
|
+
auditLogTable?: DrizzleTable;
|
|
98
|
+
/**
|
|
99
|
+
* Enable debug logging
|
|
100
|
+
* @default false
|
|
101
|
+
*/
|
|
102
|
+
debugLogs?: boolean;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create a Drizzle storage adapter for API keys
|
|
106
|
+
*
|
|
107
|
+
* **Supports:**
|
|
108
|
+
* - PostgreSQL, MySQL, and SQLite
|
|
109
|
+
* - Custom column names
|
|
110
|
+
* - Custom table names
|
|
111
|
+
* - Flattened metadata schema
|
|
112
|
+
* - JSON/JSONB columns
|
|
113
|
+
* - Audit logging
|
|
114
|
+
*
|
|
115
|
+
* **Required Table Columns (default schema):**
|
|
116
|
+
* - `id`: TEXT PRIMARY KEY
|
|
117
|
+
* - `keyHash`: TEXT
|
|
118
|
+
* - `metadata`: JSONB (or TEXT for MySQL/SQLite)
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* // Default schema (PostgreSQL)
|
|
123
|
+
* import { createDrizzleStore } from 'keypal/drizzle';
|
|
124
|
+
* import { apikey } from 'keypal/drizzle/schema';
|
|
125
|
+
* const store = createDrizzleStore({ db, table: apikey, provider: 'pg' });
|
|
126
|
+
*
|
|
127
|
+
* // MySQL with custom column names
|
|
128
|
+
* const store = createDrizzleStore({
|
|
129
|
+
* db,
|
|
130
|
+
* table: customTable,
|
|
131
|
+
* provider: 'mysql',
|
|
132
|
+
* schema: {
|
|
133
|
+
* apiKeyColumns: {
|
|
134
|
+
* id: 'key_id',
|
|
135
|
+
* keyHash: 'key_hash',
|
|
136
|
+
* metadata: 'key_metadata'
|
|
137
|
+
* }
|
|
138
|
+
* }
|
|
139
|
+
* });
|
|
140
|
+
*
|
|
141
|
+
* // SQLite with flattened metadata
|
|
142
|
+
* const store = createDrizzleStore({
|
|
143
|
+
* db,
|
|
144
|
+
* table: flatTable,
|
|
145
|
+
* provider: 'sqlite',
|
|
146
|
+
* schema: {
|
|
147
|
+
* flattenMetadata: true,
|
|
148
|
+
* apiKeyColumns: {
|
|
149
|
+
* metadataColumns: {
|
|
150
|
+
* ownerId: 'owner_id',
|
|
151
|
+
* name: 'key_name',
|
|
152
|
+
* scopes: 'key_scopes'
|
|
153
|
+
* }
|
|
154
|
+
* }
|
|
155
|
+
* }
|
|
156
|
+
* });
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
declare function createDrizzleStore(options: DrizzleAdapterConfig): Storage;
|
|
160
|
+
/**
|
|
161
|
+
* Storage adapter class for Drizzle ORM
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const store = new DrizzleStore({ db, table: apikey, provider: 'pg' });
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
declare class DrizzleStore implements Storage {
|
|
169
|
+
private readonly storage;
|
|
170
|
+
constructor(options: DrizzleAdapterConfig);
|
|
171
|
+
save: (record: ApiKeyRecord) => Promise<void>;
|
|
172
|
+
findByHash: (keyHash: string) => Promise<ApiKeyRecord | null>;
|
|
173
|
+
findById: (id: string) => Promise<ApiKeyRecord | null>;
|
|
174
|
+
findByOwner: (ownerId: string) => Promise<ApiKeyRecord[]>;
|
|
175
|
+
findByTags: (tags: string[], ownerId?: string) => Promise<ApiKeyRecord[]>;
|
|
176
|
+
findByTag: (tag: string, ownerId?: string) => Promise<ApiKeyRecord[]>;
|
|
177
|
+
updateMetadata: (id: string, metadata: Partial<ApiKeyMetadata>) => Promise<void>;
|
|
178
|
+
delete: (id: string) => Promise<void>;
|
|
179
|
+
deleteByOwner: (ownerId: string) => Promise<void>;
|
|
180
|
+
saveLog: (log: AuditLog) => Promise<void>;
|
|
181
|
+
findLogs: (query: AuditLogQuery) => Promise<AuditLog[]>;
|
|
182
|
+
countLogs: (query: AuditLogQuery) => Promise<number>;
|
|
183
|
+
deleteLogs: (query: AuditLogQuery) => Promise<number>;
|
|
184
|
+
getLogStats: (ownerId: string) => Promise<AuditLogStats> | Promise<{
|
|
185
|
+
total: number;
|
|
186
|
+
byAction: {};
|
|
187
|
+
lastActivity: null;
|
|
188
|
+
}>;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { DrizzleStore, createDrizzleStore };
|
|
192
|
+
export type { DrizzleAdapterConfig, DrizzleDB, DrizzleTable };
|