@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.
@@ -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 };