@rdlabo/workers-hono-kit 0.3.7 → 0.4.2

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 (57) hide show
  1. package/README.md +34 -1
  2. package/dist/business-time/index.d.ts +49 -0
  3. package/dist/business-time/index.js +149 -0
  4. package/dist/business-time/types.d.ts +9 -0
  5. package/dist/business-time/types.js +5 -0
  6. package/dist/db/columns.d.ts +46 -0
  7. package/dist/db/columns.js +36 -0
  8. package/dist/db/connection.js +2 -1
  9. package/dist/db/decimal.d.ts +27 -0
  10. package/dist/db/decimal.js +50 -0
  11. package/dist/db/index.d.ts +4 -1
  12. package/dist/db/index.js +3 -1
  13. package/dist/db/jst.d.ts +10 -72
  14. package/dist/db/jst.js +10 -82
  15. package/dist/testing/index.d.ts +2 -0
  16. package/dist/testing/index.js +2 -0
  17. package/dist/testing/workers-bindings.d.ts +49 -0
  18. package/dist/testing/workers-bindings.js +62 -0
  19. package/package.json +7 -3
  20. package/scripts/db-baseline.mjs +0 -0
  21. package/src/ai/gateway.ts +0 -120
  22. package/src/aws/cloudfront.ts +0 -105
  23. package/src/aws/secrets-manager.ts +0 -112
  24. package/src/cache/kv-cache.ts +0 -316
  25. package/src/db/connection.ts +0 -107
  26. package/src/db/database.ts +0 -269
  27. package/src/db/index.ts +0 -39
  28. package/src/db/jst.ts +0 -122
  29. package/src/db/migrate.ts +0 -155
  30. package/src/db/orm-config.ts +0 -171
  31. package/src/db/retry.ts +0 -43
  32. package/src/db/write-result.ts +0 -46
  33. package/src/firebase/firebase-verifier.ts +0 -76
  34. package/src/firebase/identity-toolkit.ts +0 -179
  35. package/src/firebase/jose-firebase-verifier.ts +0 -159
  36. package/src/firebase/remote-verifier.ts +0 -98
  37. package/src/http/app-env.ts +0 -53
  38. package/src/http/app-info.ts +0 -38
  39. package/src/http/execution-context.ts +0 -11
  40. package/src/http/http-status.ts +0 -71
  41. package/src/http/nest-error.ts +0 -207
  42. package/src/http/trailing-slash.ts +0 -28
  43. package/src/http/user-protocol.ts +0 -36
  44. package/src/index.ts +0 -77
  45. package/src/middleware/auth.ts +0 -129
  46. package/src/middleware/finalize-response.ts +0 -90
  47. package/src/middleware/validation.ts +0 -158
  48. package/src/middleware/zod-coerce.ts +0 -124
  49. package/src/queue/consumer.ts +0 -146
  50. package/src/queue/send.ts +0 -129
  51. package/src/stripe/client.ts +0 -85
  52. package/src/testing/auth.ts +0 -110
  53. package/src/testing/configurable-fake.ts +0 -45
  54. package/src/testing/db.ts +0 -194
  55. package/src/testing/fakes.ts +0 -153
  56. package/src/testing/index.ts +0 -31
  57. package/src/testing/stripe-fixtures.ts +0 -175
@@ -1,110 +0,0 @@
1
- import type { Pool } from 'mysql2/promise';
2
- import type { DecodedIdToken } from '../firebase/firebase-verifier.js';
3
- import type { FakeFirebaseVerifier } from './fakes.js';
4
-
5
- /**
6
- * Build authentication headers compatible with the client interceptor convention
7
- * (`x-amz-security-token` + `x-amz-meta-*`).
8
- *
9
- * Consolidates the identically-shaped header boilerplate that route specs tend to duplicate.
10
- *
11
- * @remarks
12
- * `version` is persisted into an `app_version` column (`varchar(10)`), so keep it to 10 characters
13
- * or fewer. Passing `contentType: null` omits the `content-type` header entirely (e.g. for GET requests).
14
- *
15
- * @param token - Security token placed in the `x-amz-security-token` header.
16
- * @param opts - Optional overrides.
17
- * @param opts.version - App version for `x-amz-meta-version` (defaults to `'1.0.0'`).
18
- * @param opts.uuid - Device/client UUID for `x-amz-meta-uuid` (defaults to `'test-uuid'`).
19
- * @param opts.contentType - Content type; defaults to `'application/json'`. Pass `null` to omit the header.
20
- * @returns A plain header record suitable for `fetch`/`app.request` calls.
21
- * @example
22
- * ```ts
23
- * const res = await app.request('/me', { headers: authHeaders(token) });
24
- * // GET without a content-type header:
25
- * await app.request('/items', { headers: authHeaders(token, { contentType: null }) });
26
- * ```
27
- */
28
- export function authHeaders(
29
- token: string,
30
- opts: { version?: string; uuid?: string; contentType?: string | null } = {},
31
- ): Record<string, string> {
32
- const headers: Record<string, string> = {
33
- 'x-amz-security-token': token,
34
- 'x-amz-meta-version': opts.version ?? '1.0.0',
35
- 'x-amz-meta-uuid': opts.uuid ?? 'test-uuid',
36
- };
37
- if (opts.contentType !== null) {
38
- headers['content-type'] = opts.contentType ?? 'application/json';
39
- }
40
- return headers;
41
- }
42
-
43
- /**
44
- * Register a token on a fake Firebase verifier without touching the database.
45
- *
46
- * Use this when {@link provisionUser} does not fit because the project's `users` table has a
47
- * non-conventional shape (for example, keyed by email rather than `firebase_uid`); pair it with a
48
- * project-specific provisioning step.
49
- *
50
- * @param firebase - In-memory verifier to register the token on.
51
- * @param uid - Firebase UID associated with the token.
52
- * @param record - Additional decoded-token fields to merge in (e.g. `email`).
53
- * @param token - Token string to register (defaults to `` `tok-${uid}` ``).
54
- * @returns The registered token string.
55
- * @example
56
- * ```ts
57
- * const token = registerFirebaseToken(firebase, 'uid-1', { email: 'a@example.com' });
58
- * const res = await app.request('/me', { headers: authHeaders(token) });
59
- * ```
60
- */
61
- export function registerFirebaseToken(
62
- firebase: FakeFirebaseVerifier,
63
- uid: string,
64
- record: Partial<DecodedIdToken> = {},
65
- token = `tok-${uid}`,
66
- ): string {
67
- firebase.register(token, { uid, ...record });
68
- return token;
69
- }
70
-
71
- /**
72
- * Register a token on a fake Firebase verifier and ensure a matching `users` row exists, returning
73
- * its id.
74
- *
75
- * @remarks
76
- * Assumes a conventional `users(id, firebase_uid, agree)` table. The operation is idempotent: if a
77
- * row with the same `firebase_uid` already exists it is reused rather than re-inserted. For projects
78
- * whose `users` table has a different shape, use {@link registerFirebaseToken} plus project-specific
79
- * provisioning instead.
80
- *
81
- * @param pool - mysql2 pool connected to the test database.
82
- * @param firebase - In-memory verifier to register the token on.
83
- * @param opts - Provisioning options.
84
- * @param opts.uid - Firebase UID for the user.
85
- * @param opts.token - Token string to register (defaults to `` `tok-${uid}` ``).
86
- * @param opts.agree - Value for the `agree` column on insert (defaults to `1`).
87
- * @param opts.email - Optional email merged into the decoded token record.
88
- * @returns The resolved `userId`, along with the `uid` and registered `token`.
89
- * @example
90
- * ```ts
91
- * const { userId, token } = await provisionUser(pool, firebase, { uid: 'uid-1' });
92
- * const res = await app.request('/me', { headers: authHeaders(token) });
93
- * ```
94
- */
95
- export async function provisionUser(
96
- pool: Pool,
97
- firebase: FakeFirebaseVerifier,
98
- opts: { uid: string; token?: string; agree?: number; email?: string },
99
- ): Promise<{ userId: number; uid: string; token: string }> {
100
- const token = registerFirebaseToken(firebase, opts.uid, opts.email ? { email: opts.email } : {}, opts.token);
101
-
102
- const [existing] = await pool.query('SELECT id FROM users WHERE firebase_uid = ?', [opts.uid]);
103
- const rows = existing as { id: number }[];
104
- if (rows.length > 0) {
105
- return { userId: rows[0].id, uid: opts.uid, token };
106
- }
107
-
108
- const [res] = await pool.query('INSERT INTO users (agree, firebase_uid) VALUES (?, ?)', [opts.agree ?? 1, opts.uid]);
109
- return { userId: (res as { insertId: number }).insertId, uid: opts.uid, token };
110
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * Build a test double from a partial implementation: configured members are returned as-is, while
3
- * calling any unconfigured member fails explicitly with `` `${name}.${method} not configured` ``.
4
- *
5
- * @remarks
6
- * Replaces the hand-written "accept a `Partial<impl>` and throw on anything unset" fake classes that
7
- * tend to proliferate per gateway. Because gateway interfaces differ by domain (Stripe, etc.), this
8
- * lets you stub only the members a given test exercises in a single line.
9
- *
10
- * @typeParam T - The interface being faked.
11
- * @param impl - Partial implementation; only the members the test needs.
12
- * @param name - Label used in the "not configured" error message (defaults to `'fake'`).
13
- * @returns A proxy typed as `T` that delegates to `impl` and throws on unconfigured members.
14
- * @throws Error `` `${name}.${method} not configured` `` when an unconfigured string-keyed member is called.
15
- * @example
16
- * ```ts
17
- * const stripe = configurableFake<StripeGateway>(
18
- * { listPaymentIntents: async () => fakeApiList([fakePaymentIntent()]) },
19
- * 'FakeStripeGateway',
20
- * );
21
- * await stripe.listPaymentIntents(); // ok
22
- * await stripe.cancelPaymentIntent('pi_1'); // throws: FakeStripeGateway.cancelPaymentIntent not configured
23
- * ```
24
- */
25
- export function configurableFake<T extends object>(impl: Partial<T>, name = 'fake'): T {
26
- return new Proxy(impl, {
27
- get(target, prop) {
28
- if (prop in target) {
29
- return (target as Record<string | symbol, unknown>)[prop];
30
- }
31
- // Never return the "unconfigured member" function for Promise-interop properties. Doing so would
32
- // make the fake itself look thenable, so accidentally awaiting it (or passing it to
33
- // Promise.resolve) would invoke then() and throw — a subtle footgun.
34
- if (prop === 'then' || prop === 'catch' || prop === 'finally') {
35
- return undefined;
36
- }
37
- if (typeof prop === 'string') {
38
- return () => {
39
- throw new Error(`${name}.${prop} not configured`);
40
- };
41
- }
42
- return undefined;
43
- },
44
- }) as T;
45
- }
package/src/testing/db.ts DELETED
@@ -1,194 +0,0 @@
1
- import { drizzle } from 'drizzle-orm/mysql2';
2
- import { migrate } from 'drizzle-orm/mysql2/migrator';
3
- import { createConnection, createPool } from 'mysql2/promise';
4
- import type { Pool } from 'mysql2/promise';
5
-
6
- /**
7
- * Connection parameters for the test MySQL server.
8
- *
9
- * @see {@link CreateTestDbOptions.connection} for how defaults are resolved.
10
- */
11
- export interface TestDbConnection {
12
- /** Server host. */
13
- host: string;
14
- /** Server port. */
15
- port: number;
16
- /** User name. */
17
- user: string;
18
- /** Password. */
19
- password: string;
20
- }
21
-
22
- /**
23
- * Options for {@link createTestDb}.
24
- */
25
- export interface CreateTestDbOptions {
26
- /**
27
- * Test database name (e.g. `'app_test'`). To isolate parallel runs per feature, resolve a per-run
28
- * name on the caller side and pass it here.
29
- */
30
- dbName: string;
31
- /**
32
- * Absolute path to the Drizzle migrations folder. Resolve it on the caller side, e.g.
33
- * `join(here, '..', 'drizzle')`.
34
- */
35
- migrationsFolder: string;
36
- /**
37
- * Connection overrides. Unspecified fields fall back to environment variables
38
- * (`DB_HOST`/`DB_PORT`/`DB_USER`/`DB_PASSWORD`), then to `127.0.0.1`/`3306`/`root`/`root`.
39
- */
40
- connection?: Partial<TestDbConnection>;
41
- }
42
-
43
- /**
44
- * Test database handle returned by {@link createTestDb}, bundling schema setup, pooling, and
45
- * fixture helpers for a single test database.
46
- */
47
- export interface TestDb {
48
- /** The resolved test database name. */
49
- readonly dbName: string;
50
- /** The resolved connection parameters. */
51
- readonly connection: TestDbConnection;
52
- /**
53
- * Drop and recreate the database, then apply the committed Drizzle migrations to build the schema.
54
- *
55
- * @returns A promise that resolves once migrations have been applied.
56
- */
57
- resetSchema(): Promise<void>;
58
- /**
59
- * Create a mysql2 pool connected to the test database.
60
- *
61
- * @remarks Call `pool.end()` (e.g. in `afterAll`) to release connections.
62
- * @returns A connection pool for the test database.
63
- */
64
- createTestPool(): Pool;
65
- /**
66
- * Truncate every base table in the database.
67
- *
68
- * @remarks Table names are discovered dynamically from `information_schema`; the
69
- * `__drizzle_migrations` bookkeeping table is excluded. Foreign-key checks are disabled for the
70
- * duration so truncation order does not matter.
71
- * @param pool - Pool connected to the test database.
72
- */
73
- truncateAll(pool: Pool): Promise<void>;
74
- /**
75
- * Insert a single row, mapping column names to values — a generic fixture helper for specs.
76
- *
77
- * @param pool - Pool connected to the test database.
78
- * @param table - Target table name.
79
- * @param row - Column-name to value map. A no-op if empty.
80
- */
81
- seed(pool: Pool, table: string, row: Record<string, unknown>): Promise<void>;
82
- /**
83
- * Report whether the local MySQL server is reachable.
84
- *
85
- * @remarks Useful as a guard, e.g. `describe.skipIf(!(await mysqlReachable()))`.
86
- * @returns `true` if a connection could be opened, otherwise `false`.
87
- */
88
- mysqlReachable(): Promise<boolean>;
89
- }
90
-
91
- function resolveConnection(override?: Partial<TestDbConnection>): TestDbConnection {
92
- const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env ?? {};
93
- return {
94
- host: override?.host ?? env.DB_HOST ?? '127.0.0.1',
95
- port: override?.port ?? Number(env.DB_PORT ?? '3306'),
96
- user: override?.user ?? env.DB_USER ?? 'root',
97
- password: override?.password ?? env.DB_PASSWORD ?? 'root',
98
- };
99
- }
100
-
101
- /**
102
- * Create a {@link TestDb} handle for a single test database.
103
- *
104
- * @remarks
105
- * The test schema is built from the committed Drizzle migrations as the single source of truth
106
- * (the `db:generate` output under `./drizzle`), rather than a hand-written `schema.sql`. This helper
107
- * is Node-only test infrastructure (run under Vitest) and is unrelated to runtime behavior.
108
- *
109
- * @param options - Database name, migrations folder, and optional connection overrides. See
110
- * {@link CreateTestDbOptions}.
111
- * @returns A handle exposing schema setup, pooling, truncation, seeding, and a reachability probe.
112
- * @example
113
- * ```ts
114
- * const testDb = createTestDb({ dbName: 'app_test', migrationsFolder: join(here, '..', 'drizzle') });
115
- * beforeAll(async () => {
116
- * await testDb.resetSchema();
117
- * });
118
- * const pool = testDb.createTestPool();
119
- * beforeEach(() => testDb.truncateAll(pool));
120
- * afterAll(() => pool.end());
121
- * ```
122
- */
123
- export function createTestDb(options: CreateTestDbOptions): TestDb {
124
- const { dbName, migrationsFolder } = options;
125
- const connection = resolveConnection(options.connection);
126
-
127
- return {
128
- dbName,
129
- connection,
130
-
131
- async resetSchema(): Promise<void> {
132
- const admin = await createConnection({ ...connection, multipleStatements: true });
133
- await admin.query(
134
- `DROP DATABASE IF EXISTS \`${dbName}\`; CREATE DATABASE \`${dbName}\` DEFAULT CHARACTER SET utf8mb4;`,
135
- );
136
- await admin.changeUser({ database: dbName });
137
- await migrate(drizzle(admin), { migrationsFolder });
138
- await admin.end();
139
- },
140
-
141
- createTestPool(): Pool {
142
- // decimalNumbers / timezone mirror the runtime hyperdriveConnectionOptions so specs read
143
- // DECIMAL columns as numbers and handle datetime in +09:00 (JST), matching production.
144
- const pool = createPool({
145
- ...connection,
146
- database: dbName,
147
- connectionLimit: 5,
148
- decimalNumbers: true,
149
- timezone: '+09:00',
150
- });
151
- // Pin ONLY_FULL_GROUP_BY on every pooled connection so GROUP BY violations surface in specs
152
- // regardless of the server's my.cnf (the policy is centralized here, not left to each server). CONCAT keeps
153
- // the server's other sql_mode flags and is harmless if ONLY_FULL_GROUP_BY is already present.
154
- // mysql2 queues this SET ahead of the consumer's first query on each new physical connection.
155
- pool.on('connection', (conn) => {
156
- void conn.query("SET SESSION sql_mode = CONCAT(@@SESSION.sql_mode, ',ONLY_FULL_GROUP_BY')");
157
- });
158
- return pool;
159
- },
160
-
161
- async truncateAll(pool: Pool): Promise<void> {
162
- const [rows] = await pool.query(
163
- "SELECT table_name AS t FROM information_schema.tables WHERE table_schema = ? AND table_type='BASE TABLE' AND table_name <> '__drizzle_migrations'",
164
- [dbName],
165
- );
166
- const tables = (rows as { t: string }[]).map((r) => r.t);
167
- await pool.query('SET FOREIGN_KEY_CHECKS=0');
168
- for (const t of tables) {
169
- await pool.query(`TRUNCATE TABLE \`${t}\``);
170
- }
171
- await pool.query('SET FOREIGN_KEY_CHECKS=1');
172
- },
173
-
174
- async seed(pool: Pool, table: string, row: Record<string, unknown>): Promise<void> {
175
- const cols = Object.keys(row);
176
- if (cols.length === 0) {
177
- return;
178
- }
179
- const placeholders = cols.map(() => '?').join(', ');
180
- const columnList = cols.map((c) => `\`${c}\``).join(', ');
181
- await pool.query(`INSERT INTO \`${table}\` (${columnList}) VALUES (${placeholders})`, Object.values(row));
182
- },
183
-
184
- async mysqlReachable(): Promise<boolean> {
185
- try {
186
- const c = await createConnection({ ...connection });
187
- await c.end();
188
- return true;
189
- } catch {
190
- return false;
191
- }
192
- },
193
- };
194
- }
@@ -1,153 +0,0 @@
1
- import type { Pool } from 'mysql2/promise';
2
- import { databaseFrom } from '../db/database.js';
3
- import type { DisposableDatabase } from '../db/database.js';
4
- import type { DecodedIdToken, FirebaseVerifier } from '../firebase/firebase-verifier.js';
5
-
6
- /**
7
- * In-memory {@link FirebaseVerifier} implementation for offline route tests.
8
- *
9
- * Seed fake identities with {@link FakeFirebaseVerifier.register | register(token, { uid })}, then
10
- * verification resolves the registered decoded token instead of calling a real Firebase backend.
11
- *
12
- * @example
13
- * ```ts
14
- * const firebase = new FakeFirebaseVerifier();
15
- * firebase.register('tok-1', { uid: 'uid-1' });
16
- * const decoded = await firebase.verifyIdToken('tok-1'); // { uid: 'uid-1' }
17
- * ```
18
- */
19
- export class FakeFirebaseVerifier implements FirebaseVerifier {
20
- private readonly tokens = new Map<string, DecodedIdToken>();
21
- /** UIDs passed to {@link FakeFirebaseVerifier.deleteUser}, in call order, for assertions. */
22
- readonly deleted: string[] = [];
23
-
24
- /**
25
- * Register a fake decoded token so that {@link FakeFirebaseVerifier.verifyIdToken} resolves it.
26
- *
27
- * @param token - Token string clients will present.
28
- * @param record - Decoded token returned on verification (must include `uid`).
29
- */
30
- register(token: string, record: DecodedIdToken): void {
31
- this.tokens.set(token, record);
32
- }
33
-
34
- /**
35
- * Resolve the decoded token previously registered for `idToken`.
36
- *
37
- * @param idToken - Token string to verify.
38
- * @returns The registered decoded token.
39
- * @throws Error if the token was never registered.
40
- */
41
- async verifyIdToken(idToken: string): Promise<DecodedIdToken> {
42
- const record = this.tokens.get(idToken);
43
- if (!record) {
44
- throw new Error('invalid firebase id token');
45
- }
46
- return record;
47
- }
48
-
49
- /**
50
- * Return a minimal user record echoing the requested UID.
51
- *
52
- * @param uid - UID to look up.
53
- * @returns An object containing the `uid` (never `null` in this fake).
54
- */
55
- async getUser(uid: string): Promise<{ uid: string; email?: string } | null> {
56
- return { uid };
57
- }
58
-
59
- /**
60
- * Return minimal user records echoing each requested UID.
61
- *
62
- * @param uids - UIDs to look up.
63
- * @returns One `{ uid }` entry per requested uid (never omits any, in this fake).
64
- */
65
- async getUsers(uids: string[]): Promise<{ uid: string; email?: string }[]> {
66
- return uids.map((uid) => ({ uid }));
67
- }
68
-
69
- /**
70
- * Record a user deletion by appending the UID to {@link FakeFirebaseVerifier.deleted}.
71
- *
72
- * @param uid - UID being deleted.
73
- */
74
- async deleteUser(uid: string): Promise<void> {
75
- this.deleted.push(uid);
76
- }
77
- }
78
-
79
- /**
80
- * Options for {@link createPoolDatabase}.
81
- *
82
- * @typeParam TDrizzle - The Drizzle instance type, supplied by the consumer so that type identity is
83
- * not coupled to this package's copy of `drizzle-orm`.
84
- */
85
- export interface CreatePoolDatabaseOptions<TDrizzle> {
86
- /** Test pool used as both primary and replica. */
87
- pool: Pool;
88
- /** Drizzle instance built by the consumer with its own `drizzle-orm`, e.g. `drizzle(pool, { schema, ... })`. */
89
- orm: TDrizzle;
90
- }
91
-
92
- /**
93
- * Create a `Database` backed by a single pool used as both primary and replica, suitable for tests.
94
- *
95
- * @remarks
96
- * `dispose()` ends the pool. The `orm` is provided by the caller (rather than constructed here) so
97
- * the returned database uses the consumer's own `drizzle-orm` types, avoiding type-identity clashes
98
- * across duplicated `drizzle-orm` installs.
99
- *
100
- * @typeParam TDrizzle - The Drizzle instance type provided by the consumer.
101
- * @param options - Pool and Drizzle instance. See {@link CreatePoolDatabaseOptions}.
102
- * @returns A {@link DisposableDatabase} whose `dispose()` closes the pool.
103
- * @example
104
- * ```ts
105
- * const pool = testDb.createTestPool();
106
- * const db = createPoolDatabase({ pool, orm: drizzle(pool, { schema }) });
107
- * // ... run tests ...
108
- * await db.dispose();
109
- * ```
110
- */
111
- export function createPoolDatabase<TDrizzle>(
112
- options: CreatePoolDatabaseOptions<TDrizzle>,
113
- ): DisposableDatabase<TDrizzle> {
114
- const { pool, orm } = options;
115
- const base = databaseFrom(orm, pool);
116
- return {
117
- ...base,
118
- async dispose(): Promise<void> {
119
- await pool.end();
120
- },
121
- };
122
- }
123
-
124
- /**
125
- * Create a no-op `Database` stub for routes that never touch the database (e.g. plain GET handlers).
126
- *
127
- * @remarks
128
- * `read` resolves to an empty array, while `write` and `transaction` throw so that any unexpected
129
- * database access is caught as a misuse. `dispose` is a no-op, so this can stand in for a
130
- * {@link DisposableDatabase} backing (e.g. a Hyperdrive- or pool-based one) without changes.
131
- *
132
- * @typeParam TDrizzle - The Drizzle instance type the consumer expects (defaults to `unknown`).
133
- * @returns A {@link DisposableDatabase} that reads empty and throws on writes/transactions.
134
- * @throws Error from `write`/`transaction` if they are accessed.
135
- * @example
136
- * ```ts
137
- * const db = createNoopDatabase();
138
- * await db.read('SELECT 1'); // []
139
- * await db.write(async (dz) => dz); // throws: noopDatabase.write accessed unexpectedly
140
- * ```
141
- */
142
- export function createNoopDatabase<TDrizzle = unknown>(): DisposableDatabase<TDrizzle> {
143
- return {
144
- read: async () => [],
145
- write: () => {
146
- throw new Error('noopDatabase.write accessed unexpectedly');
147
- },
148
- transaction: () => {
149
- throw new Error('noopDatabase.transaction accessed unexpectedly');
150
- },
151
- dispose: async () => {},
152
- };
153
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Shared test infrastructure for Hono on Cloudflare Workers projects (depends on `mysql2`/`drizzle-orm`).
3
- *
4
- * Test-only helpers that are never loaded at runtime. This subpath consolidates the duplicated
5
- * test boilerplate (test DB setup, in-memory fakes, auth header builders, Stripe fixtures) that
6
- * tends to be copy-pasted across projects into a single, importable surface.
7
- */
8
-
9
- export { createTestDb } from './db.js';
10
- export type { TestDb, CreateTestDbOptions, TestDbConnection } from './db.js';
11
-
12
- export { FakeFirebaseVerifier, createPoolDatabase, createNoopDatabase } from './fakes.js';
13
- export type { CreatePoolDatabaseOptions } from './fakes.js';
14
- export type { Database, DisposableDatabase, QueryRunner, TxOf } from '../db/database.js';
15
-
16
- // Authentication test helpers (route-spec header builders and user provisioning).
17
- export { authHeaders, registerFirebaseToken, provisionUser } from './auth.js';
18
-
19
- // Test double helper (partial-implementation fake that throws explicitly on unconfigured members).
20
- export { configurableFake } from './configurable-fake.js';
21
-
22
- // Test fixture factories for Stripe objects.
23
- export {
24
- fakeApiList,
25
- fakePaymentIntent,
26
- fakeStripeEvent,
27
- fakeCheckoutSession,
28
- fakeCustomer,
29
- fakePrice,
30
- fakeSubscription,
31
- } from './stripe-fixtures.js';