@geekmidas/testkit 9.0.2 → 10.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/{Factory-CUM2767q.d.cts → Factory-C6W78ulZ.d.mts} +2 -2
  2. package/dist/{Factory-ClyZLRsO.d.mts.map → Factory-C6W78ulZ.d.mts.map} +1 -1
  3. package/dist/{Factory-ClyZLRsO.d.mts → Factory-DSEADOaF.d.cts} +2 -2
  4. package/dist/{Factory-CUM2767q.d.cts.map → Factory-DSEADOaF.d.cts.map} +1 -1
  5. package/dist/Factory.d.cts +2 -2
  6. package/dist/Factory.d.mts +2 -2
  7. package/dist/{KyselyFactory-OMwcuAX_.d.cts → KyselyFactory-Cc2UmOJk.d.mts} +3 -3
  8. package/dist/{KyselyFactory-CTZmiGI9.d.mts.map → KyselyFactory-Cc2UmOJk.d.mts.map} +1 -1
  9. package/dist/{KyselyFactory-CTZmiGI9.d.mts → KyselyFactory-DzH0N1zr.d.cts} +3 -3
  10. package/dist/{KyselyFactory-OMwcuAX_.d.cts.map → KyselyFactory-DzH0N1zr.d.cts.map} +1 -1
  11. package/dist/KyselyFactory.d.cts +3 -3
  12. package/dist/KyselyFactory.d.mts +3 -3
  13. package/dist/{ObjectionFactory-DDrKwAoO.d.mts → ObjectionFactory-BYnPr9ZP.d.mts} +3 -3
  14. package/dist/{ObjectionFactory-DDrKwAoO.d.mts.map → ObjectionFactory-BYnPr9ZP.d.mts.map} +1 -1
  15. package/dist/{ObjectionFactory-DvmZVHhe.d.cts → ObjectionFactory-BmKdG0nT.d.cts} +3 -3
  16. package/dist/{ObjectionFactory-DvmZVHhe.d.cts.map → ObjectionFactory-BmKdG0nT.d.cts.map} +1 -1
  17. package/dist/ObjectionFactory.d.cts +3 -3
  18. package/dist/ObjectionFactory.d.mts +3 -3
  19. package/dist/{VitestKyselyTransactionIsolator-CfSMOFlN.mjs → VitestKyselyTransactionIsolator-1Saieke7.mjs} +10 -3
  20. package/dist/VitestKyselyTransactionIsolator-1Saieke7.mjs.map +1 -0
  21. package/dist/{VitestKyselyTransactionIsolator-0CqOsuc9.cjs → VitestKyselyTransactionIsolator-BjJSXryR.cjs} +10 -3
  22. package/dist/VitestKyselyTransactionIsolator-BjJSXryR.cjs.map +1 -0
  23. package/dist/{VitestKyselyTransactionIsolator-CduJlHoT.d.cts → VitestKyselyTransactionIsolator-CwlTo6yf.d.mts} +8 -3
  24. package/dist/VitestKyselyTransactionIsolator-CwlTo6yf.d.mts.map +1 -0
  25. package/dist/{VitestKyselyTransactionIsolator-Cswnnj0k.d.mts → VitestKyselyTransactionIsolator-DJasVuIZ.d.cts} +8 -3
  26. package/dist/VitestKyselyTransactionIsolator-DJasVuIZ.d.cts.map +1 -0
  27. package/dist/VitestKyselyTransactionIsolator.cjs +2 -2
  28. package/dist/VitestKyselyTransactionIsolator.d.cts +2 -2
  29. package/dist/VitestKyselyTransactionIsolator.d.mts +2 -2
  30. package/dist/VitestKyselyTransactionIsolator.mjs +2 -2
  31. package/dist/{VitestObjectionTransactionIsolator-CNo40EdC.mjs → VitestObjectionTransactionIsolator-B_VSWFum.mjs} +2 -2
  32. package/dist/{VitestObjectionTransactionIsolator-CNo40EdC.mjs.map → VitestObjectionTransactionIsolator-B_VSWFum.mjs.map} +1 -1
  33. package/dist/{VitestObjectionTransactionIsolator-BXoR6xdG.d.cts → VitestObjectionTransactionIsolator-CTTjvTPO.d.cts} +2 -2
  34. package/dist/{VitestObjectionTransactionIsolator-BXoR6xdG.d.cts.map → VitestObjectionTransactionIsolator-CTTjvTPO.d.cts.map} +1 -1
  35. package/dist/{VitestObjectionTransactionIsolator-x6hY5j4u.d.mts → VitestObjectionTransactionIsolator-CyZG6nq4.d.mts} +2 -2
  36. package/dist/{VitestObjectionTransactionIsolator-x6hY5j4u.d.mts.map → VitestObjectionTransactionIsolator-CyZG6nq4.d.mts.map} +1 -1
  37. package/dist/{VitestObjectionTransactionIsolator-B5J9jjKq.cjs → VitestObjectionTransactionIsolator-DDoJTu7e.cjs} +2 -2
  38. package/dist/{VitestObjectionTransactionIsolator-B5J9jjKq.cjs.map → VitestObjectionTransactionIsolator-DDoJTu7e.cjs.map} +1 -1
  39. package/dist/VitestObjectionTransactionIsolator.cjs +2 -2
  40. package/dist/VitestObjectionTransactionIsolator.d.cts +2 -2
  41. package/dist/VitestObjectionTransactionIsolator.d.mts +2 -2
  42. package/dist/VitestObjectionTransactionIsolator.mjs +2 -2
  43. package/dist/{VitestTransactionIsolator-BNWJqh9f.d.mts → VitestTransactionIsolator-BLaw80cx.d.mts} +20 -4
  44. package/dist/VitestTransactionIsolator-BLaw80cx.d.mts.map +1 -0
  45. package/dist/{VitestTransactionIsolator-D6ZxLWys.mjs → VitestTransactionIsolator-CvwPecpl.mjs} +17 -4
  46. package/dist/VitestTransactionIsolator-CvwPecpl.mjs.map +1 -0
  47. package/dist/{VitestTransactionIsolator-CtZaOUjH.cjs → VitestTransactionIsolator-DyiX-QtK.cjs} +17 -4
  48. package/dist/VitestTransactionIsolator-DyiX-QtK.cjs.map +1 -0
  49. package/dist/{VitestTransactionIsolator-CSroc7Df.d.cts → VitestTransactionIsolator-glcxyS_R.d.cts} +20 -4
  50. package/dist/VitestTransactionIsolator-glcxyS_R.d.cts.map +1 -0
  51. package/dist/VitestTransactionIsolator.cjs +1 -1
  52. package/dist/VitestTransactionIsolator.d.cts +2 -2
  53. package/dist/VitestTransactionIsolator.d.mts +2 -2
  54. package/dist/VitestTransactionIsolator.mjs +1 -1
  55. package/dist/better-auth.d.cts +2 -2
  56. package/dist/better-auth.d.mts +2 -2
  57. package/dist/{faker-BcjUfHxx.d.mts → faker-D9gz7KjY.d.mts} +3 -3
  58. package/dist/{faker-BcjUfHxx.d.mts.map → faker-D9gz7KjY.d.mts.map} +1 -1
  59. package/dist/{faker-zVCm31nU.d.cts → faker-km9UhOS6.d.cts} +3 -3
  60. package/dist/{faker-zVCm31nU.d.cts.map → faker-km9UhOS6.d.cts.map} +1 -1
  61. package/dist/faker.d.cts +1 -1
  62. package/dist/faker.d.mts +1 -1
  63. package/dist/kysely.cjs +2 -2
  64. package/dist/kysely.d.cts +5 -5
  65. package/dist/kysely.d.mts +5 -5
  66. package/dist/kysely.mjs +2 -2
  67. package/dist/objection.cjs +2 -2
  68. package/dist/objection.d.cts +5 -5
  69. package/dist/objection.d.mts +5 -5
  70. package/dist/objection.mjs +2 -2
  71. package/dist/requestContext.cjs +1 -1
  72. package/dist/requestContext.d.cts +1 -1
  73. package/dist/requestContext.d.mts +1 -1
  74. package/dist/requestContext.mjs +1 -1
  75. package/package.json +10 -7
  76. package/CHANGELOG.md +0 -151
  77. package/dist/VitestKyselyTransactionIsolator-0CqOsuc9.cjs.map +0 -1
  78. package/dist/VitestKyselyTransactionIsolator-CduJlHoT.d.cts.map +0 -1
  79. package/dist/VitestKyselyTransactionIsolator-CfSMOFlN.mjs.map +0 -1
  80. package/dist/VitestKyselyTransactionIsolator-Cswnnj0k.d.mts.map +0 -1
  81. package/dist/VitestTransactionIsolator-BNWJqh9f.d.mts.map +0 -1
  82. package/dist/VitestTransactionIsolator-CSroc7Df.d.cts.map +0 -1
  83. package/dist/VitestTransactionIsolator-CtZaOUjH.cjs.map +0 -1
  84. package/dist/VitestTransactionIsolator-D6ZxLWys.mjs.map +0 -1
  85. package/src/Factory.ts +0 -174
  86. package/src/KyselyFactory.ts +0 -391
  87. package/src/ObjectionFactory.ts +0 -412
  88. package/src/PostgresKyselyMigrator.ts +0 -104
  89. package/src/PostgresMigrator.ts +0 -193
  90. package/src/PostgresObjectionMigrator.ts +0 -138
  91. package/src/VitestKyselyTransactionIsolator.ts +0 -72
  92. package/src/VitestObjectionTransactionIsolator.ts +0 -75
  93. package/src/VitestTransactionIsolator.ts +0 -348
  94. package/src/__tests__/Factory.spec.ts +0 -178
  95. package/src/__tests__/KyselyFactory.spec.ts +0 -458
  96. package/src/__tests__/ObjectionFactory.spec.ts +0 -586
  97. package/src/__tests__/PostgresKyselyMigrator.spec.ts +0 -794
  98. package/src/__tests__/PostgresMigrator.spec.ts +0 -471
  99. package/src/__tests__/PostgresObjectionMigrator.spec.ts +0 -634
  100. package/src/__tests__/VitestObjectionTransactionIsolator.spec.ts +0 -138
  101. package/src/__tests__/benchmark.spec.ts +0 -140
  102. package/src/__tests__/better-auth.spec.ts +0 -21
  103. package/src/__tests__/faker.spec.ts +0 -231
  104. package/src/__tests__/initScript.spec.ts +0 -332
  105. package/src/__tests__/integration.spec.ts +0 -610
  106. package/src/__tests__/requestContext.spec.ts +0 -113
  107. package/src/__tests__/utilities.spec.ts +0 -211
  108. package/src/aws.ts +0 -131
  109. package/src/benchmark.ts +0 -48
  110. package/src/better-auth.ts +0 -310
  111. package/src/faker.ts +0 -349
  112. package/src/helpers.ts +0 -45
  113. package/src/initScript.ts +0 -122
  114. package/src/kysely.ts +0 -166
  115. package/src/logger.ts +0 -18
  116. package/src/objection.ts +0 -157
  117. package/src/os/directory.ts +0 -26
  118. package/src/os/index.ts +0 -1
  119. package/src/requestContext.ts +0 -119
  120. package/src/timer.ts +0 -3
  121. package/test/globalSetup.ts +0 -54
  122. package/test/helpers.ts +0 -268
  123. package/test/migrations/1749664623372_user.ts +0 -22
  124. package/tsconfig.json +0 -9
  125. package/vitest.config.ts +0 -8
@@ -1,211 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { describe, expect, it } from 'vitest';
4
- import {
5
- createMockContext,
6
- createMockV1Event,
7
- createMockV2Event,
8
- } from '../aws';
9
- import { createMockLogger } from '../logger';
10
- import { itWithDir } from '../os/directory';
11
- import { waitFor } from '../timer';
12
-
13
- describe('testkit utilities', () => {
14
- describe('createMockLogger', () => {
15
- it('should create a logger with all required methods', () => {
16
- const logger = createMockLogger();
17
-
18
- expect(logger.debug).toBeDefined();
19
- expect(logger.info).toBeDefined();
20
- expect(logger.warn).toBeDefined();
21
- expect(logger.error).toBeDefined();
22
- expect(logger.fatal).toBeDefined();
23
- expect(logger.trace).toBeDefined();
24
- expect(logger.child).toBeDefined();
25
- });
26
-
27
- it('should have mock functions that can be called', () => {
28
- const logger = createMockLogger();
29
-
30
- logger.debug('debug message');
31
- logger.info({ data: 'test' }, 'info message');
32
- logger.warn('warning');
33
- logger.error('error');
34
- logger.fatal('fatal');
35
- logger.trace('trace');
36
-
37
- expect(logger.debug).toHaveBeenCalledWith('debug message');
38
- expect(logger.info).toHaveBeenCalledWith(
39
- { data: 'test' },
40
- 'info message',
41
- );
42
- expect(logger.warn).toHaveBeenCalledWith('warning');
43
- expect(logger.error).toHaveBeenCalledWith('error');
44
- expect(logger.fatal).toHaveBeenCalledWith('fatal');
45
- expect(logger.trace).toHaveBeenCalledWith('trace');
46
- });
47
-
48
- it('should return itself from child()', () => {
49
- const logger = createMockLogger();
50
- const childLogger = logger.child({ module: 'test' });
51
-
52
- expect(childLogger).toBe(logger);
53
- expect(logger.child).toHaveBeenCalledWith({ module: 'test' });
54
- });
55
- });
56
-
57
- describe('waitFor', () => {
58
- it('should wait for the specified time', async () => {
59
- const start = Date.now();
60
- await waitFor(50);
61
- const elapsed = Date.now() - start;
62
-
63
- expect(elapsed).toBeGreaterThanOrEqual(40);
64
- expect(elapsed).toBeLessThan(150);
65
- });
66
-
67
- it('should resolve without a value', async () => {
68
- const result = await waitFor(10);
69
- expect(result).toBeUndefined();
70
- });
71
- });
72
-
73
- describe('AWS mock utilities', () => {
74
- describe('createMockContext', () => {
75
- it('should create a valid Lambda context', () => {
76
- const context = createMockContext();
77
-
78
- expect(context.awsRequestId).toBe('test-request-id');
79
- expect(context.functionName).toBe('test-function');
80
- expect(context.functionVersion).toBe('1');
81
- expect(context.memoryLimitInMB).toBe('128');
82
- expect(context.logGroupName).toBe('/aws/lambda/test-function');
83
- expect(context.invokedFunctionArn).toContain('arn:aws:lambda');
84
- });
85
-
86
- it('should have mock callback functions', () => {
87
- const context = createMockContext();
88
-
89
- expect(context.done).toBeDefined();
90
- expect(context.fail).toBeDefined();
91
- expect(context.succeed).toBeDefined();
92
-
93
- context.done();
94
- context.fail(new Error('test'));
95
- context.succeed('result');
96
-
97
- expect(context.done).toHaveBeenCalled();
98
- expect(context.fail).toHaveBeenCalled();
99
- expect(context.succeed).toHaveBeenCalled();
100
- });
101
-
102
- it('should return remaining time', () => {
103
- const context = createMockContext();
104
- const remaining = context.getRemainingTimeInMillis();
105
-
106
- expect(remaining).toBe(5000);
107
- });
108
- });
109
-
110
- describe('createMockV1Event', () => {
111
- it('should create a valid API Gateway V1 event', () => {
112
- const event = createMockV1Event();
113
-
114
- expect(event.httpMethod).toBe('GET');
115
- expect(event.path).toBe('/test');
116
- expect(event.headers['content-type']).toBe('application/json');
117
- expect(event.requestContext.accountId).toBe('123456789012');
118
- expect(event.requestContext.stage).toBe('test');
119
- });
120
-
121
- it('should allow overriding properties', () => {
122
- const event = createMockV1Event({
123
- httpMethod: 'POST',
124
- path: '/users',
125
- body: JSON.stringify({ name: 'test' }),
126
- pathParameters: { id: '123' },
127
- queryStringParameters: { page: '1' },
128
- });
129
-
130
- expect(event.httpMethod).toBe('POST');
131
- expect(event.path).toBe('/users');
132
- expect(event.body).toBe(JSON.stringify({ name: 'test' }));
133
- expect(event.pathParameters).toEqual({ id: '123' });
134
- expect(event.queryStringParameters).toEqual({ page: '1' });
135
- });
136
-
137
- it('should have correct identity fields', () => {
138
- const event = createMockV1Event();
139
-
140
- expect(event.requestContext.identity.sourceIp).toBe('127.0.0.1');
141
- expect(event.requestContext.identity.userAgent).toBe('test-agent');
142
- });
143
- });
144
-
145
- describe('createMockV2Event', () => {
146
- it('should create a valid API Gateway V2 event', () => {
147
- const event = createMockV2Event();
148
-
149
- expect(event.version).toBe('2.0');
150
- expect(event.routeKey).toBe('GET /test');
151
- expect(event.rawPath).toBe('/test');
152
- expect(event.headers['content-type']).toBe('application/json');
153
- expect(event.requestContext.accountId).toBe('123456789012');
154
- });
155
-
156
- it('should allow overriding properties', () => {
157
- const event = createMockV2Event({
158
- routeKey: 'POST /users',
159
- rawPath: '/users',
160
- body: JSON.stringify({ name: 'test' }),
161
- pathParameters: { id: '123' },
162
- queryStringParameters: { page: '1' },
163
- });
164
-
165
- expect(event.routeKey).toBe('POST /users');
166
- expect(event.rawPath).toBe('/users');
167
- expect(event.body).toBe(JSON.stringify({ name: 'test' }));
168
- expect(event.pathParameters).toEqual({ id: '123' });
169
- expect(event.queryStringParameters).toEqual({ page: '1' });
170
- });
171
-
172
- it('should have correct HTTP context', () => {
173
- const event = createMockV2Event();
174
-
175
- expect(event.requestContext.http.method).toBe('GET');
176
- expect(event.requestContext.http.path).toBe('/test');
177
- expect(event.requestContext.http.sourceIp).toBe('127.0.0.1');
178
- expect(event.requestContext.http.userAgent).toBe('test-agent');
179
- });
180
- });
181
- });
182
-
183
- describe('itWithDir', () => {
184
- itWithDir('should provide a temporary directory', async ({ dir }) => {
185
- expect(dir).toBeDefined();
186
- expect(typeof dir).toBe('string');
187
-
188
- // Directory should exist
189
- const stat = await fs.stat(dir);
190
- expect(stat.isDirectory()).toBe(true);
191
- });
192
-
193
- itWithDir(
194
- 'should allow creating files in the directory',
195
- async ({ dir }) => {
196
- const testFile = path.join(dir, 'test.txt');
197
- await fs.writeFile(testFile, 'hello');
198
-
199
- const content = await fs.readFile(testFile, 'utf-8');
200
- expect(content).toBe('hello');
201
- },
202
- );
203
-
204
- itWithDir('should provide unique directories per test', async ({ dir }) => {
205
- // The directory should have a UUID-like name (uppercase hex)
206
- const dirName = path.basename(dir);
207
- expect(dirName).toMatch(/^[A-F0-9]{32}$/);
208
- expect(dir.length).toBeGreaterThan(10);
209
- });
210
- });
211
- });
package/src/aws.ts DELETED
@@ -1,131 +0,0 @@
1
- import type {
2
- APIGatewayProxyEvent,
3
- APIGatewayProxyEventV2,
4
- Context,
5
- } from 'aws-lambda';
6
- import { vi } from 'vitest';
7
-
8
- /**
9
- * Shared test utilities for AWS Lambda adapter testing
10
- */
11
-
12
- /**
13
- * Creates a mock AWS Lambda Context for testing
14
- */
15
- export function createMockContext(): Context {
16
- return {
17
- awsRequestId: 'test-request-id',
18
- callbackWaitsForEmptyEventLoop: false,
19
- functionName: 'test-function',
20
- functionVersion: '1',
21
- invokedFunctionArn:
22
- 'arn:aws:lambda:us-east-1:123456789012:function:test-function',
23
- memoryLimitInMB: '128',
24
- logGroupName: '/aws/lambda/test-function',
25
- logStreamName: '2024/01/01/[$LATEST]abcdef123456',
26
- getRemainingTimeInMillis: () => 5000,
27
- done: vi.fn(),
28
- fail: vi.fn(),
29
- succeed: vi.fn(),
30
- };
31
- }
32
-
33
- /**
34
- * Creates a mock AWS API Gateway V1 (REST API) event for testing
35
- */
36
- export function createMockV1Event(
37
- overrides: Partial<APIGatewayProxyEvent> = {},
38
- ): APIGatewayProxyEvent {
39
- return {
40
- body: null,
41
- headers: {
42
- 'content-type': 'application/json',
43
- 'user-agent': 'test-agent',
44
- host: 'test.example.com',
45
- },
46
- multiValueHeaders: {},
47
- httpMethod: 'GET',
48
- isBase64Encoded: false,
49
- path: '/test',
50
- pathParameters: null,
51
- queryStringParameters: null,
52
- multiValueQueryStringParameters: null,
53
- stageVariables: null,
54
- requestContext: {
55
- accountId: '123456789012',
56
- apiId: 'api-id',
57
- authorizer: null,
58
- protocol: 'HTTP/1.1',
59
- httpMethod: 'GET',
60
- path: '/test',
61
- stage: 'test',
62
- requestId: 'request-id',
63
- requestTimeEpoch: 1704067200000,
64
- resourceId: 'resource-id',
65
- resourcePath: '/test',
66
- identity: {
67
- accessKey: null,
68
- accountId: null,
69
- apiKey: null,
70
- apiKeyId: null,
71
- caller: null,
72
- cognitoAuthenticationProvider: null,
73
- cognitoAuthenticationType: null,
74
- cognitoIdentityId: null,
75
- cognitoIdentityPoolId: null,
76
- principalOrgId: null,
77
- sourceIp: '127.0.0.1',
78
- user: null,
79
- userAgent: 'test-agent',
80
- userArn: null,
81
- clientCert: null,
82
- },
83
- },
84
- resource: '/test',
85
- ...overrides,
86
- };
87
- }
88
-
89
- /**
90
- * Creates a mock AWS API Gateway V2 (HTTP API) event for testing
91
- */
92
- export function createMockV2Event(
93
- overrides: Partial<APIGatewayProxyEventV2> = {},
94
- ): APIGatewayProxyEventV2 {
95
- return {
96
- version: '2.0',
97
- routeKey: 'GET /test',
98
- rawPath: '/test',
99
- rawQueryString: '',
100
- headers: {
101
- 'content-type': 'application/json',
102
- 'user-agent': 'test-agent',
103
- host: 'test.example.com',
104
- },
105
- requestContext: {
106
- accountId: '123456789012',
107
- apiId: 'api-id',
108
- domainName: 'test.example.com',
109
- domainPrefix: 'api',
110
- requestId: 'request-id',
111
- routeKey: 'GET /test',
112
- stage: 'test',
113
- time: '01/Jan/2024:00:00:00 +0000',
114
- timeEpoch: 1704067200000,
115
- http: {
116
- method: 'GET',
117
- path: '/test',
118
- protocol: 'HTTP/1.1',
119
- sourceIp: '127.0.0.1',
120
- userAgent: 'test-agent',
121
- },
122
- },
123
- body: undefined,
124
- pathParameters: undefined,
125
- isBase64Encoded: false,
126
- stageVariables: undefined,
127
- queryStringParameters: undefined,
128
- cookies: undefined,
129
- ...overrides,
130
- };
131
- }
package/src/benchmark.ts DELETED
@@ -1,48 +0,0 @@
1
- /**
2
- * Generates an array of test records for benchmark data sets.
3
- *
4
- * @param count - Number of records to generate
5
- * @returns Array of test data objects
6
- */
7
- export function generateTestData(
8
- count: number,
9
- ): Array<{ id: string; name: string; value: number }> {
10
- return Array.from({ length: count }, (_, i) => ({
11
- id: `id-${i}`,
12
- name: `Item ${i}`,
13
- value: Math.random() * 1000,
14
- }));
15
- }
16
-
17
- /**
18
- * Generates unique keys for cache benchmarks to avoid collisions.
19
- *
20
- * @param prefix - Key prefix
21
- * @param count - Number of keys to generate
22
- * @returns Array of unique cache keys
23
- */
24
- export function generateCacheKeys(prefix: string, count: number): string[] {
25
- return Array.from({ length: count }, (_, i) => `${prefix}:${i}`);
26
- }
27
-
28
- /**
29
- * Generates IP addresses for rate limit benchmarks.
30
- *
31
- * @param count - Number of IPs to generate
32
- * @param subnet - Subnet prefix (default: '192.168.1')
33
- * @returns Array of IP addresses
34
- */
35
- export function generateIpAddresses(
36
- count: number,
37
- subnet: string = '192.168.1',
38
- ): string[] {
39
- return Array.from({ length: count }, (_, i) => `${subnet}.${i % 256}`);
40
- }
41
-
42
- /**
43
- * Creates a random IP address for rate limit benchmarks.
44
- */
45
- export function randomIpAddress(): string {
46
- const octet = () => Math.floor(Math.random() * 256);
47
- return `${octet()}.${octet()}.${octet()}.${octet()}`;
48
- }
@@ -1,310 +0,0 @@
1
- import {
2
- createAdapterFactory,
3
- type DBAdapterDebugLogOption,
4
- type Where,
5
- } from 'better-auth/adapters';
6
-
7
- interface MemoryAdapterConfig {
8
- debugLogs?: DBAdapterDebugLogOption;
9
- usePlural?: boolean;
10
- initialData?: Record<string, any[]>;
11
- }
12
-
13
- class MemoryStore {
14
- constructor(
15
- initialData?: Record<string, any[]>,
16
- private readonly data: Map<string, any> = new Map(),
17
- ) {
18
- if (initialData) {
19
- for (const [model, records] of Object.entries(initialData)) {
20
- const modelData = new Map();
21
- for (const record of records) {
22
- modelData.set(record.id, { ...record });
23
- }
24
- this.data.set(model, modelData);
25
- }
26
- }
27
- }
28
-
29
- getModel(modelName: string): Map<string, any> {
30
- if (!this.data.has(modelName)) {
31
- this.data.set(modelName, new Map());
32
- }
33
- return this.data.get(modelName)!;
34
- }
35
-
36
- clear() {
37
- this.data.clear();
38
- }
39
-
40
- getAllData() {
41
- const result: Record<string, any[]> = {};
42
- for (const [model, records] of this.data.entries()) {
43
- result[model] = Array.from(records.values());
44
- }
45
- return result;
46
- }
47
- }
48
-
49
- function matchesWhere(record: any, where?: Where[]): boolean {
50
- if (!where || where.length === 0) return true;
51
-
52
- let result: boolean | null = null;
53
-
54
- for (const condition of where) {
55
- const { field, value, operator = 'eq', connector = 'AND' } = condition;
56
- const recordValue = record[field];
57
-
58
- let matches = false;
59
-
60
- switch (operator) {
61
- case 'eq':
62
- matches = recordValue === value;
63
- break;
64
- case 'ne':
65
- matches = recordValue !== value;
66
- break;
67
- case 'lt':
68
- matches = value != null && recordValue < value;
69
- break;
70
- case 'lte':
71
- matches = value != null && recordValue <= value;
72
- break;
73
- case 'gt':
74
- matches = value != null && recordValue > value;
75
- break;
76
- case 'gte':
77
- matches = value != null && recordValue >= value;
78
- break;
79
- case 'in':
80
- matches =
81
- Array.isArray(value) && (value as unknown[]).includes(recordValue);
82
- break;
83
- case 'not_in':
84
- matches =
85
- Array.isArray(value) && !(value as unknown[]).includes(recordValue);
86
- break;
87
- case 'contains':
88
- matches =
89
- typeof recordValue === 'string' &&
90
- typeof value === 'string' &&
91
- recordValue.includes(value);
92
- break;
93
- case 'starts_with':
94
- matches =
95
- typeof recordValue === 'string' &&
96
- typeof value === 'string' &&
97
- recordValue.startsWith(value);
98
- break;
99
- case 'ends_with':
100
- matches =
101
- typeof recordValue === 'string' &&
102
- typeof value === 'string' &&
103
- recordValue.endsWith(value);
104
- break;
105
- default:
106
- matches = recordValue === value;
107
- }
108
-
109
- // Apply connector logic
110
- if (result === null) {
111
- result = matches;
112
- } else if (connector === 'OR') {
113
- result = result || matches;
114
- } else {
115
- // Default: AND
116
- result = result && matches;
117
- }
118
- }
119
-
120
- return result ?? true;
121
- }
122
- type SortBy = {
123
- field: string;
124
- direction: 'asc' | 'desc';
125
- };
126
-
127
- function applySorting(records: any[], sortBy?: SortBy): any[] {
128
- if (!sortBy) return records;
129
-
130
- const { field, direction } = sortBy;
131
-
132
- return records.sort((a, b) => {
133
- const aVal = a[field];
134
- const bVal = b[field];
135
-
136
- if (aVal === bVal) return 0;
137
- if (aVal == null) return direction === 'asc' ? -1 : 1;
138
- if (bVal == null) return direction === 'asc' ? 1 : -1;
139
-
140
- const comparison = aVal < bVal ? -1 : 1;
141
- return direction === 'asc' ? comparison : -comparison;
142
- });
143
- }
144
-
145
- export const memoryAdapter = (
146
- config: MemoryAdapterConfig = {},
147
- store = new Map(),
148
- ) => {
149
- const storeInstance = new MemoryStore(config.initialData, store);
150
-
151
- const adapterInstance = createAdapterFactory({
152
- config: {
153
- adapterId: 'memory-adapter',
154
- adapterName: 'Memory Adapter',
155
- usePlural: config.usePlural ?? false,
156
- debugLogs: config.debugLogs ?? false,
157
- supportsJSON: true,
158
- supportsDates: true,
159
- supportsBooleans: true,
160
- supportsNumericIds: false,
161
- },
162
-
163
- // Note: The framework automatically transforms field names in both directions:
164
- // - Input data is already transformed before reaching the adapter (e.g., email -> email_address)
165
- // - Output data is automatically transformed after the adapter returns (e.g., email_address -> email)
166
- // Therefore, we should NOT call transformInput or transformOutput ourselves.
167
- adapter: ({ debugLog, getModelName, transformWhereClause }) => ({
168
- create: async ({ data, model }) => {
169
- debugLog('CREATE', { model, data });
170
- const modelName = getModelName(model);
171
- const modelData = storeInstance.getModel(modelName);
172
-
173
- // Data is already transformed by the framework - store directly
174
- const record = data as Record<string, unknown>;
175
- if (!record.id) {
176
- record.id = crypto.randomUUID();
177
- }
178
-
179
- const id = record.id as string;
180
- modelData.set(id, { ...record });
181
- return modelData.get(id);
182
- },
183
-
184
- findOne: async ({ where, model }) => {
185
- debugLog('FIND_ONE', { model, where });
186
- const modelName = getModelName(model);
187
- const modelData = storeInstance.getModel(modelName);
188
- const transformedWhere = transformWhereClause({ model, where });
189
-
190
- for (const record of modelData.values()) {
191
- if (matchesWhere(record, transformedWhere)) {
192
- return record;
193
- }
194
- }
195
- return null;
196
- },
197
-
198
- findMany: async ({ where, model, limit, offset, sortBy }) => {
199
- debugLog('FIND_MANY', { model, where });
200
-
201
- const modelName = getModelName(model);
202
- const modelData = storeInstance.getModel(modelName);
203
- const transformedWhere = transformWhereClause({ model, where });
204
-
205
- let results = Array.from(modelData.values()).filter((record) =>
206
- matchesWhere(record, transformedWhere),
207
- );
208
-
209
- if (sortBy) {
210
- results = applySorting(results, sortBy);
211
- }
212
-
213
- if (offset) {
214
- results = results.slice(offset);
215
- }
216
- if (limit) {
217
- results = results.slice(0, limit);
218
- }
219
-
220
- return results;
221
- },
222
-
223
- update: async ({ where, update, model }) => {
224
- debugLog('UPDATE', { model, where });
225
-
226
- const modelName = getModelName(model);
227
- const modelData = storeInstance.getModel(modelName);
228
- const transformedWhere = transformWhereClause({ model, where });
229
-
230
- for (const [id, record] of modelData.entries()) {
231
- if (matchesWhere(record, transformedWhere)) {
232
- // Update data is already transformed by the framework
233
- const updated = { ...record, ...update };
234
- modelData.set(id, updated);
235
- return updated;
236
- }
237
- }
238
- return null;
239
- },
240
-
241
- updateMany: async ({ where, update, model }) => {
242
- debugLog('UPDATE_MANY', { model, where });
243
- const modelName = getModelName(model);
244
- const modelData = storeInstance.getModel(modelName);
245
- const transformedWhere = transformWhereClause({ model, where });
246
-
247
- let count = 0;
248
-
249
- for (const [id, record] of modelData.entries()) {
250
- if (matchesWhere(record, transformedWhere)) {
251
- // Update data is already transformed by the framework
252
- modelData.set(id, { ...record, ...update });
253
- count++;
254
- }
255
- }
256
- return count;
257
- },
258
-
259
- delete: async ({ where, model }) => {
260
- debugLog('DELETE', { model, where });
261
- const modelName = getModelName(model);
262
- const modelData = storeInstance.getModel(modelName);
263
- const transformedWhere = transformWhereClause({ model, where });
264
-
265
- for (const [id, record] of modelData.entries()) {
266
- if (matchesWhere(record, transformedWhere)) {
267
- modelData.delete(id);
268
- return;
269
- }
270
- }
271
- },
272
-
273
- deleteMany: async ({ where, model }) => {
274
- debugLog('DELETE_MANY', { model, where });
275
- const modelName = getModelName(model);
276
- const modelData = storeInstance.getModel(modelName);
277
- const transformedWhere = transformWhereClause({ model, where });
278
-
279
- const toDelete: string[] = [];
280
- for (const [id, record] of modelData.entries()) {
281
- if (matchesWhere(record, transformedWhere)) {
282
- toDelete.push(id);
283
- }
284
- }
285
-
286
- for (const id of toDelete) {
287
- modelData.delete(id);
288
- }
289
- return toDelete.length;
290
- },
291
-
292
- count: async ({ where, model }) => {
293
- const modelName = getModelName(model);
294
- const modelData = storeInstance.getModel(modelName);
295
- const transformedWhere = transformWhereClause({ model, where });
296
-
297
- return Array.from(modelData.values()).filter((record) =>
298
- matchesWhere(record, transformedWhere),
299
- ).length;
300
- },
301
- }),
302
- });
303
-
304
- // Add utility methods to the adapter
305
- return Object.assign(adapterInstance, {
306
- clear: () => store.clear(),
307
- getAllData: () => storeInstance.getAllData(),
308
- getStore: () => store,
309
- });
310
- };